using System.Text; using System.Text.Json.Nodes; using Fleet.Core; using Monitor.Probe; namespace Monitor.Backend.Tests; /// 进程内的真实 Probe:用后端生成的身份文件(和面板下载的 probe.json 同一份)启动 。 public sealed class ProbeHarness : IAsyncDisposable { private readonly CancellationTokenSource _stop = new(); private readonly string _directory; private readonly Task _run; private ProbeHarness(string directory, ProbeApp app) { _directory = directory; App = app; _run = Task.Run(() => app.RunAsync(_stop.Token), CancellationToken.None); } public ProbeApp App { get; } public string Directory => _directory; public string ProbeId { get; init; } = ""; /// 向后端申请身份(POST /api/admin/probe/identity),写成 probe.json 并启动。 public static async Task StartAsync(BackendFixture backend, Action? configure = null) { JsonNode created = await backend.CreateProbeAsync(); string json = created.ToJsonString(); string directory = Path.Combine(Path.GetTempPath(), "monitor-probe-" + Guid.NewGuid().ToString("N")); System.IO.Directory.CreateDirectory(directory); string path = Path.Combine(directory, "probe.json"); await File.WriteAllTextAsync(path, json, Encoding.UTF8); ProbeFile file = Fleet.Hosting.NodeConfig.Load(path, ProbeConfigContext.Default.ProbeFile); configure?.Invoke(file); var app = new ProbeApp(file, directory, TimeProvider.System, new Fleet.Hosting.ConsoleNodeLog(TimeProvider.System, Console.Out)); return new ProbeHarness(directory, app) { ProbeId = created["probe_id"]!.GetValue() }; } public async ValueTask DisposeAsync() { await _stop.CancelAsync(); try { await _run.WaitAsync(TimeSpan.FromSeconds(15)); } catch (Exception ex) when (ex is OperationCanceledException or TimeoutException) { // 停止中 } App.Dispose(); _stop.Dispose(); try { System.IO.Directory.Delete(_directory, recursive: true); } catch (IOException) { // 临时目录清理失败不影响测试结果 } } }