test: replace campaign labels with behavior names
This commit is contained in:
parent
e6fab96f12
commit
9c6b143a03
30 changed files with 135 additions and 97 deletions
|
|
@ -0,0 +1,510 @@
|
|||
namespace AcDream.App.Tests.Diagnostics;
|
||||
|
||||
public sealed class ConnectedWorldSoakRouteContractTests
|
||||
{
|
||||
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 routePath = Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"connected-r6-soak.route.txt");
|
||||
string[] checkpoints = File.ReadAllLines(routePath)
|
||||
.Select(static line => line.Trim())
|
||||
.Where(static line => line.StartsWith(
|
||||
"checkpoint ",
|
||||
StringComparison.Ordinal))
|
||||
.Select(static line => line["checkpoint ".Length..])
|
||||
.ToArray();
|
||||
|
||||
Assert.Equal(ExpectedCheckpointNames, checkpoints);
|
||||
|
||||
string[] teleports = File.ReadAllLines(routePath)
|
||||
.Select(static line => line.Trim())
|
||||
.Where(static line => line.StartsWith(
|
||||
"command /teleloc ",
|
||||
StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
Assert.Equal(9, teleports.Length);
|
||||
Assert.All(teleports, static line => Assert.EndsWith(
|
||||
" 1 0 0 0",
|
||||
line,
|
||||
StringComparison.Ordinal));
|
||||
|
||||
string[] screenshots = File.ReadAllLines(routePath)
|
||||
.Select(static line => line.Trim())
|
||||
.Where(static line => line.StartsWith(
|
||||
"screenshot ",
|
||||
StringComparison.Ordinal))
|
||||
.Select(static line => line.Split(' ', StringSplitOptions.RemoveEmptyEntries)[1])
|
||||
.ToArray();
|
||||
Assert.Equal(ExpectedCheckpointNames, screenshots);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DenseTownRoutePinsArwicViewAndScreenshot()
|
||||
{
|
||||
string[] route = File.ReadAllLines(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"connected-dense-town.route.txt"))
|
||||
.Select(static line => line.Trim())
|
||||
.Where(static line => line.Length > 0 && !line.StartsWith('#'))
|
||||
.ToArray();
|
||||
|
||||
AssertAppearsInOrder(
|
||||
string.Join('\n', route),
|
||||
"command /telepoi Arwic",
|
||||
"wait materialized 1 60000",
|
||||
"input down MovementTurnRight",
|
||||
"sleep 6000",
|
||||
"input up MovementTurnRight",
|
||||
"screenshot arwic-dense 10000",
|
||||
"checkpoint arwic-dense");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PerformanceRoutesPinNoonBeforeTheirFirstTeleport()
|
||||
{
|
||||
foreach (string routeName in new[]
|
||||
{
|
||||
"connected-r6-soak.route.txt",
|
||||
"connected-dense-town.route.txt",
|
||||
})
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
routeName));
|
||||
int firstTeleport = source.IndexOf("command /tele", StringComparison.Ordinal);
|
||||
Assert.True(firstTeleport > 0, $"{routeName} has no teleport command.");
|
||||
string preTeleport = source[..firstTeleport];
|
||||
Assert.Equal(
|
||||
3,
|
||||
CountOccurrences(
|
||||
preTeleport,
|
||||
"input press AcdreamCycleTimeOfDay"));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReferenceConfigurationDefinesLocalAuthorityAndScreenshotRule()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"docs",
|
||||
"research",
|
||||
"2026-07-24-performance-reference-configuration.json"));
|
||||
using System.Text.Json.JsonDocument document =
|
||||
System.Text.Json.JsonDocument.Parse(source);
|
||||
System.Text.Json.JsonElement root = document.RootElement;
|
||||
|
||||
Assert.Equal(
|
||||
"performance-gate",
|
||||
root.GetProperty("displayPaths")
|
||||
.GetProperty("authoritativeLocal")
|
||||
.GetProperty("authority")
|
||||
.GetString());
|
||||
Assert.Equal(
|
||||
"diagnostic-only",
|
||||
root.GetProperty("displayPaths")
|
||||
.GetProperty("diagnosticRdp")
|
||||
.GetProperty("authority")
|
||||
.GetString());
|
||||
Assert.Equal(
|
||||
2,
|
||||
root.GetProperty("screenshotComparison")
|
||||
.GetProperty("channelTolerance")
|
||||
.GetInt32());
|
||||
Assert.Equal(
|
||||
0.001,
|
||||
root.GetProperty("screenshotComparison")
|
||||
.GetProperty("maxDifferentPixelFraction")
|
||||
.GetDouble());
|
||||
}
|
||||
|
||||
[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);
|
||||
Assert.Contains(
|
||||
"canonical cache '$field' grew",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"if ($workloadChanged) { $warnings.Add($message) }",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
|
||||
string[] zeroFields =
|
||||
[
|
||||
"pendingLiveTeardowns",
|
||||
"pendingLandblockRetirements",
|
||||
"stagedMeshUploads",
|
||||
"stagedMeshBytes",
|
||||
"compositeWarmupPending",
|
||||
];
|
||||
foreach (string field in zeroFields)
|
||||
Assert.Contains($"'{field}'", source, StringComparison.Ordinal);
|
||||
|
||||
string[] revealFields =
|
||||
[
|
||||
"materialized",
|
||||
"completed",
|
||||
"worldViewportObserved",
|
||||
"cancelled",
|
||||
"invariantFailureCount",
|
||||
"isReady",
|
||||
];
|
||||
foreach (string field in revealFields)
|
||||
Assert.Contains($"'{field}'", source, StringComparison.Ordinal);
|
||||
|
||||
string[] streamingZeroFields =
|
||||
[
|
||||
"deferredCompletions",
|
||||
"deferredAdoptedCpuBytes",
|
||||
"pendingPublications",
|
||||
"pendingRetirements",
|
||||
"workerCompletionBacklog",
|
||||
"destinationBacklog",
|
||||
"controlBacklog",
|
||||
"unloadBacklog",
|
||||
"nearBacklog",
|
||||
"farBacklog",
|
||||
];
|
||||
foreach (string field in streamingZeroFields)
|
||||
Assert.Contains($"'{field}'", source, StringComparison.Ordinal);
|
||||
|
||||
string[] streamingEvidenceFields =
|
||||
[
|
||||
"lifetimeFrameOverrunCount",
|
||||
"lifetimeOversizedProgressCount",
|
||||
"maximumFrameMilliseconds",
|
||||
"maximumFrameStage",
|
||||
"maximumOperationMilliseconds",
|
||||
"maximumOperationStage",
|
||||
];
|
||||
foreach (string field in streamingEvidenceFields)
|
||||
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"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UncappedRenderDefaultsToCappedAndIsGatedByAParameter()
|
||||
{
|
||||
// 2026-07-24 measurement-tooling review: the soak unconditionally
|
||||
// forced ACDREAM_UNCAPPED_RENDER=1 with no capped mode, while the
|
||||
// sibling lifecycle gate script exposes both. Pin the fix so it
|
||||
// cannot silently regress back to an unconditional '1'.
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
|
||||
Assert.Contains("[switch]$Uncapped", source, StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"$env:ACDREAM_UNCAPPED_RENDER = if ($Uncapped) { '1' } else { $null }",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"$env:ACDREAM_UNCAPPED_RENDER = '1'",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StationaryDwellSamplesAfterTheLivenessDeadline()
|
||||
{
|
||||
// LiveEntityLivenessController.DestructionTimeoutSeconds is 25s; the
|
||||
// stationary sample must dwell past it or a prior destination's
|
||||
// records can masquerade as retained memory in the return gate.
|
||||
// The script previously slept only 12s despite the comment already
|
||||
// citing the 25s deadline.
|
||||
string script = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
string route = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"connected-r6-soak.route.txt"));
|
||||
|
||||
AssertAppearsInOrder(
|
||||
script,
|
||||
"LiveEntityLivenessController's 25-second authoritative absence",
|
||||
"$checkpointPattern =",
|
||||
"Wait-ForLogPattern $process $stdoutLog $checkpointPattern",
|
||||
"$stationaryProfiles = Get-FrameProfiles $stdoutLog",
|
||||
"Capture-Sample $process $destination.Name 'stationary'");
|
||||
Assert.Equal(9, CountOccurrences(route, "sleep 27000"));
|
||||
Assert.Equal(9, CountOccurrences(route, "sleep 3000"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LaunchConfigurationIsDisclosedToTheArtifactDirectoryBeforeLaunch()
|
||||
{
|
||||
// 2026-07-24 measurement-tooling review: a prior audit could only
|
||||
// observe ACDREAM_DUMP_MOVE_TRUTH because no other ACDREAM_* launch
|
||||
// flag the script sets was ever recorded anywhere machine-readable.
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"Get-ChildItem Env: | Where-Object { $_.Name -like 'ACDREAM_*' }",
|
||||
"Join-Path $artifactDir 'env-disclosure.json'",
|
||||
"try {");
|
||||
Assert.Contains(
|
||||
"EnvDisclosure = Join-Path $artifactDir 'env-disclosure.json'",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"$sensitive = $_.Name -match '(?i)(PASS|PASSWORD|TOKEN|SECRET|KEY)'",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"Value = if ($sensitive) { '<redacted>' } else { $_.Value }",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
// ACDREAM_DUMP_MOVE_TRUTH stays SET (the exercise gate greps its
|
||||
// output) — it is now disclosed, not removed.
|
||||
Assert.Contains("$env:ACDREAM_DUMP_MOVE_TRUTH = '1'", source, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BaselineIdentityComesFromTheMeasuredBinaryRatherThanOnlyTheCheckout()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"$sourceCommit = (& git -C $Repository rev-parse HEAD).Trim()",
|
||||
"[Diagnostics.FileVersionInfo]::GetVersionInfo($exe).ProductVersion",
|
||||
"$binaryCommitMatch = [regex]::Match(",
|
||||
"$commit = if ($null -ne $binaryCommit) { $binaryCommit } else { $sourceCommit }",
|
||||
"$binaryMatchesSource = $null -ne $binaryCommit -and $binaryCommit -eq $sourceCommit");
|
||||
Assert.Contains(
|
||||
"status --short --untracked-files=no",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("BinaryProductVersion = $binaryProductVersion", source);
|
||||
Assert.Contains("BinaryCommit = $binaryCommit", source);
|
||||
Assert.Contains("BinaryMatchesSource = $binaryMatchesSource", source);
|
||||
Assert.Contains("TrackedSourceStatus = @($sourceStatus)", source);
|
||||
Assert.Contains(
|
||||
"measured binary commit $binaryCommit differs from checked-out source commit $sourceCommit",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SoakExportsAndSummarizesFrameHistory()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
|
||||
Assert.Contains(
|
||||
"$env:ACDREAM_FRAME_HISTORY = $frameHistory",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"& dotnet $cliDll summarize-frame-history",
|
||||
"$frameHistory",
|
||||
"$checkpointTimeline",
|
||||
"$markerLog",
|
||||
"$frameSummary");
|
||||
Assert.Contains("FrameHistory = $frameHistory", source, StringComparison.Ordinal);
|
||||
Assert.Contains("FrameSummary = $frameSummary", source, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ContentionCaptureIsExplicitAndIncludesStackEvents()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
|
||||
Assert.Contains("[switch]$CaptureContention", source, StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"'Microsoft-Windows-DotNETRuntime:0x4000:5'",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"ContentionTrace = if ($CaptureContention) { $contentionTrace } else { $null }",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RuntimeCountersCaptureProcessWideAllocationByDefault()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
|
||||
Assert.Contains("[switch]$SkipRuntimeCounters", source, StringComparison.Ordinal);
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"if (-not $SkipRuntimeCounters) {",
|
||||
"'--counters', 'System.Runtime'",
|
||||
"'--refresh-interval', '1'",
|
||||
"'--format', 'csv'",
|
||||
"'--output', $runtimeCounters");
|
||||
Assert.Contains(
|
||||
"RuntimeCounters = if (-not $SkipRuntimeCounters) { $runtimeCounters } else { $null }",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"Wait-ForLogPattern $process $stdoutLog 'live: in world'",
|
||||
"if (-not $SkipRuntimeCounters) {",
|
||||
"Start-Process -FilePath 'dotnet-counters'",
|
||||
"if ($CaptureContention) {",
|
||||
"Start-Process -FilePath 'dotnet-trace'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LoginGateDoesNotRequireTheOptionalFirstPositionRecenterDiagnostic()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
|
||||
Assert.Contains(
|
||||
"Wait-ForLogPattern $process $stdoutLog 'live: in world'",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
"Wait-ForLogPattern $process $stdoutLog 'live: first player position'",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"route materialization below is the deterministic world-ready barrier.",
|
||||
source,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DenseTownModeUsesTheDedicatedOneCheckpointRoute()
|
||||
{
|
||||
string source = File.ReadAllText(Path.Combine(
|
||||
FindRepoRoot(),
|
||||
"tools",
|
||||
"run-connected-r6-soak.ps1"));
|
||||
|
||||
Assert.Contains("[switch]$DenseTown", source, StringComparison.Ordinal);
|
||||
AssertAppearsInOrder(
|
||||
source,
|
||||
"if ($DenseTown) {",
|
||||
"Name = 'Arwic dense'",
|
||||
"$expectedCheckpointNames = @('arwic-dense')",
|
||||
"$routeFileName = 'connected-dense-town.route.txt'",
|
||||
"$runName = 'connected-dense-town'");
|
||||
Assert.Contains("if (-not $DenseTown) {", source, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue