using XFEEDToolBox.Core.Services; using XFEExtension.NetCore.XUnit.Attributes; namespace XFEEDToolBox.Test; [TestFixture] public sealed class ActivityLogTests { [Test]public void RepeatedPollFailuresKeepOneRowFirstLastCountAndBothDiagnostics() { var start=DateTimeOffset.Parse("2026-10-25T10:00:00Z");var now=start;var saved=new List(); var log=new ActivityLog(()=>now,saved.Add); for(var index=0;index<100;index++) { now=start.AddSeconds(index*3); log.Report("system.telemetry","当前星系","等待飞行遥测",ActivitySeverity.Status,"stack "+index,"telemetry-not-ready"); } var row=log.Snapshot().Single();Check.Equal(100,row.Occurrences);Check.Equal(start,row.Time);Check.Equal(now,row.LastSeen); Check.Equal("stack 0",row.FirstDiagnostic);Check.Equal("stack 99",row.LastDiagnostic);Check.That(row.DiagnosticDisplay.Contains("stack 0")&&row.DiagnosticDisplay.Contains("stack 99")); Check.Equal(5,saved.Count);now=start.AddSeconds(300);Check.That(log.Resolve("system.telemetry","当前星系","飞行遥测已恢复")); var resolved=log.Snapshot().Single();Check.Equal(row.Id,resolved.Id);Check.That(resolved.Resolved);Check.Equal(row.LastSeen,resolved.LastSeen);Check.Equal(now,resolved.ClosedAt!.Value); Check.Equal(100,saved.Last().Occurrences);Check.That(!log.Resolve("system.telemetry","当前星系","重复恢复")); } [Test]public void ChangedReasonEscalatesAndOrdinaryEventsDoNotLoseTheirSeparateTimeline() { var now=DateTimeOffset.UtcNow;var log=new ActivityLog(()=>now); log.Append("执行","已到站");log.Append("执行","已到站"); log.Report("read","读取","等待加载",ActivitySeverity.Status,"first","same-type");var first=log.Snapshot()[0]; now=now.AddSeconds(3);log.Report("read","读取","读取持续失败",ActivitySeverity.Warning,"last","same-type"); var last=log.Snapshot()[0];Check.Equal(first.Id,last.Id);Check.Equal(ActivitySeverity.Warning,last.Severity);Check.Equal("等待加载",last.FirstMessage);Check.Equal("读取持续失败",last.Message); log.Report("read","读取","权限不足",ActivitySeverity.Error,"permission","different-type"); var rows=log.Snapshot();Check.Equal(4,rows.Count);Check.That(rows[1].Superseded&&!rows[1].Resolved);Check.Equal("已更新",rows[1].SeverityDisplay); Check.That(rows[2].Id!=rows[3].Id);Check.Equal(1,rows[2].Occurrences); } [Test]public void BoundedRetentionEvictsOldActiveKeysWithoutMergingUnrelatedFailures() { var log=new ActivityLog(); for(var index=0;index<400;index++)log.Report("failure:"+index,"读取","失败",ActivitySeverity.Warning); Check.Equal(300,log.Snapshot(300).Count);Check.Equal(200,log.Snapshot().Count); log.Report("failure:0","读取","失败",ActivitySeverity.Warning); Check.Equal(1,log.Snapshot()[0].Occurrences);Check.Equal(300,log.Snapshot(300).Count); } [Test]public async Task RuntimeDiagnosticApiRetainsStacksWithoutPuttingThemInTheVisibleSummary() { using var temporary=new TemporaryDirectory();await using var runtime=new ToolboxRuntime(temporary.Path); runtime.ReportDiagnostic("system.telemetry","当前星系",new InvalidOperationException("Native player telemetry unavailable or stale"),ActivitySeverity.Status,"等待游戏飞行遥测"); runtime.ReportDiagnostic("system.telemetry","当前星系",new InvalidOperationException("Native player telemetry unavailable or stale"),ActivitySeverity.Status,"等待游戏飞行遥测"); var entry=runtime.Activity.Single();Check.Equal(2,entry.Occurrences);Check.Equal("等待游戏飞行遥测",entry.Message);Check.That(entry.FirstDiagnostic.Contains("InvalidOperationException")); runtime.ResolveDiagnostic("system.telemetry","当前星系","遥测已恢复");Check.That(runtime.Activity.Single().Resolved); Check.That(File.ReadAllText(System.IO.Path.Combine(temporary.Path,"logs","activity.jsonl")).Contains("Occurrences")); } }