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:
parent
2862622ba2
commit
bca4148739
17 changed files with 995 additions and 52 deletions
|
|
@ -0,0 +1,133 @@
|
|||
namespace AcDream.App.Tests.Diagnostics;
|
||||
|
||||
public sealed class ConnectedR6SoakContractTests
|
||||
{
|
||||
private static readonly string[] ExpectedCheckpointNames =
|
||||
[
|
||||
"caul-baseline",
|
||||
"sawato-baseline",
|
||||
"rynthid",
|
||||
"aerlinthe",
|
||||
"sawato-return",
|
||||
"holtburg",
|
||||
"caul-return",
|
||||
"sawato-plateau",
|
||||
"caul-plateau",
|
||||
];
|
||||
|
||||
[Fact]
|
||||
public void RouteContainsExactlyNineOrderedCheckpointBarriers()
|
||||
{
|
||||
string[] checkpoints = File.ReadAllLines(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"connected-r6-soak.route.txt"))
|
||||
.Select(static line => line.Trim())
|
||||
.Where(static line => line.StartsWith(
|
||||
"checkpoint ",
|
||||
StringComparison.Ordinal))
|
||||
.Select(static line => line["checkpoint ".Length..])
|
||||
.ToArray();
|
||||
|
||||
Assert.Equal(ExpectedCheckpointNames, checkpoints);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GateConsumesCanonicalTimelineWithoutWeakeningResidencyFormulas()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"$expectedCheckpointNames = @(",
|
||||
"'caul-baseline'",
|
||||
"'sawato-baseline'",
|
||||
"'rynthid'",
|
||||
"'aerlinthe'",
|
||||
"'sawato-return'",
|
||||
"'holtburg'",
|
||||
"'caul-return'",
|
||||
"'sawato-plateau'",
|
||||
"'caul-plateau'");
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"$canonicalCheckpoints = @(Read-CanonicalCheckpoints)",
|
||||
"Add-CanonicalCheckpointFailures $process",
|
||||
"Add-RelativeGateFailures");
|
||||
Assert.Contains("CanonicalCheckpoints = @($canonicalCheckpoints)", source);
|
||||
Assert.Contains("CheckpointTimeline = $checkpointTimeline", source);
|
||||
Assert.Contains(
|
||||
"Join-Path $artifactDir \"checkpoint-$expectedName.json\"",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"missing render-world synchronization fields",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
|
||||
string[] zeroFields =
|
||||
[
|
||||
"pendingLiveTeardowns",
|
||||
"pendingLandblockRetirements",
|
||||
"stagedMeshUploads",
|
||||
"stagedMeshBytes",
|
||||
"compositeWarmupPending",
|
||||
];
|
||||
foreach (string field in zeroFields)
|
||||
Assert.Contains($"'{field}'", source, StringComparison.Ordinal);
|
||||
|
||||
Assert.Equal(1, CountOccurrences(
|
||||
source,
|
||||
"$privateLimit = [Math]::Max(192.0, $pair.First.PrivateMiB * 0.20)"));
|
||||
Assert.Equal(1, CountOccurrences(
|
||||
source,
|
||||
"$workingLimit = [Math]::Max(192.0, $pair.First.WorkingSetMiB * 0.20)"));
|
||||
Assert.Equal(1, CountOccurrences(
|
||||
source,
|
||||
"$updateLimit = $pair.First.UpdateP95Ms * 1.5 + 0.5"));
|
||||
Assert.Equal(1, CountOccurrences(
|
||||
source,
|
||||
"$allocLimit = $pair.First.AllocP50Kb * 1.5 + 16.0"));
|
||||
}
|
||||
|
||||
private static int CountOccurrences(string source, string value)
|
||||
{
|
||||
int count = 0;
|
||||
int cursor = 0;
|
||||
while ((cursor = source.IndexOf(value, cursor, StringComparison.Ordinal)) >= 0)
|
||||
{
|
||||
count++;
|
||||
cursor += value.Length;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private static void AssertAppearsInOrder(string source, params string[] values)
|
||||
{
|
||||
int cursor = -1;
|
||||
foreach (string value in values)
|
||||
{
|
||||
int next = source.IndexOf(value, cursor + 1, StringComparison.Ordinal);
|
||||
Assert.True(next >= 0, $"Missing expected source fragment: {value}");
|
||||
Assert.True(next > cursor, $"Out-of-order source fragment: {value}");
|
||||
cursor = next;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FindRepoRoot()
|
||||
{
|
||||
DirectoryInfo? directory = new(AppContext.BaseDirectory);
|
||||
while (directory is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(directory.FullName, "AcDream.slnx")))
|
||||
return directory.FullName;
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
throw new DirectoryNotFoundException("Could not find AcDream.slnx.");
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue