fix(runtime): review findings — recursion-safe run cap, atomic detach counter, summary edge cases, per-row event-log fallback
This commit is contained in:
+49
@@ -149,6 +149,55 @@ public class ScriptRunSummaryRecorderTests
|
||||
Assert.Contains($"{expectedTotal} completed", row.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RunSpanningAFlushBoundary_StillReportsItsCompletionInTheNextWindow()
|
||||
{
|
||||
// A long run starts in window N and finishes in window N+1. Its completion is recorded
|
||||
// against a FRESH counters object whose Started is 0 — so a flush filter keyed on
|
||||
// Started/Failed/TimedOut alone would discard it, and the completion (plus its
|
||||
// duration) would appear in NO summary row at all: window N reports a run that started
|
||||
// and never finished, window N+1 reports nothing.
|
||||
var recorder = new ScriptRunSummaryRecorder();
|
||||
recorder.RecordStarted("Inst1", "Slow");
|
||||
|
||||
var firstLog = new FakeSiteEventLogger();
|
||||
Assert.True(await recorder.FlushAsync(firstLog));
|
||||
Assert.Equal("1 runs: 0 completed, 0 failed, 0 timed out across 1 scripts",
|
||||
firstLog.OfType("script").Single().Message);
|
||||
|
||||
// …the run finishes after that flush.
|
||||
recorder.RecordCompleted("Inst1", "Slow", 42);
|
||||
|
||||
var secondLog = new FakeSiteEventLogger();
|
||||
Assert.True(await recorder.FlushAsync(secondLog));
|
||||
|
||||
var row = secondLog.OfType("script").Single();
|
||||
Assert.Equal("0 runs: 1 completed, 0 failed, 0 timed out across 1 scripts", row.Message);
|
||||
|
||||
// The duration is carried too, so the completion is not merely counted.
|
||||
using var doc = JsonDocument.Parse(row.Details!);
|
||||
var script = doc.RootElement.GetProperty("scripts")[0];
|
||||
Assert.Equal("Slow", script.GetProperty("scriptName").GetString());
|
||||
Assert.Equal(0, script.GetProperty("started").GetInt64());
|
||||
Assert.Equal(1, script.GetProperty("completed").GetInt64());
|
||||
Assert.Equal(42, script.GetProperty("maxDurationMs").GetInt64());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CompletionOnlyEntry_DoesNotResurrectTheIdleFlushSuppression()
|
||||
{
|
||||
// The Completed>0 admission must not weaken "an idle interval emits nothing": a window
|
||||
// in which literally nothing was recorded still has zero entries to admit.
|
||||
var recorder = new ScriptRunSummaryRecorder();
|
||||
recorder.RecordStarted("Inst1", "A");
|
||||
recorder.RecordCompleted("Inst1", "A", 1);
|
||||
Assert.True(await recorder.FlushAsync(new FakeSiteEventLogger()));
|
||||
|
||||
var idleLog = new FakeSiteEventLogger();
|
||||
Assert.False(await recorder.FlushAsync(idleLog));
|
||||
Assert.Empty(idleLog.Entries);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DurationTracking_ReportsAverageAndMax()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user