using Fleet.Core; using Fleet.Hosting; using MoShiro.Agent; namespace MoShiro.Backend.Tests; /// 进程内的真实拨号节点:用加入令牌注册出来的身份启动 ,监听关闭(listen.enabled = false),只向 Backend 下发的目标拨出。 public sealed class DialerHarness : IAsyncDisposable { private readonly CancellationTokenSource _stop = new(); private readonly string _directory; private readonly Task _run; private readonly EnrolledDialer _enrolled; private DialerHarness(string directory, AgentApp app, EnrolledDialer enrolled) { _directory = directory; _enrolled = enrolled; App = app; _run = Task.Run(() => app.RunAsync(_stop.Token), CancellationToken.None); } public AgentApp App { get; } public string Directory => _directory; public string DialerId { get; init; } = ""; public static async Task StartAsync(BackendFixture backend, Action? configure = null) { EnrolledDialer enrolled = await backend.CreateDialerAsync(); var config = new AgentConfig { Fleet = { Server = backend.BaseAddress.ToString(), IdentityDir = enrolled.Directory }, Listen = { Enabled = false } }; configure?.Invoke(config); var app = new AgentApp(config, enrolled.Identity, enrolled.Directory, TimeProvider.System, NullNodeLog.Instance); return new DialerHarness(enrolled.Directory, app, enrolled) { DialerId = enrolled.DialerId }; } public async ValueTask DisposeAsync() { await _stop.CancelAsync(); try { await _run.WaitAsync(TimeSpan.FromSeconds(15)); } catch (Exception ex) when (ex is OperationCanceledException or TimeoutException) { // 停止中 } await App.DisposeAsync(); _enrolled.Dispose(); _stop.Dispose(); try { System.IO.Directory.Delete(_directory, recursive: true); } catch (IOException) { // 临时目录清理失败不影响测试结果 } } }