Files
MoShiro/backend/agent/tests/MoShiro.Agent.Tests/TaskLinkTests.cs
T
justme ad5efc62ff 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.
2026-10-21 11:55:36 +08:00

59 lines
2.5 KiB
C#

using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Fleet.Core;
using Fleet.Link;
using MoShiro.Measurement;
using MoShiro.Protocol;
namespace MoShiro.Agent.Tests;
public sealed class TaskLinkTests
{
[Fact]
public async Task QuicConnectionLoss_IsRedialedFromANewPort_WhileTheControlLayerStaysUp()
{
using ECDsa key = ECDsa.Create(ECCurve.NamedCurves.nistP256);
var request = new CertificateRequest("CN=localhost", key, HashAlgorithmName.SHA256);
using X509Certificate2 certificate = request.CreateSelfSigned(DateTimeOffset.UnixEpoch, DateTimeOffset.UnixEpoch.AddYears(100));
var session = new DataSession(1, new byte[32]);
var clock = new MonoClock(TimeProvider.System);
await using var server = new QuicDatagramTransport(new SingleSession(session), null, clock, new DataPlaneCounters(), NullNodeLog.Instance,
IPAddress.Loopback, [0], certificate);
server.Bind();
await using var client = new QuicDatagramTransport(session, clock, new DataPlaneCounters(), NullNodeLog.Instance,
new IPEndPoint(IPAddress.Loopback, server.BoundPorts[0]), key.ExportSubjectPublicKeyInfo());
var status = new LinkStatus("agt_1", "ipv4", TimeProvider.System, NullNodeLog.Instance);
status.SetControl(ControlState.Up);
using var link = new TaskLink(client, status, TimeProvider.System);
using var stop = new CancellationTokenSource(TimeSpan.FromSeconds(30));
Task run = link.RunAsync(stop.Token);
await WaitUntilAsync(() => status.Quic == QuicState.Ready, stop.Token);
int firstPort = client.BoundPorts[0];
await client.CloseClientAsync();
bool controlStayedUp = true;
await WaitUntilAsync(() =>
{
controlStayedUp &= status.Control == ControlState.Up;
return status.Quic == QuicState.Ready && client.BoundPorts[0] != firstPort;
}, stop.Token);
Assert.True(controlStayedUp);
LinkHealth health = status.Snapshot(new Outbox(1 << 10), 0, null);
Assert.Equal(2, health.Task.Quic.HandshakeSuccesses);
Assert.Equal(ControlState.Up, health.Control.State);
await stop.CancelAsync();
await run.WaitAsync(TimeSpan.FromSeconds(5));
}
private static async Task WaitUntilAsync(Func<bool> condition, CancellationToken ct)
{
while (!condition())
{
await Task.Delay(20, ct);
}
}
}