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

@ -1,12 +1,21 @@
using System.Text.Json;
using AcDream.App.Diagnostics;
using AcDream.App.Rendering;
using AcDream.App.Streaming;
using AcDream.App.UI.Testing;
using SixLabors.ImageSharp;
namespace AcDream.App.Tests.Diagnostics;
public sealed class WorldLifecycleAutomationControllerTests
{
private static readonly RenderFrameInput FrameInput = new(1d / 60d, 1280, 720);
private static readonly RenderFrameOutcome FrameOutcome = new(
new WorldRenderFrameOutcome(4, 17, NormalWorldDrawn: true),
new PrivatePresentationFrameOutcome(
PortalViewportDrawn: false,
ScreenshotCaptured: true));
[Fact]
public void ScreenshotCapture_FlipsGlRowsAndWritesACompletePng()
{
@ -112,7 +121,7 @@ public sealed class WorldLifecycleAutomationControllerTests
var controller = new WorldLifecycleAutomationController(
() => reveal,
() => 3,
() => resources,
_ => resources,
screenshots,
directory);
@ -121,13 +130,26 @@ public sealed class WorldLifecycleAutomationControllerTests
Assert.True(controller.IsWorldReady);
Assert.True(controller.IsWorldViewportVisible);
Assert.Equal(3, controller.PortalMaterializationCount);
Assert.True(controller.TryWriteCheckpoint("dungeon", out string error), error);
Assert.True(controller.TryRequestCheckpoint(
"dungeon",
out IRetailUiAutomationCheckpoint? request,
out string error), error);
Assert.NotNull(request);
Assert.Equal(RetailUiAutomationCheckpointStatus.Pending, request.Status);
controller.Process(FrameInput, FrameOutcome);
Assert.Equal(RetailUiAutomationCheckpointStatus.Succeeded, request.Status);
string line = Assert.Single(File.ReadAllLines(
Path.Combine(directory, "world-lifecycle.checkpoints.jsonl")));
using JsonDocument json = JsonDocument.Parse(line);
Assert.Equal("dungeon", json.RootElement.GetProperty("name").GetString());
Assert.Equal(7, json.RootElement.GetProperty("reveal").GetProperty("generation").GetInt64());
Assert.Equal(4, json.RootElement.GetProperty("render").GetProperty("world")
.GetProperty("visibleLandblocks").GetInt32());
Assert.True(json.RootElement.GetProperty("render").GetProperty("presentation")
.GetProperty("screenshotCaptured").GetBoolean());
Assert.Equal(42, json.RootElement.GetProperty("resources").GetProperty("worldEntities").GetInt32());
Assert.True(File.Exists(Path.Combine(directory, "checkpoint-dungeon.json")));
}
@ -137,6 +159,123 @@ public sealed class WorldLifecycleAutomationControllerTests
}
}
[Fact]
public void CheckpointRequests_DrainInFifoOrderOnce()
{
string directory = NewDirectory();
int captures = 0;
var controller = CreateController(
directory,
_ =>
{
captures++;
return EmptyResources();
});
try
{
Assert.True(controller.TryRequestCheckpoint(
"first", out IRetailUiAutomationCheckpoint? first, out _));
Assert.True(controller.TryRequestCheckpoint(
"second", out IRetailUiAutomationCheckpoint? second, out _));
controller.Process(FrameInput, FrameOutcome);
controller.Process(FrameInput, FrameOutcome);
Assert.NotNull(first);
Assert.NotNull(second);
Assert.Equal(1, first.Sequence);
Assert.Equal(2, second.Sequence);
Assert.Equal(RetailUiAutomationCheckpointStatus.Succeeded, first.Status);
Assert.Equal(RetailUiAutomationCheckpointStatus.Succeeded, second.Status);
Assert.Equal(2, captures);
string[] lines = File.ReadAllLines(
Path.Combine(directory, "world-lifecycle.checkpoints.jsonl"));
Assert.Equal(2, lines.Length);
Assert.Contains("\"name\":\"first\"", lines[0], StringComparison.Ordinal);
Assert.Contains("\"name\":\"second\"", lines[1], StringComparison.Ordinal);
}
finally
{
controller.Dispose();
Directory.Delete(directory, recursive: true);
}
}
[Fact]
public void CheckpointWriteFailure_IsReportedOnTokenWithoutThrowingFromFrame()
{
string directory = NewDirectory();
string blockedPath = Path.Combine(directory, "not-a-directory");
File.WriteAllText(blockedPath, "occupied");
var controller = CreateController(blockedPath, _ => EmptyResources());
try
{
Assert.True(controller.TryRequestCheckpoint(
"failed", out IRetailUiAutomationCheckpoint? request, out _));
controller.Process(FrameInput, FrameOutcome);
Assert.NotNull(request);
Assert.Equal(RetailUiAutomationCheckpointStatus.Failed, request.Status);
Assert.Contains("checkpoint 'failed' sequence 1 failed", request.Error);
}
finally
{
controller.Dispose();
Directory.Delete(directory, recursive: true);
}
}
[Fact]
public void CheckpointCancellationAndShutdown_AreExplicitAndNeverWritten()
{
string directory = NewDirectory();
var controller = CreateController(directory, _ => EmptyResources());
try
{
Assert.True(controller.TryRequestCheckpoint(
"caller", out IRetailUiAutomationCheckpoint? caller, out _));
Assert.True(controller.TryRequestCheckpoint(
"shutdown", out IRetailUiAutomationCheckpoint? shutdown, out _));
Assert.NotNull(caller);
Assert.NotNull(shutdown);
controller.CancelCheckpoint(caller);
controller.Dispose();
controller.Process(FrameInput, FrameOutcome);
Assert.Equal(RetailUiAutomationCheckpointStatus.Cancelled, caller.Status);
Assert.Contains("cancelled before render-frame capture", caller.Error);
Assert.Equal(RetailUiAutomationCheckpointStatus.Cancelled, shutdown.Status);
Assert.Contains("cancelled during world lifecycle automation shutdown", shutdown.Error);
Assert.False(controller.TryRequestCheckpoint(
"late", out IRetailUiAutomationCheckpoint? late, out string error));
Assert.Null(late);
Assert.Contains("shutting down", error);
Assert.False(File.Exists(Path.Combine(
directory,
"world-lifecycle.checkpoints.jsonl")));
}
finally
{
controller.Dispose();
Directory.Delete(directory, recursive: true);
}
}
private static WorldLifecycleAutomationController CreateController(
string directory,
Func<RenderFrameOutcome, WorldLifecycleResourceSnapshot> capture) =>
new(
() => default,
() => 0,
capture,
new FrameScreenshotController((_, _) => [], directory),
directory);
private static WorldLifecycleResourceSnapshot EmptyResources() => new(
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0L, 0, 0L, 0L, 0, 0, 0, 0, 0, 0, 0, 0L, 0L, 0d, 0d, null);