using System.Net; using System.Text.Json.Nodes; namespace MoShiro.Backend.Tests; [Trait("Category", "Slow")] public sealed class AgentMeshTests : IClassFixture { private readonly BackendFixture _backend; public AgentMeshTests(BackendFixture backend) => _backend = backend; [Fact] public async Task ListeningAgents_MeasureBothDirections_AndReportThroughTheirBackendLinks() { await using AgentHarness a = await AgentHarness.StartAsync(_backend); await using AgentHarness b = await AgentHarness.StartAsync(_backend); await a.OverrideLineTasksAsync(rateHz: 30); await b.OverrideLineTasksAsync(rateHz: 30); await BackendFixture.EventuallyAsync( () => Task.FromResult(a.App.Dialer.IsConnected(b.Id) && b.App.Dialer.IsConnected(a.Id)), TimeSpan.FromSeconds(30), "both listening agents should establish outgoing measurement sessions"); using HttpResponseMessage retry = await _backend.Admin.PostAsync($"/api/admin/links/{a.Id}/{b.Id}/retry", null); Assert.Equal(HttpStatusCode.Accepted, retry.StatusCode); JsonNode result = JsonNode.Parse(await retry.Content.ReadAsStringAsync())!; Assert.True(result["queued"]!.GetValue()); await BackendFixture.EventuallyAsync(async () => { JsonNode matrix = await _backend.GetJsonAsync(_backend.Admin, "/api/admin/links"); return matrix["items"]!.AsArray().Count(i => ((i!["dialer_id"]!.GetValue() == a.Id && i["listener_id"]!.GetValue() == b.Id) || (i["dialer_id"]!.GetValue() == b.Id && i["listener_id"]!.GetValue() == a.Id)) && i["connected"]!.GetValue()) == 2; }, TimeSpan.FromSeconds(30), "each agent heartbeat should report its outgoing connection"); await BackendFixture.EventuallyAsync(async () => { JsonNode left = await _backend.GetJsonAsync(_backend.Admin, $"/api/admin/raw/chunks?agent_id={a.Id}"); JsonNode right = await _backend.GetJsonAsync(_backend.Admin, $"/api/admin/raw/chunks?agent_id={b.Id}"); return left["items"]!.AsArray().Any(c => c!["kind"]!.GetValue() == "udp_echo" && c["series"]!.GetValue() == "line:" + b.Id) && right["items"]!.AsArray().Any(c => c!["kind"]!.GetValue() == "udp_echo" && c["series"]!.GetValue() == "line:" + a.Id); }, TimeSpan.FromSeconds(40), "both directed lines should persist measured packet data"); } }