아바타 저장소 승격 계약을 완성
This commit is contained in:
parent
ac9b702688
commit
ccdcfcd2f5
36 changed files with 14734 additions and 222 deletions
285
scripts/test_public_runtime_task_definition_cutover.py
Normal file
285
scripts/test_public_runtime_task_definition_cutover.py
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCRIPTS = Path(__file__).resolve().parent
|
||||
CONTRACT = SCRIPTS / "public-runtime-task-definition-cutover.ps1"
|
||||
REPO_ROOT = SCRIPTS.parent
|
||||
|
||||
|
||||
class PublicRuntimeTaskDefinitionCutoverTest(unittest.TestCase):
|
||||
def _run_powershell(self, body: str) -> subprocess.CompletedProcess[str]:
|
||||
powershell = shutil.which("powershell.exe")
|
||||
if powershell is None:
|
||||
self.skipTest("Windows PowerShell 5.1 is not available")
|
||||
with tempfile.TemporaryDirectory(prefix="vignette-task-cutover-") as raw:
|
||||
harness = Path(raw) / "task-cutover.ps1"
|
||||
harness.write_text(body, encoding="utf-8-sig")
|
||||
return subprocess.run(
|
||||
[
|
||||
powershell,
|
||||
"-NoLogo",
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
str(harness),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=30,
|
||||
check=False,
|
||||
)
|
||||
|
||||
def _assert_harness_passes(self, body: str) -> None:
|
||||
completed = self._run_powershell(body)
|
||||
self.assertEqual(
|
||||
0,
|
||||
completed.returncode,
|
||||
msg=f"stdout={completed.stdout}\nstderr={completed.stderr}",
|
||||
)
|
||||
|
||||
def test_contract_digest_ignores_only_enabled_state(self) -> None:
|
||||
contract = str(CONTRACT).replace("'", "''")
|
||||
self._assert_harness_passes(
|
||||
f"""
|
||||
. '{contract}'
|
||||
$enabled = '<Task><Settings><Enabled>true</Enabled></Settings><Actions><Exec><Command>one</Command></Exec></Actions></Task>'
|
||||
$disabled = '<Task><Settings><Enabled>false</Enabled></Settings><Actions><Exec><Command>one</Command></Exec></Actions></Task>'
|
||||
$drifted = '<Task><Settings><Enabled>false</Enabled></Settings><Actions><Exec><Command>two</Command></Exec></Actions></Task>'
|
||||
$enabledDigest = Get-PublicRuntimeTaskXmlContractSha256 -Xml $enabled
|
||||
$disabledDigest = Get-PublicRuntimeTaskXmlContractSha256 -Xml $disabled
|
||||
$driftedDigest = Get-PublicRuntimeTaskXmlContractSha256 -Xml $drifted
|
||||
if ($enabledDigest -cne $disabledDigest) {{ exit 2 }}
|
||||
if ($enabledDigest -ceq $driftedDigest) {{ exit 3 }}
|
||||
exit 0
|
||||
"""
|
||||
)
|
||||
|
||||
def test_exact_action_contract_accepts_disabled_and_operational_snapshots(self) -> None:
|
||||
contract = str(CONTRACT).replace("'", "''")
|
||||
root = str(REPO_ROOT).replace("'", "''")
|
||||
self._assert_harness_passes(
|
||||
f"""
|
||||
. '{contract}'
|
||||
$contracts = @(Get-PublicRuntimeExpectedTaskActionContracts `
|
||||
-StableSourceRoot '{root}' `
|
||||
-ExpectedSourceCommit ('a' * 40) `
|
||||
-ExpectedSourceTree ('b' * 40) `
|
||||
-PythonPath 'C:\\Python311\\python.exe' `
|
||||
-UserUploadDir 'C:\\Runtime\\uploads' `
|
||||
-UserUploadManifestPath 'C:\\RuntimeState\\manifest.json' `
|
||||
-ExpectedUserUploadManifestSha256 ('c' * 64) `
|
||||
-UserUploadWriteFreezePath 'C:\\RuntimeState\\freeze.json' `
|
||||
-CloudflaredPath 'C:\\Tools\\cloudflared.exe' `
|
||||
-CloudflaredConfigPath 'C:\\RuntimeState\\cloudflared.yml' `
|
||||
-PublicHealthUrl 'https://api-vignette.chanpaca.net/health')
|
||||
$entries = @()
|
||||
foreach ($item in $contracts) {{
|
||||
$entries += [pscustomobject]@{{
|
||||
role = $item.role
|
||||
enabled = $false
|
||||
action_execute = $item.execute
|
||||
action_arguments = $item.arguments
|
||||
action_working_directory = $item.working_directory
|
||||
}}
|
||||
}}
|
||||
$snapshot = [pscustomobject]@{{ entries = $entries }}
|
||||
$null = Assert-NewPublicRuntimeTaskDefinitionsPinned `
|
||||
-Snapshot $snapshot `
|
||||
-StableSourceRoot '{root}' `
|
||||
-ExpectedSourceCommit ('a' * 40) `
|
||||
-ExpectedSourceTree ('b' * 40) `
|
||||
-PythonPath 'C:\\Python311\\python.exe' `
|
||||
-UserUploadDir 'C:\\Runtime\\uploads' `
|
||||
-UserUploadManifestPath 'C:\\RuntimeState\\manifest.json' `
|
||||
-ExpectedUserUploadManifestSha256 ('c' * 64) `
|
||||
-UserUploadWriteFreezePath 'C:\\RuntimeState\\freeze.json' `
|
||||
-CloudflaredPath 'C:\\Tools\\cloudflared.exe' `
|
||||
-CloudflaredConfigPath 'C:\\RuntimeState\\cloudflared.yml' `
|
||||
-PublicHealthUrl 'https://api-vignette.chanpaca.net/health'
|
||||
foreach ($entry in $entries) {{ $entry.enabled = $true }}
|
||||
$null = Assert-NewPublicRuntimeTaskDefinitionsPinned `
|
||||
-Snapshot $snapshot `
|
||||
-StableSourceRoot '{root}' `
|
||||
-ExpectedSourceCommit ('a' * 40) `
|
||||
-ExpectedSourceTree ('b' * 40) `
|
||||
-PythonPath 'C:\\Python311\\python.exe' `
|
||||
-UserUploadDir 'C:\\Runtime\\uploads' `
|
||||
-UserUploadManifestPath 'C:\\RuntimeState\\manifest.json' `
|
||||
-ExpectedUserUploadManifestSha256 ('c' * 64) `
|
||||
-UserUploadWriteFreezePath 'C:\\RuntimeState\\freeze.json' `
|
||||
-CloudflaredPath 'C:\\Tools\\cloudflared.exe' `
|
||||
-CloudflaredConfigPath 'C:\\RuntimeState\\cloudflared.yml' `
|
||||
-PublicHealthUrl 'https://api-vignette.chanpaca.net/health' `
|
||||
-AllowEnabled
|
||||
$entries[0].action_arguments += ' -InjectedDrift'
|
||||
try {{
|
||||
$null = Assert-NewPublicRuntimeTaskDefinitionsPinned `
|
||||
-Snapshot $snapshot `
|
||||
-StableSourceRoot '{root}' `
|
||||
-ExpectedSourceCommit ('a' * 40) `
|
||||
-ExpectedSourceTree ('b' * 40) `
|
||||
-PythonPath 'C:\\Python311\\python.exe' `
|
||||
-UserUploadDir 'C:\\Runtime\\uploads' `
|
||||
-UserUploadManifestPath 'C:\\RuntimeState\\manifest.json' `
|
||||
-ExpectedUserUploadManifestSha256 ('c' * 64) `
|
||||
-UserUploadWriteFreezePath 'C:\\RuntimeState\\freeze.json' `
|
||||
-CloudflaredPath 'C:\\Tools\\cloudflared.exe' `
|
||||
-CloudflaredConfigPath 'C:\\RuntimeState\\cloudflared.yml' `
|
||||
-PublicHealthUrl 'https://api-vignette.chanpaca.net/health' `
|
||||
-AllowEnabled
|
||||
exit 2
|
||||
}} catch {{
|
||||
exit 0
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
def test_second_installer_failure_compensates_both_tasks_to_disabled(self) -> None:
|
||||
contract = str(CONTRACT).replace("'", "''")
|
||||
self._assert_harness_passes(
|
||||
f"""
|
||||
. '{contract}'
|
||||
$script:states = @{{ Boot = $false; Watchdog = $false }}
|
||||
$script:bootCalls = 0
|
||||
$script:watchdogCalls = 0
|
||||
$script:suspendCalls = 0
|
||||
$script:assertCalls = 0
|
||||
function Suspend-PublicRuntimeTasks {{
|
||||
param($Snapshot, $TimeoutSec)
|
||||
$script:suspendCalls += 1
|
||||
$script:states.Boot = $false
|
||||
$script:states.Watchdog = $false
|
||||
}}
|
||||
function Assert-PublicRuntimeTasksDisabledAndIdle {{
|
||||
param($Snapshot, $TimeoutSec)
|
||||
$script:assertCalls += 1
|
||||
if ($script:states.Boot -or $script:states.Watchdog) {{
|
||||
throw 'task was not compensated to disabled'
|
||||
}}
|
||||
}}
|
||||
$bootInstaller = {{
|
||||
$script:bootCalls += 1
|
||||
$script:states.Boot = $true
|
||||
}}
|
||||
$watchdogInstaller = {{
|
||||
$script:watchdogCalls += 1
|
||||
throw 'synthetic second installer failure'
|
||||
}}
|
||||
$maintenance = @(
|
||||
[pscustomobject]@{{ role='boot'; task_name='Boot' }},
|
||||
[pscustomobject]@{{ role='watchdog'; task_name='Watchdog' }}
|
||||
)
|
||||
try {{
|
||||
Invoke-PublicRuntimeTaskDefinitionInstallerPairDisabled `
|
||||
-BootInstaller $bootInstaller `
|
||||
-WatchdogInstaller $watchdogInstaller `
|
||||
-MaintenanceSnapshot $maintenance `
|
||||
-TimeoutSec 3
|
||||
exit 2
|
||||
}} catch {{
|
||||
if ($script:bootCalls -ne 1 -or $script:watchdogCalls -ne 1) {{ exit 3 }}
|
||||
if ($script:suspendCalls -ne 1 -or $script:assertCalls -ne 1) {{ exit 4 }}
|
||||
if ($script:states.Boot -or $script:states.Watchdog) {{ exit 5 }}
|
||||
exit 0
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
def test_second_enable_failure_compensates_both_tasks_to_disabled(self) -> None:
|
||||
contract = str(CONTRACT).replace("'", "''")
|
||||
self._assert_harness_passes(
|
||||
f"""
|
||||
. '{contract}'
|
||||
$script:states = @{{ Boot = $false; Watchdog = $false }}
|
||||
$script:taskPaths = @()
|
||||
function Assert-PublicRuntimeTaskDefinitionSnapshotCurrent {{
|
||||
param($ExpectedSnapshot)
|
||||
return $ExpectedSnapshot
|
||||
}}
|
||||
function Enable-ScheduledTask {{
|
||||
param($TaskName, $TaskPath, $ErrorAction)
|
||||
$script:taskPaths += $TaskPath
|
||||
if ($TaskPath -cne '\\') {{ throw 'wrong task path' }}
|
||||
if ($TaskName -eq 'Watchdog') {{ throw 'synthetic second enable failure' }}
|
||||
$script:states[$TaskName] = $true
|
||||
}}
|
||||
function Disable-ScheduledTask {{
|
||||
param($TaskName, $TaskPath, $ErrorAction)
|
||||
$script:taskPaths += $TaskPath
|
||||
if ($TaskPath -cne '\\') {{ throw 'wrong task path' }}
|
||||
$script:states[$TaskName] = $false
|
||||
}}
|
||||
function Get-PublicRuntimeTaskDefinitionSnapshot {{
|
||||
param($BootTaskName, $WatchdogTaskName, [switch]$RequireEnabled)
|
||||
return [pscustomobject]@{{ entries = @(
|
||||
[pscustomobject]@{{ role='boot'; task_name='Boot'; enabled=$script:states.Boot }},
|
||||
[pscustomobject]@{{ role='watchdog'; task_name='Watchdog'; enabled=$script:states.Watchdog }}
|
||||
) }}
|
||||
}}
|
||||
$snapshot = [pscustomobject]@{{ entries = @(
|
||||
[pscustomobject]@{{ role='boot'; task_name='Boot'; contract_sha256=('a' * 64); action_execute='one'; action_arguments='one'; action_working_directory='one' }},
|
||||
[pscustomobject]@{{ role='watchdog'; task_name='Watchdog'; contract_sha256=('b' * 64); action_execute='two'; action_arguments='two'; action_working_directory='two' }}
|
||||
) }}
|
||||
try {{
|
||||
Enable-NewPublicRuntimeTaskDefinitions -DisabledSnapshot $snapshot | Out-Null
|
||||
exit 2
|
||||
}} catch {{
|
||||
if ($script:states.Boot -or $script:states.Watchdog) {{ exit 3 }}
|
||||
if ($script:taskPaths.Count -lt 3) {{ exit 4 }}
|
||||
if (@($script:taskPaths | Where-Object {{ $_ -cne '\\' }}).Count -ne 0) {{ exit 5 }}
|
||||
exit 0
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
def test_operational_definition_drift_disables_both_tasks(self) -> None:
|
||||
contract = str(CONTRACT).replace("'", "''")
|
||||
self._assert_harness_passes(
|
||||
f"""
|
||||
. '{contract}'
|
||||
$script:states = @{{ Boot = $false; Watchdog = $false }}
|
||||
function Assert-PublicRuntimeTaskDefinitionSnapshotCurrent {{ param($ExpectedSnapshot); return $ExpectedSnapshot }}
|
||||
function Enable-ScheduledTask {{
|
||||
param($TaskName, $TaskPath, $ErrorAction)
|
||||
if ($TaskPath -cne '\\') {{ throw 'wrong task path' }}
|
||||
$script:states[$TaskName] = $true
|
||||
}}
|
||||
function Disable-ScheduledTask {{
|
||||
param($TaskName, $TaskPath, $ErrorAction)
|
||||
if ($TaskPath -cne '\\') {{ throw 'wrong task path' }}
|
||||
$script:states[$TaskName] = $false
|
||||
}}
|
||||
function Get-PublicRuntimeTaskDefinitionSnapshot {{
|
||||
param($BootTaskName, $WatchdogTaskName, [switch]$RequireEnabled)
|
||||
return [pscustomobject]@{{ entries = @(
|
||||
[pscustomobject]@{{ role='boot'; task_name='Boot'; enabled=$true; contract_sha256=('a' * 64); action_execute='one'; action_arguments='one'; action_working_directory='one' }},
|
||||
[pscustomobject]@{{ role='watchdog'; task_name='Watchdog'; enabled=$true; contract_sha256=('c' * 64); action_execute='two'; action_arguments='two'; action_working_directory='two' }}
|
||||
); set_sha256=('d' * 64) }}
|
||||
}}
|
||||
$snapshot = [pscustomobject]@{{ entries = @(
|
||||
[pscustomobject]@{{ role='boot'; task_name='Boot'; contract_sha256=('a' * 64); action_execute='one'; action_arguments='one'; action_working_directory='one' }},
|
||||
[pscustomobject]@{{ role='watchdog'; task_name='Watchdog'; contract_sha256=('b' * 64); action_execute='two'; action_arguments='two'; action_working_directory='two' }}
|
||||
) }}
|
||||
try {{
|
||||
Enable-NewPublicRuntimeTaskDefinitions -DisabledSnapshot $snapshot | Out-Null
|
||||
exit 2
|
||||
}} catch {{
|
||||
if ($script:states.Boot -or $script:states.Watchdog) {{ exit 3 }}
|
||||
exit 0
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue