test(app): add canonical connected soak snapshots

Make scripted lifecycle checkpoints acknowledged post-diagnostics render barriers, capture the exact frame outcome beside canonical resource ownership, and harden the nine-stop route with ordered same-location cache and lifetime gates without weakening process residency thresholds.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-22 20:01:06 +02:00
parent 2862622ba2
commit bca4148739
17 changed files with 995 additions and 52 deletions

View file

@ -38,7 +38,10 @@ public sealed class RenderFrameOrchestratorTests
RenderFrameOutcome outcome = orchestrator.Render(Input);
Assert.Equal(
["gpu-begin", "resources", "world", "presentation", "diagnostics", "gpu-end"],
[
"gpu-begin", "resources", "world", "presentation",
"diagnostics", "post-diagnostics", "gpu-end",
],
calls);
Assert.Equal(phases.World, outcome.World);
Assert.Equal(phases.Presentation, outcome.Presentation);
@ -48,6 +51,7 @@ public sealed class RenderFrameOrchestratorTests
("world", Input),
("presentation", Input),
("diagnostics", Input),
("post-diagnostics", Input),
],
phases.ObservedInputs);
Assert.Equal(phases.World, phases.ObservedWorld);
@ -77,6 +81,7 @@ public sealed class RenderFrameOrchestratorTests
[InlineData("world")]
[InlineData("presentation")]
[InlineData("diagnostics")]
[InlineData("post-diagnostics")]
public void RenderFailure_ClosesExactlyOnceAndPropagates(string failurePoint)
{
var calls = new List<string>();
@ -112,7 +117,10 @@ public sealed class RenderFrameOrchestratorTests
Assert.Same(expected, actual);
Assert.Equal(
["gpu-begin", "resources", "world", "presentation", "diagnostics", "gpu-end"],
[
"gpu-begin", "resources", "world", "presentation",
"diagnostics", "post-diagnostics", "gpu-end",
],
calls);
}
@ -121,6 +129,7 @@ public sealed class RenderFrameOrchestratorTests
[InlineData("world")]
[InlineData("presentation")]
[InlineData("diagnostics")]
[InlineData("post-diagnostics")]
public void RenderAndCloseFailure_AreAggregatedInCausalOrder(string failurePoint)
{
var calls = new List<string>();
@ -208,17 +217,19 @@ public sealed class RenderFrameOrchestratorTests
var phases = new RecordingPhases([]);
Assert.Throws<ArgumentNullException>(() => new RenderFrameOrchestrator(
null!, phases, phases, phases, phases, phases));
null!, phases, phases, phases, phases, phases, phases));
Assert.Throws<ArgumentNullException>(() => new RenderFrameOrchestrator(
phases, null!, phases, phases, phases, phases));
phases, null!, phases, phases, phases, phases, phases));
Assert.Throws<ArgumentNullException>(() => new RenderFrameOrchestrator(
phases, phases, null!, phases, phases, phases));
phases, phases, null!, phases, phases, phases, phases));
Assert.Throws<ArgumentNullException>(() => new RenderFrameOrchestrator(
phases, phases, phases, null!, phases, phases));
phases, phases, phases, null!, phases, phases, phases));
Assert.Throws<ArgumentNullException>(() => new RenderFrameOrchestrator(
phases, phases, phases, phases, null!, phases));
phases, phases, phases, phases, null!, phases, phases));
Assert.Throws<ArgumentNullException>(() => new RenderFrameOrchestrator(
phases, phases, phases, phases, phases, null!));
phases, phases, phases, phases, phases, null!, phases));
Assert.Throws<ArgumentNullException>(() => new RenderFrameOrchestrator(
phases, phases, phases, phases, phases, phases, null!));
}
[Fact]
@ -231,6 +242,7 @@ public sealed class RenderFrameOrchestratorTests
typeof(IWorldSceneFramePhase),
typeof(IPrivatePresentationFramePhase),
typeof(IRenderFrameDiagnosticsPhase),
typeof(IRenderFramePostDiagnosticsPhase),
typeof(IRenderFrameFailureRecovery),
];
FieldInfo[] fields = typeof(RenderFrameOrchestrator).GetFields(
@ -308,6 +320,11 @@ public sealed class RenderFrameOrchestratorTests
"gpu-begin", "resources", "world", "presentation", "diagnostics",
"recovery-abort", "gpu-end",
],
"post-diagnostics" =>
[
"gpu-begin", "resources", "world", "presentation", "diagnostics",
"post-diagnostics", "recovery-abort", "gpu-end",
],
_ => throw new ArgumentOutOfRangeException(nameof(failurePoint)),
};
@ -320,13 +337,18 @@ public sealed class RenderFrameOrchestratorTests
"world" => ["resources", "world"],
"presentation" => ["resources", "world", "presentation"],
"diagnostics" => ["resources", "world", "presentation", "diagnostics"],
"post-diagnostics" =>
[
"resources", "world", "presentation", "diagnostics",
"post-diagnostics",
],
_ => throw new ArgumentOutOfRangeException(nameof(failurePoint)),
};
return phases.Select(phase => (phase, Input)).ToArray();
}
private static RenderFrameOrchestrator Create(RecordingPhases phases) =>
new(phases, phases, phases, phases, phases, phases);
new(phases, phases, phases, phases, phases, phases, phases);
private sealed class RecordingPhases :
IRenderFrameLifetime,
@ -334,6 +356,7 @@ public sealed class RenderFrameOrchestratorTests
IWorldSceneFramePhase,
IPrivatePresentationFramePhase,
IRenderFrameDiagnosticsPhase,
IRenderFramePostDiagnosticsPhase,
IRenderFrameFailureRecovery
{
private readonly List<string> _calls;
@ -399,6 +422,13 @@ public sealed class RenderFrameOrchestratorTests
Record("diagnostics");
}
public void Process(RenderFrameInput input, RenderFrameOutcome outcome)
{
ObservedInputs.Add(("post-diagnostics", input));
ObservedOutcome = outcome;
Record("post-diagnostics");
}
private void Record(string call)
{
_calls.Add(call);

View file

@ -37,6 +37,7 @@ public sealed class RenderFrameRecoveryIntegrationTests
new World(failure),
presentation,
new Diagnostics(),
NullRenderFramePostDiagnosticsPhase.Instance,
devTools);
Assert.Throws<InvalidOperationException>(() => orchestrator.Render(Input));