返回 DeepSeek-Reasonix
test-windows-upgrade-startup.test.ps1
根目录 / scripts / test-windows-upgrade-startup.test.ps1
1 $ErrorActionPreference = 'Stop'
2 . (Join-Path $PSScriptRoot 'test-windows-upgrade-startup.ps1')
3 . (Join-Path $PSScriptRoot 'windows-upgrade-ui-evidence.ps1')
4
5 function Assert-True($value, [string]$message) { if (-not $value) { throw $message } }
6 function Assert-Throws([scriptblock]$action, [string]$message) {
7 $caught = $false
8 try { & $action } catch { $caught = $true }
9 Assert-True $caught $message
10 }
11
12 $testRoot = Join-Path ([IO.Path]::GetTempPath()) ('reasonix-upgrade-contract-' + [guid]::NewGuid().ToString('N'))
13 $savedHome = $HOME
14 try {
15 $release = Join-Path $testRoot 'install/releases/test/app/resources'
16 New-Item -ItemType Directory -Path $release -Force | Out-Null
17 $application = Join-Path $testRoot 'install/Reasonix.exe'
18 $builder = Join-Path $testRoot 'fixture.exe'
19 Set-Content -LiteralPath $application -Value 'mock launcher'
20 Set-Content -LiteralPath $builder -Value 'mock builder'
21 $version = 'v1.38.9-5'
22 $commit = '0123456789abcdef0123456789abcdef01234567'
23 @{activeVersion=$version; activeDir='releases/test'} | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $testRoot 'install/current.json')
24 $buildPath = Join-Path $release 'build.json'
25 @{version=$version; commit=$commit} | ConvertTo-Json | Set-Content -LiteralPath $buildPath
26 $script:calls = [Collections.Generic.List[string]]::new()
27 $script:failPhase = ''
28 # Only replace native process boundaries; run the real evidence orchestration.
29 function Invoke-UpgradeFixture([string]$builder, [string[]]$arguments) {
30 $mode = $arguments[1]
31 $fixtureHome = $arguments[3]
32 $report = $arguments[5]
33 Assert-True ($fixtureHome -ne $HOME -and $fixtureHome.Contains('home # %20 中文')) 'Fixture must use a disposable home.'
34 if ($mode -eq 'create') {
35 $script:calls.Add('create')
36 @{visibleText='assistant-only marker'} | ConvertTo-Json | Set-Content -LiteralPath $report
37 } else {
38 $phase = $arguments[7]
39 $script:calls.Add("verify-$phase")
40 if ($script:failPhase -eq $phase) { throw 'Injected verification failure' }
41 }
42 }
43 function Invoke-UpgradeStartup([string]$installRoot, [string]$version, [string]$fixtureHome, [string]$text, [string]$evidence, [bool]$prepareHistorical) {
44 Assert-True ($text -eq 'assistant-only marker') 'Startup must require the assistant marker.'
45 Assert-True ($prepareHistorical -eq ((Split-Path $evidence -Leaf) -eq 'first')) 'Only the first launch explicitly prepares old content; canonical restart restores automatically.'
46 $script:calls.Add('startup-' + (Split-Path $evidence -Leaf))
47 }
48 $evidence = Join-Path $testRoot 'success'
49 Invoke-WindowsUpgradeAcceptance $application $builder $version $evidence
50 $result = Get-Content -LiteralPath (Join-Path $evidence 'result.json') -Raw | ConvertFrom-Json
51 Assert-True ($HOME -eq $savedHome) 'Acceptance changed the PowerShell home.'
52 Assert-True ($result.sourceSha -eq $commit) 'Evidence must read build.json.commit.'
53 Assert-True ($result.applicationSha256 -eq (Get-FileHash -Algorithm SHA256 -LiteralPath $application).Hash) 'Evidence must hash the tested application.'
54 Assert-True (($script:calls -join ',') -eq 'create,startup-first,verify-first,startup-restart,verify-restart') 'Upgrade and restart must both be checked in order.'
55
56 foreach ($invalidCommit in @('', 'unknown', '0123456')) {
57 @{version=$version; commit=$invalidCommit; sourceSha=$commit} | ConvertTo-Json | Set-Content -LiteralPath $buildPath
58 $badEvidence = Join-Path $testRoot ('invalid-' + [guid]::NewGuid().ToString('N'))
59 Assert-Throws { Invoke-WindowsUpgradeAcceptance $application $builder $version $badEvidence } 'Missing/invalid commit must fail closed.'
60 Assert-True (-not (Test-Path -LiteralPath $badEvidence)) 'Invalid package must not get acceptance evidence.'
61 }
62 @{version=$version; commit=$commit} | ConvertTo-Json | Set-Content -LiteralPath $buildPath
63 foreach ($phase in @('first', 'restart')) {
64 $script:failPhase = $phase
65 $badEvidence = Join-Path $testRoot "failure-$phase"
66 Assert-Throws { Invoke-WindowsUpgradeAcceptance $application $builder $version $badEvidence } 'Data verification failure must propagate.'
67 Assert-True (-not (Test-Path -LiteralPath (Join-Path $badEvidence 'result.json'))) 'Failed verification cannot publish a pass.'
68 }
69
70 # Model the native tree enumeration boundary. Selection and visibility checks
71 # below use the same function as packaged Windows acceptance.
72 function Get-UpgradeUIDescendants($element) {
73 foreach ($child in $element.Children) { $child; Get-UpgradeUIDescendants $child }
74 }
75 function New-UIElement([string]$name, [string]$id='', [bool]$offscreen=$false, [object[]]$children=@()) {
76 return [pscustomobject]@{
77 Current=[pscustomobject]@{Name=$name; AutomationId=$id; IsOffscreen=$offscreen; BoundingRectangle=[pscustomobject]@{Width=200; Height=20}}
78 Children=$children
79 }
80 }
81 $marker = 'assistant-only marker'
82 $script:clicked = 0
83 function Invoke-UpgradeUIButton($element) { $script:clicked++ }
84 $pending = New-UIElement 'Import and open' 'reasonix-prepare-restored-session'
85 $pendingRoot = New-UIElement '' '' $false @($pending)
86 $pending.Current.IsOffscreen = $true
87 Assert-True (-not (Invoke-PendingHistoricalSession $pendingRoot)) 'Hidden preparation actions must not be clicked.'
88 $pending.Current.IsOffscreen = $false
89 Assert-True (Invoke-PendingHistoricalSession $pendingRoot) 'Explicit preparation must invoke the actual pending-session action.'
90 Assert-True ($script:clicked -eq 1) 'Invoke only the visible action.'
91 $body = New-UIElement $marker
92 $transcript = New-UIElement '' 'reasonix-chat-transcript-upgrade-tab' $false @($body)
93 $sidebar = New-UIElement $marker 'sidebar-topic'
94 $root = New-UIElement '' '' $false @($sidebar)
95 Assert-True (-not (Test-VisibleUpgradeHistory $root $marker)) 'A matching sidebar title must not pass.'
96 $root.Children = @($sidebar, $transcript)
97 Assert-True (Test-VisibleUpgradeHistory $root $marker) 'Visible transcript assistant body should pass.'
98 $root.Children = @($sidebar, $transcript, $pending)
99 Assert-True (-not (Test-VisibleUpgradeHistory $root $marker)) 'Prepared content must not retain the import action.'
100 $root.Children = @($sidebar, $transcript)
101 $failure = New-UIElement 'Failed to load conversation history. Previous content was kept when available — retry to try again.'
102 $transcript.Children = @($body, $failure)
103 Assert-True (-not (Test-VisibleUpgradeHistory $root $marker)) 'Visible history with an obsolete failure notice must not pass.'
104 $transcript.Children = @($body)
105 $recovery = New-UIElement 'Loading history' 'reasonix-session-recovery-test'
106 $root.Children = @($sidebar, $transcript, $recovery)
107 Assert-True (-not (Test-VisibleUpgradeHistory $root $marker)) 'History behind an unresolved recovery banner must not pass.'
108 $recovery.Current.IsOffscreen = $true
109 Assert-True (Test-VisibleUpgradeHistory $root $marker) 'An offscreen recovery surface does not block the visible session.'
110 $root.Children = @($sidebar, $transcript)
111 $body.Current.IsOffscreen = $true
112 Assert-True (-not (Test-VisibleUpgradeHistory $root $marker)) 'Offscreen history must not pass.'
113 $body.Current.IsOffscreen = $false
114 $transcript.Current.IsOffscreen = $true
115 Assert-True (-not (Test-VisibleUpgradeHistory $root $marker)) 'Hidden transcript must not pass.'
116 $transcript.Current.IsOffscreen = $false
117 $body.Current.BoundingRectangle.Width = 0
118 Assert-True (-not (Test-VisibleUpgradeHistory $root $marker)) 'Zero-size history must not pass.'
119 $body.Current.BoundingRectangle.Width = 200
120 $body.Current.Name = 'unrelated body'
121 Assert-True (-not (Test-VisibleUpgradeHistory $root $marker)) 'Matching text outside the transcript must not pass.'
122 Write-Host 'Windows upgrade orchestration and UI evidence contracts passed (mocked native boundaries).'
123 } finally {
124 Remove-Item -LiteralPath $testRoot -Recurse -Force -ErrorAction SilentlyContinue
125 }
126
126 lines Plain Text