Harden released world witness evidence
This commit is contained in:
parent
b45b08e232
commit
c731430297
2 changed files with 111 additions and 22 deletions
|
|
@ -271,21 +271,23 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
|
||||
var deadline = Time.realtimeSinceStartup + 12f;
|
||||
while (Time.realtimeSinceStartup < deadline &&
|
||||
(runtime.LastReceipt == null || runtime.ActiveVersion <= initialVersion ||
|
||||
(runtime.LastReceipt == null || runtime.LastReceipt.CommandId != request.CommandId ||
|
||||
!string.Equals(runtime.LastReceipt.State, "reconciled", StringComparison.OrdinalIgnoreCase) ||
|
||||
runtime.ActiveVersion <= initialVersion ||
|
||||
Vector3.Distance(FindMarker(root, playerId).transform.position, initialPosition) < 0.01f))
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(0.1f);
|
||||
runtime.Refresh();
|
||||
}
|
||||
|
||||
Assert.That(runtime.LastReceipt, Is.Not.Null);
|
||||
Assert.That(runtime.LastReceipt.CommandId, Is.EqualTo(request.CommandId));
|
||||
Assert.That(
|
||||
runtime.LastReceipt.State,
|
||||
Is.EqualTo("accepted").Or.EqualTo("reconciled"),
|
||||
runtime.LastReceipt.Message);
|
||||
Assert.That(runtime.LastReceipt.SourceVersion, Is.GreaterThan(initialVersion));
|
||||
AssertReconciledProviderReceipt(
|
||||
runtime.LastReceipt,
|
||||
request.CommandId,
|
||||
provider.Selection.ProviderId,
|
||||
provider.Selection.SurfaceId,
|
||||
initialVersion);
|
||||
Assert.That(runtime.ActiveVersion, Is.GreaterThan(initialVersion));
|
||||
Assert.That(runtime.ActiveVersion, Is.GreaterThanOrEqualTo(runtime.LastReceipt.SourceVersion));
|
||||
movementDistance = Vector3.Distance(FindMarker(root, playerId).transform.position, initialPosition);
|
||||
Assert.That(movementDistance, Is.GreaterThan(0.01f));
|
||||
movementReceipt = WitnessReceipt.From("movement", runtime.LastReceipt);
|
||||
|
|
@ -295,15 +297,19 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
var focusDeadline = Time.realtimeSinceStartup + 12f;
|
||||
while (Time.realtimeSinceStartup < focusDeadline &&
|
||||
(runtime.LastReceipt == null || runtime.LastReceipt.CommandId != focus.CommandId ||
|
||||
!string.Equals(runtime.LastReceipt.State, "reconciled", StringComparison.OrdinalIgnoreCase) ||
|
||||
runtime.ActiveVersion < runtime.LastReceipt.SourceVersion))
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(0.1f);
|
||||
runtime.Refresh();
|
||||
}
|
||||
Assert.That(runtime.LastReceipt, Is.Not.Null);
|
||||
Assert.That(runtime.LastReceipt.CommandId, Is.EqualTo(focus.CommandId));
|
||||
Assert.That(runtime.LastReceipt.State, Is.EqualTo("accepted").Or.EqualTo("reconciled"));
|
||||
Assert.That(runtime.LastReceipt.SourceVersion, Is.GreaterThan(movementVersion));
|
||||
AssertReconciledProviderReceipt(
|
||||
runtime.LastReceipt,
|
||||
focus.CommandId,
|
||||
provider.Selection.ProviderId,
|
||||
provider.Selection.SurfaceId,
|
||||
movementVersion);
|
||||
Assert.That(runtime.ActiveVersion, Is.GreaterThanOrEqualTo(runtime.LastReceipt.SourceVersion));
|
||||
focusReceipt = WitnessReceipt.From("targeting", runtime.LastReceipt);
|
||||
|
||||
var focusVersion = runtime.ActiveVersion;
|
||||
|
|
@ -311,18 +317,18 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
var actionDeadline = Time.realtimeSinceStartup + 12f;
|
||||
while (Time.realtimeSinceStartup < actionDeadline &&
|
||||
(runtime.LastReceipt == null || runtime.LastReceipt.CommandId != action.CommandId ||
|
||||
!string.Equals(runtime.LastReceipt.State, "reconciled", StringComparison.OrdinalIgnoreCase) ||
|
||||
runtime.ActiveVersion < runtime.LastReceipt.SourceVersion))
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(0.1f);
|
||||
runtime.Refresh();
|
||||
}
|
||||
Assert.That(runtime.LastReceipt, Is.Not.Null);
|
||||
Assert.That(runtime.LastReceipt.CommandId, Is.EqualTo(action.CommandId));
|
||||
Assert.That(
|
||||
runtime.LastReceipt.State,
|
||||
Is.EqualTo("accepted").Or.EqualTo("reconciled"),
|
||||
runtime.LastReceipt.Message);
|
||||
Assert.That(runtime.LastReceipt.SourceVersion, Is.GreaterThan(focusVersion));
|
||||
AssertReconciledProviderReceipt(
|
||||
runtime.LastReceipt,
|
||||
action.CommandId,
|
||||
provider.Selection.ProviderId,
|
||||
provider.Selection.SurfaceId,
|
||||
focusVersion);
|
||||
Assert.That(runtime.ActiveVersion, Is.GreaterThanOrEqualTo(runtime.LastReceipt.SourceVersion));
|
||||
actionReceipt = WitnessReceipt.From("action", runtime.LastReceipt);
|
||||
|
||||
|
|
@ -366,7 +372,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
|
||||
var mapCamera = mapCameraObject.AddComponent<Camera>();
|
||||
mapCamera.cullingMask = 1 << mapLayer;
|
||||
Assert.That(mapCamera.cullingMask & (1 << mapLayer), Is.Not.Zero);
|
||||
Assert.That(mapCamera.cullingMask, Is.EqualTo(1 << mapLayer));
|
||||
target = new RenderTexture(640, 360, 24, RenderTextureFormat.ARGB32);
|
||||
camera.targetTexture = target;
|
||||
yield return null;
|
||||
|
|
@ -375,6 +381,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
pixels = new Texture2D(640, 360, TextureFormat.RGB24, false);
|
||||
pixels.ReadPixels(new Rect(0, 0, 640, 360), 0, 0);
|
||||
pixels.Apply();
|
||||
var pilotChangedPixels = CountChangedPixels(pixels, camera.backgroundColor);
|
||||
Assert.That(pilotChangedPixels, Is.GreaterThan(25), "The pilot camera rendered no provider-authored world pixels.");
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(capturePath)));
|
||||
File.WriteAllBytes(capturePath, pixels.EncodeToPNG());
|
||||
Assert.That(new FileInfo(capturePath).Length, Is.GreaterThan(1024));
|
||||
|
|
@ -404,6 +412,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
initialVersion,
|
||||
runtime.ActiveVersion,
|
||||
movementDistance,
|
||||
playerRenderers.Length,
|
||||
pilotChangedPixels,
|
||||
mapRenderers.Count,
|
||||
mapChangedPixels,
|
||||
(camera.cullingMask & (1 << mapLayer)) == 0,
|
||||
|
|
@ -433,6 +443,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
long initialVersion,
|
||||
long finalVersion,
|
||||
float movementDistance,
|
||||
int playerRendererCount,
|
||||
int pilotChangedPixels,
|
||||
int mapChannelRendererCount,
|
||||
int mapChangedPixels,
|
||||
bool pilotCameraExcludesMapChannel,
|
||||
|
|
@ -453,6 +465,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
initialVersion = initialVersion,
|
||||
finalVersion = finalVersion,
|
||||
movementDistance = movementDistance,
|
||||
playerRendererCount = playerRendererCount,
|
||||
pilotChangedPixels = pilotChangedPixels,
|
||||
mapChannelRendererCount = mapChannelRendererCount,
|
||||
mapChangedPixels = mapChangedPixels,
|
||||
pilotCameraExcludesMapChannel = pilotCameraExcludesMapChannel,
|
||||
|
|
@ -474,6 +488,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
public long initialVersion;
|
||||
public long finalVersion;
|
||||
public float movementDistance;
|
||||
public int playerRendererCount;
|
||||
public int pilotChangedPixels;
|
||||
public int mapChannelRendererCount;
|
||||
public int mapChangedPixels;
|
||||
public bool pilotCameraExcludesMapChannel;
|
||||
|
|
@ -487,6 +503,12 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
public string commandKind;
|
||||
public string commandId;
|
||||
public string state;
|
||||
public string receiptId;
|
||||
public string ownerRepo;
|
||||
public string authority;
|
||||
public string providerId;
|
||||
public string surfaceId;
|
||||
public bool isProviderOwned;
|
||||
public long sourceVersion;
|
||||
|
||||
public static WitnessReceipt From(string commandKind, EveUnitySceneCommandReceipt receipt)
|
||||
|
|
@ -496,11 +518,36 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
commandKind = commandKind,
|
||||
commandId = receipt.CommandId,
|
||||
state = receipt.State,
|
||||
receiptId = receipt.ReceiptId,
|
||||
ownerRepo = receipt.OwnerRepo,
|
||||
authority = receipt.Authority,
|
||||
providerId = receipt.ProviderId,
|
||||
surfaceId = receipt.SurfaceId,
|
||||
isProviderOwned = receipt.IsProviderOwned,
|
||||
sourceVersion = receipt.SourceVersion
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertReconciledProviderReceipt(
|
||||
EveUnitySceneCommandReceipt receipt,
|
||||
string commandId,
|
||||
string providerId,
|
||||
string surfaceId,
|
||||
long minimumSourceVersion)
|
||||
{
|
||||
Assert.That(receipt, Is.Not.Null);
|
||||
Assert.That(receipt.CommandId, Is.EqualTo(commandId));
|
||||
Assert.That(receipt.State, Is.EqualTo("reconciled"), receipt.Message);
|
||||
Assert.That(receipt.IsProviderOwned, Is.True);
|
||||
Assert.That(receipt.ProviderId, Is.EqualTo(providerId));
|
||||
Assert.That(receipt.SurfaceId, Is.EqualTo(surfaceId));
|
||||
Assert.That(receipt.ReceiptId, Is.Not.Empty);
|
||||
Assert.That(receipt.OwnerRepo, Is.Not.Empty);
|
||||
Assert.That(receipt.Authority, Is.Not.Empty);
|
||||
Assert.That(receipt.SourceVersion, Is.GreaterThan(minimumSourceVersion));
|
||||
}
|
||||
|
||||
private static EveUnityPlayableWorldEntityMarker FindMarker(GameObject root, string entityId)
|
||||
{
|
||||
foreach (var marker in root.GetComponentsInChildren<EveUnityPlayableWorldEntityMarker>())
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ param(
|
|||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$expectedEveUnityCommit = "ed21479e467faea8ff624f2d2f5a7d2fecf913f4"
|
||||
$expectedCultLibCommit = "feb5c71513e71d681699f462fe3682b3168c6f73"
|
||||
$repoRoot = Split-Path -Parent $PSScriptRoot
|
||||
$projectRoot = $ClientProject
|
||||
$outputRoot = if ([IO.Path]::IsPathRooted($OutputDirectory)) { $OutputDirectory } else { Join-Path $repoRoot $OutputDirectory }
|
||||
|
|
@ -34,9 +36,17 @@ foreach ($required in @($UnityExe, (Join-Path $repoRoot $projectRoot), $daemonPr
|
|||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $outputRoot | Out-Null
|
||||
foreach ($priorArtifact in @($resultsPath, $capturePath, $mapCapturePath, $factsPath, $witnessPath)) {
|
||||
if (Test-Path -LiteralPath $priorArtifact) { Remove-Item -LiteralPath $priorArtifact -Force }
|
||||
}
|
||||
if ($CacheState -eq "cold" -and (Test-Path -LiteralPath $assetCachePath)) {
|
||||
Remove-Item -LiteralPath $assetCachePath -Recurse -Force
|
||||
}
|
||||
$initialBodyCount = @(Get-ChildItem -LiteralPath $assetCachePath -Filter *.body -File -Recurse -ErrorAction SilentlyContinue).Count
|
||||
$initialPartialCount = @(Get-ChildItem -LiteralPath $assetCachePath -Filter *.partial -File -Recurse -ErrorAction SilentlyContinue).Count
|
||||
if ($CacheState -eq "cold" -and ($initialBodyCount -ne 0 -or $initialPartialCount -ne 0)) {
|
||||
throw "Cold witness cache was not empty before Unity launch. bodies=$initialBodyCount partials=$initialPartialCount"
|
||||
}
|
||||
$cacheWasWarm = @(Get-ChildItem -LiteralPath $assetCachePath -Filter *.body -File -ErrorAction SilentlyContinue).Count -gt 0
|
||||
if ($CacheState -eq "warm" -and -not $cacheWasWarm) {
|
||||
throw "Warm witness requested without an existing verified bundle cache at $assetCachePath"
|
||||
|
|
@ -155,13 +165,45 @@ try {
|
|||
if (-not (Test-Path $capturePath) -or (Get-Item $capturePath).Length -lt 1024) { throw "Live world capture is missing: $capturePath" }
|
||||
if (-not (Test-Path $mapCapturePath) -or (Get-Item $mapCapturePath).Length -lt 1024) { throw "Live map-channel capture is missing: $mapCapturePath" }
|
||||
if (-not (Test-Path $factsPath)) { throw "Live world witness facts are missing: $factsPath" }
|
||||
foreach ($freshArtifact in @($resultsPath, $capturePath, $mapCapturePath, $factsPath)) {
|
||||
if ((Get-Item -LiteralPath $freshArtifact).LastWriteTimeUtc -lt $witnessStartedAt.UtcDateTime) {
|
||||
throw "Live witness artifact predates this run: $freshArtifact"
|
||||
}
|
||||
}
|
||||
$facts = Get-Content -LiteralPath $factsPath -Raw | ConvertFrom-Json
|
||||
$releaseLock = Get-Content -LiteralPath (Join-Path $repoRoot "ReleaseConsumerProject\Packages\packages-lock.json") -Raw | ConvertFrom-Json
|
||||
$releasedPackageClient = $projectRoot -eq "ReleaseConsumerProject"
|
||||
$sceneLock = $releaseLock.dependencies.'org.gamecult.eve.unity-scene'
|
||||
$cultLibLock = $releaseLock.dependencies.'org.gamecult.cultlib'
|
||||
if (-not $releasedPackageClient) { throw "Released witness must run ReleaseConsumerProject, got '$projectRoot'." }
|
||||
if ($sceneLock.source -ne "git" -or $cultLibLock.source -ne "git" -or
|
||||
$sceneLock.version -like "file:*" -or $cultLibLock.version -like "file:*") {
|
||||
throw "Released witness resolved a non-git/local package dependency."
|
||||
}
|
||||
if ($sceneLock.hash -ne $expectedEveUnityCommit -or $cultLibLock.hash -ne $expectedCultLibCommit) {
|
||||
throw "Released package commits do not match the witnessed releases. scene=$($sceneLock.hash) cultlib=$($cultLibLock.hash)"
|
||||
}
|
||||
$finalBodies = @(Get-ChildItem -LiteralPath $assetCachePath -Filter *.body -File -Recurse -ErrorAction SilentlyContinue)
|
||||
$finalPartials = @(Get-ChildItem -LiteralPath $assetCachePath -Filter *.partial -File -Recurse -ErrorAction SilentlyContinue)
|
||||
if ($finalBodies.Count -ne 1 -or $finalPartials.Count -ne 0) {
|
||||
throw "Content promotion is incomplete. bodies=$($finalBodies.Count) partials=$($finalPartials.Count)"
|
||||
}
|
||||
$bodyHash = (Get-FileHash -LiteralPath $finalBodies[0].FullName -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
if ($finalBodies[0].BaseName -ne $bodyHash) {
|
||||
throw "Promoted content body name does not match its SHA-256. name=$($finalBodies[0].BaseName) hash=$bodyHash"
|
||||
}
|
||||
$facts | Add-Member -NotePropertyName releasedPackageClient -NotePropertyValue $releasedPackageClient
|
||||
$facts | Add-Member -NotePropertyName clientProject -NotePropertyValue $projectRoot
|
||||
$facts | Add-Member -NotePropertyName eveUnityPackageCommit -NotePropertyValue $releaseLock.dependencies.'org.gamecult.eve.unity-scene'.hash
|
||||
$facts | Add-Member -NotePropertyName cultLibPackageCommit -NotePropertyValue $releaseLock.dependencies.'org.gamecult.cultlib'.hash
|
||||
$facts | Add-Member -NotePropertyName eveUnityPackageCommit -NotePropertyValue $sceneLock.hash
|
||||
$facts | Add-Member -NotePropertyName cultLibPackageCommit -NotePropertyValue $cultLibLock.hash
|
||||
$facts | Add-Member -NotePropertyName contentDelivery -NotePropertyValue ([ordered]@{
|
||||
initialBodyCount = $initialBodyCount
|
||||
initialPartialCount = $initialPartialCount
|
||||
finalBodyCount = $finalBodies.Count
|
||||
finalPartialCount = $finalPartials.Count
|
||||
contentHash = $bodyHash
|
||||
sizeBytes = $finalBodies[0].Length
|
||||
})
|
||||
$capture = Get-Item -LiteralPath $capturePath
|
||||
$mapCapture = Get-Item -LiteralPath $mapCapturePath
|
||||
$resultsArtifact = Get-Item -LiteralPath $resultsPath
|
||||
|
|
|
|||
Reference in a new issue