agent: unify listening and dialing with directed mutual measurements
Replace Probe with Agent across node runtime, Fleet contracts, backend state, API and storage. Report incoming sessions and outgoing link health through each Agent uplink, and retain directed link controls and retry. Update protocol fixtures and end-to-end coverage for the unified model; accept requested cancellation during the Fleet timeout test cleanup.
This commit is contained in:
1 parent
d5ebf29e57
commit
ad5efc62ff
206 files changed
+4202
-4964
No files matched your search
@@ -141,14 +141,12 @@ public sealed class HostStatusTests : IClassFixture<BackendFixture>
|
||||
await using SseClient sse = await SseClient.ConnectAsync(_backend.Anonymous, "/api/public/live?topics=hosts");
|
||||
await agent.SendHostAsync(Snapshot(18.5));
|
||||
SseEvent live = await sse.WaitForAsync(e => e.Name == "host" && e.Data!["id"]!.GetValue<string>() == id);
|
||||
Assert.Equal("agent", live.Data!["kind"]!.GetValue<string>());
|
||||
Assert.Equal(18.5, live.Data!["host"]!["cpu_percent"]!.GetValue<double>());
|
||||
Assert.True(live.Data["online"]!.GetValue<bool>());
|
||||
|
||||
// REST:最新值,没有过期
|
||||
JsonNode list = await _backend.GetJsonAsync(_backend.Anonymous, "/api/public/hosts");
|
||||
JsonNode item = list["items"]!.AsArray().Single(i => i!["id"]!.GetValue<string>() == id)!;
|
||||
Assert.Equal("agent", item["kind"]!.GetValue<string>());
|
||||
Assert.False(item["stale"]!.GetValue<bool>());
|
||||
Assert.Equal(40L << 30, item["host"]!["disk_total"]!.GetValue<long>());
|
||||
Assert.Equal(1000, item["host"]!["net_link_mbps"]!.GetValue<long>());
|
||||
@@ -160,10 +158,10 @@ public sealed class HostStatusTests : IClassFixture<BackendFixture>
|
||||
Assert.DoesNotContain(forbidden, text, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// 线路详情也不泄漏 Probe 的地址和版本
|
||||
// 线路详情也不泄漏 Dialer 的地址和版本
|
||||
string line = (await _backend.GetJsonAsync(_backend.Anonymous, $"/api/public/lines/{_backend.Line(id)}")).ToJsonString();
|
||||
Assert.DoesNotContain("remote", line, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.DoesNotContain("probe_version", line, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.DoesNotContain("dialer_version", line, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
// 历史:每分钟一个样本
|
||||
JsonNode history = null!;
|
||||
@@ -185,47 +183,10 @@ public sealed class HostStatusTests : IClassFixture<BackendFixture>
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", "Slow")]
|
||||
public async Task ARealProbeReportsItsHostStatus_LikeAnAgent_NeverCarriesModelsOrAddresses_AndDisappearsWhenRevoked()
|
||||
public async Task ADialerThatTurnsReportingOff_SendsNothing()
|
||||
{
|
||||
await _backend.SiteMustBePublicAsync();
|
||||
await using ProbeHarness probe = await ProbeHarness.StartAsync(_backend, file => file.Reporting.HostIntervalSeconds = 1);
|
||||
|
||||
JsonNode? item = null;
|
||||
await BackendFixture.EventuallyAsync(
|
||||
async () =>
|
||||
{
|
||||
JsonNode list = await _backend.GetJsonAsync(_backend.Anonymous, "/api/public/hosts");
|
||||
item = list["items"]!.AsArray().SingleOrDefault(i => i!["id"]!.GetValue<string>() == probe.ProbeId);
|
||||
return item?["host"] is not null;
|
||||
},
|
||||
TimeSpan.FromSeconds(30),
|
||||
"the probe's host status shows up");
|
||||
Assert.Equal("probe", item!["kind"]!.GetValue<string>());
|
||||
Assert.NotNull(item["host"]!["uptime_seconds"]); // 任何平台都读得到运行时长
|
||||
foreach (string forbidden in new[] { "model", "hostname", "\"ip\"", "address", "remote", "mac", "iface", "public_host" })
|
||||
{
|
||||
Assert.DoesNotContain(forbidden, item.ToJsonString(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
// 历史也按节点 id 取
|
||||
using HttpResponseMessage history = await _backend.Anonymous.GetAsync($"/api/public/hosts/{probe.ProbeId}?range=1h");
|
||||
Assert.Equal(System.Net.HttpStatusCode.OK, history.StatusCode);
|
||||
|
||||
// 吊销之后展示页就看不到它了
|
||||
using HttpResponseMessage revoked = await _backend.Admin.PostAsync($"/api/admin/probes/{probe.ProbeId}/revoke", null);
|
||||
Assert.True(revoked.IsSuccessStatusCode);
|
||||
JsonNode after = await _backend.GetJsonAsync(_backend.Anonymous, "/api/public/hosts");
|
||||
Assert.DoesNotContain(after["items"]!.AsArray(), i => i!["id"]!.GetValue<string>() == probe.ProbeId);
|
||||
using HttpResponseMessage gone = await _backend.Anonymous.GetAsync($"/api/public/hosts/{probe.ProbeId}");
|
||||
Assert.Equal(System.Net.HttpStatusCode.NotFound, gone.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", "Slow")]
|
||||
public async Task AProbeThatTurnsReportingOff_SendsNothing()
|
||||
{
|
||||
await _backend.SiteMustBePublicAsync();
|
||||
await using ProbeHarness probe = await ProbeHarness.StartAsync(_backend, file =>
|
||||
await using DialerHarness dialer = await DialerHarness.StartAsync(_backend, file =>
|
||||
{
|
||||
file.Reporting.HostStats = false;
|
||||
file.Reporting.HostIntervalSeconds = 1;
|
||||
@@ -234,7 +195,7 @@ public sealed class HostStatusTests : IClassFixture<BackendFixture>
|
||||
await Task.Delay(TimeSpan.FromSeconds(4));
|
||||
|
||||
JsonNode list = await _backend.GetJsonAsync(_backend.Anonymous, "/api/public/hosts");
|
||||
JsonNode item = list["items"]!.AsArray().Single(i => i!["id"]!.GetValue<string>() == probe.ProbeId)!;
|
||||
JsonNode item = list["items"]!.AsArray().Single(i => i!["id"]!.GetValue<string>() == dialer.DialerId)!;
|
||||
Assert.Null(item["host"]); // 节点还在,但一个字也没上报
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user