feat: consolidate legacy parity migration baseline
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[ValidateSet('ReadOnly', 'DryRunPlayout', 'FullUiDb')]
|
||||
[string]$Profile = 'ReadOnly',
|
||||
|
||||
[ValidateSet('All', 'PList', 'GraphE', 'Catalog', 'Screens')]
|
||||
[string]$FullUiDbScope = 'All',
|
||||
|
||||
[ValidateRange(1024, 65535)]
|
||||
[int]$Port = 9339,
|
||||
|
||||
@@ -12,7 +18,7 @@ param(
|
||||
[ValidateRange(10, 120)]
|
||||
[int]$LaunchTimeoutSeconds = 30,
|
||||
|
||||
[ValidateRange(30, 300)]
|
||||
[ValidateRange(30, 900)]
|
||||
[int]$HarnessTimeoutSeconds = 180
|
||||
)
|
||||
|
||||
@@ -1544,6 +1550,8 @@ function Invoke-NodeHarnessUnderTcpWatch(
|
||||
[string]$ScreenshotPath,
|
||||
[string]$WindowsInputRequestPath,
|
||||
[string]$WindowsInputAcknowledgementPath,
|
||||
[string]$HarnessProfile,
|
||||
[string]$HarnessScope,
|
||||
[int]$TimeoutSeconds,
|
||||
[Diagnostics.Process]$Application,
|
||||
[string]$ExpectedApplicationPath) {
|
||||
@@ -1559,6 +1567,10 @@ function Invoke-NodeHarnessUnderTcpWatch(
|
||||
$WindowsInputRequestPath,
|
||||
'--windows-input-ack',
|
||||
$WindowsInputAcknowledgementPath,
|
||||
'--profile',
|
||||
$HarnessProfile,
|
||||
'--scope',
|
||||
$HarnessScope,
|
||||
'--timeout-ms',
|
||||
[string]($TimeoutSeconds * 1000)
|
||||
) | ForEach-Object { ConvertTo-QuotedProcessArgument ([string]$_) }
|
||||
@@ -2210,6 +2222,8 @@ function Read-AndAssertHarnessEvidence(
|
||||
[string]$ScreenshotPath,
|
||||
[string]$WindowsInputRequestPath,
|
||||
[string]$WindowsInputAcknowledgementPath,
|
||||
[string]$HarnessProfile,
|
||||
[string]$HarnessScope,
|
||||
[int]$ExpectedPort,
|
||||
[int]$ExpectedTimeoutSeconds) {
|
||||
try {
|
||||
@@ -2218,7 +2232,52 @@ function Read-AndAssertHarnessEvidence(
|
||||
$result = [string]$evidence.result
|
||||
$safeResult = $result -ceq 'PASS' -or $result -ceq 'PASS_WITH_WARNING'
|
||||
$warnings = @($evidence.warnings)
|
||||
$expectedProfile = switch -CaseSensitive ($HarnessProfile) {
|
||||
'FullUiDb' { 'full-ui-db'; break }
|
||||
'DryRunPlayout' { 'dry-run-playout'; break }
|
||||
default { 'read-only' }
|
||||
}
|
||||
$expectedScope = if ($HarnessProfile -ceq 'FullUiDb') {
|
||||
$HarnessScope.ToLowerInvariant()
|
||||
}
|
||||
else {
|
||||
'all'
|
||||
}
|
||||
$databaseWriteContractOk = if ($HarnessProfile -ceq 'FullUiDb') {
|
||||
$evidence.safety.databaseWriteIntentIssued -eq $true -and
|
||||
@($evidence.safety.approvedDatabaseWriteMessages).Count -ge 3 -and
|
||||
[string]$evidence.fullUiDb.result -ceq 'PASS' -and
|
||||
$evidence.fullUiDb.cleanupVerified -eq $true
|
||||
}
|
||||
else {
|
||||
$evidence.safety.databaseWriteIntentIssued -eq $false -and
|
||||
@($evidence.safety.approvedDatabaseWriteMessages).Count -eq 0 -and
|
||||
$null -eq $evidence.fullUiDb
|
||||
}
|
||||
$playoutIntentContractOk = if ($HarnessProfile -ceq 'DryRunPlayout') {
|
||||
$evidence.safety.playoutIntentIssued -eq $true -and
|
||||
[string]$evidence.dryRunPlayout.result -ceq 'PASS' -and
|
||||
-not [string]::IsNullOrWhiteSpace(
|
||||
[string]$evidence.dryRunPlayout.selectedEntryId) -and
|
||||
-not [string]::IsNullOrWhiteSpace(
|
||||
[string]$evidence.dryRunPlayout.nextEntryId) -and
|
||||
-not [string]::IsNullOrWhiteSpace(
|
||||
[string]$evidence.dryRunPlayout.stagedEntryId) -and
|
||||
[string]$evidence.dryRunPlayout.selectedEntryId -cne
|
||||
[string]$evidence.dryRunPlayout.nextEntryId -and
|
||||
[string]$evidence.dryRunPlayout.stagedEntryId -cne
|
||||
[string]$evidence.dryRunPlayout.selectedEntryId -and
|
||||
[int]$evidence.dryRunPlayout.playlistCountBeforeSelection -eq
|
||||
[int]$evidence.dryRunPlayout.playlistCountAfterDoubleClick -and
|
||||
[int]$evidence.dryRunPlayout.programCutSelection -ge 0
|
||||
}
|
||||
else {
|
||||
$evidence.safety.playoutIntentIssued -eq $false -and
|
||||
$null -eq $evidence.dryRunPlayout
|
||||
}
|
||||
if ([int]$evidence.schemaVersion -ne 1 -or
|
||||
[string]$evidence.profile -cne $expectedProfile -or
|
||||
[string]$evidence.scope -cne $expectedScope -or
|
||||
-not $safeResult -or
|
||||
($result -ceq 'PASS_WITH_WARNING' -and $warnings.Count -eq 0) -or
|
||||
$null -ne $evidence.error -or
|
||||
@@ -2231,8 +2290,8 @@ function Read-AndAssertHarnessEvidence(
|
||||
[string]$evidence.safety.requiredMode -cne 'dryRun' -or
|
||||
[string]$evidence.safety.requiredPhase -cne 'idle' -or
|
||||
$evidence.safety.appCloseRequested -ne $false -or
|
||||
$evidence.safety.playoutIntentIssued -ne $false -or
|
||||
$evidence.safety.databaseWriteIntentIssued -ne $false -or
|
||||
-not $playoutIntentContractOk -or
|
||||
-not $databaseWriteContractOk -or
|
||||
$evidence.safety.externalCancellationRequested -ne $false -or
|
||||
@($evidence.safety.blockedOutboundMessages).Count -ne 0 -or
|
||||
@($evidence.safety.stateViolations).Count -ne 0 -or
|
||||
@@ -2241,14 +2300,30 @@ function Read-AndAssertHarnessEvidence(
|
||||
Throw-SafeFailure 'The real input evidence does not satisfy the DryRun safety contract.'
|
||||
}
|
||||
|
||||
$allowedOutbound = @(
|
||||
'ready', 'search-stocks', 'select-stock', 'cut-pointer-down',
|
||||
'cut-key-down', 'drop-selected-cuts', 'activate-playlist-row',
|
||||
'select-playlist-row', 'reorder-playlist-rows',
|
||||
'select-playlist-boundary', 'refresh-named-playlists')
|
||||
foreach ($messageType in @($evidence.safety.observedOutboundMessageTypes)) {
|
||||
if ($allowedOutbound -cnotcontains [string]$messageType) {
|
||||
Throw-SafeFailure 'The evidence contains an outbound message outside the read-only allowlist.'
|
||||
if ($HarnessProfile -ceq 'ReadOnly' -or
|
||||
$HarnessProfile -ceq 'DryRunPlayout') {
|
||||
$allowedOutbound = @(
|
||||
'ready', 'search-stocks', 'select-stock', 'cut-pointer-down',
|
||||
'cut-key-down', 'drop-selected-cuts', 'activate-playlist-row',
|
||||
'select-playlist-row', 'reorder-playlist-rows',
|
||||
'select-playlist-boundary', 'refresh-named-playlists')
|
||||
if ($HarnessProfile -ceq 'DryRunPlayout') {
|
||||
$allowedOutbound += @('take-in', 'next-playout', 'take-out')
|
||||
}
|
||||
foreach ($messageType in @($evidence.safety.observedOutboundMessageTypes)) {
|
||||
if ($allowedOutbound -cnotcontains [string]$messageType) {
|
||||
Throw-SafeFailure 'The evidence contains an outbound message outside the selected non-write allowlist.'
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$playoutMessages = @(
|
||||
'prepare-playout', 'take-in', 'next-playout', 'take-out',
|
||||
'choose-background', 'toggle-background')
|
||||
foreach ($messageType in @($evidence.safety.observedOutboundMessageTypes)) {
|
||||
if ($playoutMessages -ccontains [string]$messageType) {
|
||||
Throw-SafeFailure 'The full UI/DB evidence contains a playout message.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2338,7 +2413,9 @@ function Read-AndAssertHarnessEvidence(
|
||||
$dragVisualCount = @($domPlaylist | Where-Object {
|
||||
$_.dragging -eq $true -or $_.dragBefore -eq $true -or $_.dragAfter -eq $true
|
||||
}).Count
|
||||
if (-not (Test-ExactStringSequence $statePlaylistIds $expectedAfterOrder) -or
|
||||
if (($HarnessProfile -ceq 'ReadOnly' -or
|
||||
$HarnessProfile -ceq 'DryRunPlayout') -and (
|
||||
-not (Test-ExactStringSequence $statePlaylistIds $expectedAfterOrder) -or
|
||||
-not (Test-ExactStringSequence $domPlaylistIds $expectedAfterOrder) -or
|
||||
-not (Test-ExactStringSequence $selectedStateIds @([string]$request.sourceRowId)) -or
|
||||
-not (Test-ExactStringSequence $selectedDomIds @([string]$request.sourceRowId)) -or
|
||||
@@ -2349,9 +2426,18 @@ function Read-AndAssertHarnessEvidence(
|
||||
$activeDomIds `
|
||||
@([string]$request.expectedActiveRowIdAfterHome)) -or
|
||||
$dragVisualCount -ne 0 -or
|
||||
@($dom.playlistPointerCapture.rowIds).Count -ne 0) {
|
||||
@($dom.playlistPointerCapture.rowIds).Count -ne 0)) {
|
||||
Throw-SafeFailure 'The sealed final playlist state does not match the Windows input result.'
|
||||
}
|
||||
$expectedFullUiDbPlaylistCount = if ($HarnessScope -ceq 'GraphE' -or
|
||||
$HarnessScope -ceq 'Screens' -or $HarnessScope -ceq 'All') { 0 } else { 3 }
|
||||
if ($HarnessProfile -ceq 'FullUiDb' -and (
|
||||
$statePlaylist.Count -ne $expectedFullUiDbPlaylistCount -or
|
||||
$domPlaylist.Count -ne $expectedFullUiDbPlaylistCount -or
|
||||
$dragVisualCount -ne 0 -or
|
||||
@($dom.playlistPointerCapture.rowIds).Count -ne 0)) {
|
||||
Throw-SafeFailure 'The sealed full UI/DB playlist readback is not exact.'
|
||||
}
|
||||
|
||||
return $evidence
|
||||
}
|
||||
@@ -2426,6 +2512,16 @@ try {
|
||||
$Screenshot `
|
||||
$WindowsInputRequest `
|
||||
$WindowsInputAcknowledgement `
|
||||
$(if ($Profile -ceq 'FullUiDb') {
|
||||
'full-ui-db'
|
||||
}
|
||||
elseif ($Profile -ceq 'DryRunPlayout') {
|
||||
'dry-run-playout'
|
||||
}
|
||||
else {
|
||||
'read-only'
|
||||
}) `
|
||||
$(if ($Profile -ceq 'FullUiDb') { $FullUiDbScope.ToLowerInvariant() } else { 'all' }) `
|
||||
$HarnessTimeoutSeconds `
|
||||
$script:ApplicationProcess `
|
||||
$registration.Executable
|
||||
@@ -2447,6 +2543,8 @@ try {
|
||||
$Screenshot `
|
||||
$WindowsInputRequest `
|
||||
$WindowsInputAcknowledgement `
|
||||
$Profile `
|
||||
$FullUiDbScope `
|
||||
$Port `
|
||||
$HarnessTimeoutSeconds
|
||||
if ($null -eq $harnessRun.WindowsInput -or
|
||||
@@ -2460,10 +2558,24 @@ try {
|
||||
Assert-ExactApplicationStillRunning $script:ApplicationProcess $registration.Executable
|
||||
Assert-NoTornadoConnection $script:ApplicationProcess.Id
|
||||
|
||||
$script:Phase = 'single-instance activation'
|
||||
$singleInstance = Assert-SingleInstanceActivation `
|
||||
$script:ApplicationProcess `
|
||||
$registration.Executable
|
||||
if ($Profile -cne 'FullUiDb') {
|
||||
$script:Phase = 'single-instance activation'
|
||||
$singleInstance = Assert-SingleInstanceActivation `
|
||||
$script:ApplicationProcess `
|
||||
$registration.Executable
|
||||
}
|
||||
else {
|
||||
# The read-only package smoke already owns the single-instance contract.
|
||||
# Avoid launching an unrelated redirector after an authorized DB-write run.
|
||||
$singleInstance = [pscustomobject]@{
|
||||
ActivationCalls = 0
|
||||
ProcessCount = 1
|
||||
RedirectorProcessId = $null
|
||||
RedirectorStartTimeUtc = $null
|
||||
RedirectorExited = $null
|
||||
StableOriginalMilliseconds = $null
|
||||
}
|
||||
}
|
||||
|
||||
$script:Phase = 'normal close'
|
||||
Invoke-ExactNormalClose $script:ApplicationProcess $registration.Executable
|
||||
|
||||
Reference in New Issue
Block a user