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
|
|
@ -26,6 +26,18 @@ public sealed class RetailUiAutomationProbeTests
|
|||
|
||||
private sealed class FakeRuntime : IRetailUiAutomationRuntime
|
||||
{
|
||||
private sealed class FakeCheckpoint(int sequence, string name) :
|
||||
IRetailUiAutomationCheckpoint
|
||||
{
|
||||
public int Sequence { get; } = sequence;
|
||||
public string Name { get; } = name;
|
||||
public RetailUiAutomationCheckpointStatus Status { get; set; } =
|
||||
RetailUiAutomationCheckpointStatus.Pending;
|
||||
public string? Error { get; set; }
|
||||
}
|
||||
|
||||
private readonly List<FakeCheckpoint> _checkpointTokens = [];
|
||||
|
||||
public bool IsWorldReady { get; set; }
|
||||
public bool IsWorldViewportVisible { get; set; }
|
||||
public int PortalMaterializationCount { get; set; }
|
||||
|
|
@ -33,13 +45,41 @@ public sealed class RetailUiAutomationProbeTests
|
|||
public HashSet<string> ScreenshotRequests { get; } = new();
|
||||
public HashSet<string> CompletedScreenshots { get; } = new();
|
||||
|
||||
public bool TryWriteCheckpoint(string name, out string error)
|
||||
public bool TryRequestCheckpoint(
|
||||
string name,
|
||||
out IRetailUiAutomationCheckpoint? checkpoint,
|
||||
out string error)
|
||||
{
|
||||
Checkpoints.Add(name);
|
||||
var token = new FakeCheckpoint(_checkpointTokens.Count + 1, name);
|
||||
_checkpointTokens.Add(token);
|
||||
checkpoint = token;
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void CancelCheckpoint(IRetailUiAutomationCheckpoint checkpoint)
|
||||
{
|
||||
var token = Assert.IsType<FakeCheckpoint>(checkpoint);
|
||||
token.Status = RetailUiAutomationCheckpointStatus.Cancelled;
|
||||
token.Error = $"checkpoint '{token.Name}' cancelled";
|
||||
}
|
||||
|
||||
public void CompleteCheckpoint(
|
||||
string name,
|
||||
RetailUiAutomationCheckpointStatus status =
|
||||
RetailUiAutomationCheckpointStatus.Succeeded,
|
||||
string? error = null)
|
||||
{
|
||||
FakeCheckpoint token = Assert.Single(
|
||||
_checkpointTokens,
|
||||
value => value.Name == name);
|
||||
if (token.Status != RetailUiAutomationCheckpointStatus.Pending)
|
||||
throw new InvalidOperationException("checkpoint is already terminal");
|
||||
token.Status = status;
|
||||
token.Error = error;
|
||||
}
|
||||
|
||||
public bool TryRequestScreenshot(string name, out string error)
|
||||
{
|
||||
ScreenshotRequests.Add(name);
|
||||
|
|
@ -590,6 +630,16 @@ public sealed class RetailUiAutomationProbeTests
|
|||
runner.Tick(0.001d);
|
||||
|
||||
Assert.Equal(["stable"], runtime.Checkpoints);
|
||||
Assert.DoesNotContain("stable", runtime.ScreenshotRequests);
|
||||
Assert.False(runner.Completed);
|
||||
|
||||
runner.Tick(0.001d);
|
||||
Assert.Equal(["stable"], runtime.Checkpoints);
|
||||
Assert.DoesNotContain("stable", runtime.ScreenshotRequests);
|
||||
|
||||
runtime.CompleteCheckpoint("stable");
|
||||
runner.Tick(0.001d);
|
||||
|
||||
Assert.Contains("stable", runtime.ScreenshotRequests);
|
||||
Assert.False(runner.Completed);
|
||||
|
||||
|
|
@ -604,6 +654,79 @@ public sealed class RetailUiAutomationProbeTests
|
|||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(RetailUiAutomationCheckpointStatus.Failed, "deferred write failed")]
|
||||
[InlineData(RetailUiAutomationCheckpointStatus.Cancelled, "shutdown cancelled")]
|
||||
public void ScriptRunner_checkpointTerminalFailure_StopsWithExactError(
|
||||
RetailUiAutomationCheckpointStatus status,
|
||||
string expectedError)
|
||||
{
|
||||
var (root, _, _, _, objects) = RootWithTwoItemLists();
|
||||
var runtime = new FakeRuntime();
|
||||
var probe = new RetailUiAutomationProbe(root, objects);
|
||||
var logs = new List<string>();
|
||||
string path = Path.Combine(
|
||||
Path.GetTempPath(),
|
||||
Path.GetRandomFileName() + ".ui-probe.txt");
|
||||
File.WriteAllLines(path, ["checkpoint stable", "input press CombatToggleCombat"]);
|
||||
|
||||
try
|
||||
{
|
||||
using var runner = new RetailUiAutomationScriptRunner(
|
||||
probe,
|
||||
path,
|
||||
dumpOnStart: false,
|
||||
log: logs.Add,
|
||||
runtime: runtime);
|
||||
|
||||
runner.Tick(0d);
|
||||
runtime.CompleteCheckpoint("stable", status, expectedError);
|
||||
runner.Tick(0d);
|
||||
|
||||
Assert.True(runner.Completed);
|
||||
Assert.Equal(["stable"], runtime.Checkpoints);
|
||||
Assert.Contains(logs, line => line.Contains(
|
||||
expectedError,
|
||||
StringComparison.Ordinal));
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScriptRunner_disposeCancelsPendingCheckpoint()
|
||||
{
|
||||
var (root, _, _, _, objects) = RootWithTwoItemLists();
|
||||
var runtime = new FakeRuntime();
|
||||
var probe = new RetailUiAutomationProbe(root, objects);
|
||||
string path = Path.Combine(
|
||||
Path.GetTempPath(),
|
||||
Path.GetRandomFileName() + ".ui-probe.txt");
|
||||
File.WriteAllText(path, "checkpoint stable");
|
||||
|
||||
try
|
||||
{
|
||||
var runner = new RetailUiAutomationScriptRunner(
|
||||
probe,
|
||||
path,
|
||||
dumpOnStart: false,
|
||||
runtime: runtime);
|
||||
runner.Tick(0d);
|
||||
|
||||
runner.Dispose();
|
||||
|
||||
Assert.Equal(["stable"], runtime.Checkpoints);
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
runtime.CompleteCheckpoint("stable"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScriptRunner_worldReadyTimeout_stopsWithActionableLine()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue