Evan's Blog
EvanZhu0721 / 公开仓库

SBMS

镜像已同步

SBMS complete the calculation rules for the default logical desktop topology relationship and the physical dimensions of the displays in the Windows multi-screen collaboration system.

上游 GitHub
READ-ONLY MIRROR

README、源码与 Release 已保存到本站;源码视图固定到 commit bd87fa1e。

main/ root / installer/tests
bd87fa1e· 固定源码快照
installer/tests/prepare-upgrade.Tests.ps110.3 KB
1$ErrorActionPreference = 'Stop'
2Set-StrictMode -Version Latest
3
4$maintenanceScript = [IO.Path]::GetFullPath(
5 (Join-Path $PSScriptRoot '..\maintenance.ps1')
6)
7
8Describe 'PrepareUpgrade maintenance contract' {
9 BeforeAll {
10 $loadRoot = Join-Path $TestDrive 'load-root'
11 New-Item -ItemType Directory -Path $loadRoot -Force | Out-Null
12
13 # Load the real function definitions without dispatching an action. This
14 # keeps the contract tests isolated from live SBMS processes, tasks, and
15 # drivers.
16 $maintenanceSource = [IO.File]::ReadAllText(
17 $maintenanceScript,
18 [Text.Encoding]::UTF8
19 )
20 $dispatchMarker = 'switch ($Action) {'
21 $dispatchIndex = $maintenanceSource.LastIndexOf(
22 $dispatchMarker,
23 [StringComparison]::Ordinal
24 )
25 if ($dispatchIndex -lt 0) {
26 throw 'maintenance.ps1 action dispatcher was not found.'
27 }
28 $definitions = $maintenanceSource.Substring(0, $dispatchIndex)
29 . ([scriptblock]::Create($definitions)) `
30 -Action Stop `
31 -InstallRoot $loadRoot
32 }
33
34 BeforeEach {
35 $script:previousLocalAppData = $env:LOCALAPPDATA
36 $script:caseRoot = Join-Path $TestDrive ([guid]::NewGuid().ToString('N'))
37 $script:localAppData = Join-Path $script:caseRoot 'LocalAppData'
38 $script:installRoot = Join-Path $script:caseRoot 'Program Files\SBMS'
39 $script:userStateRoot = Join-Path $script:localAppData 'SBMS'
40 $script:snapshotRoot = Join-Path $script:caseRoot 'ProgramData\SBMS\upgrade-backup\current'
41
42 New-Item -ItemType Directory -Path $script:userStateRoot -Force | Out-Null
43 New-Item -ItemType Directory -Path $script:installRoot -Force | Out-Null
44 $env:LOCALAPPDATA = $script:localAppData
45 $script:configRoot = $script:userStateRoot
46 }
47
48 AfterEach {
49 $env:LOCALAPPDATA = $script:previousLocalAppData
50 }
51
52 It 'exposes PrepareUpgrade as a supported action' {
53 $source = [IO.File]::ReadAllText(
54 $maintenanceScript,
55 [Text.Encoding]::UTF8
56 )
57
58 $source | Should Match "ValidateSet\([^\)]*'PrepareUpgrade'"
59 $source | Should Match "'PrepareUpgrade'\s*\{"
60 }
61
62 It 'stops the old tray before taking the snapshot' {
63 $tokens = $null
64 $parseErrors = $null
65 $ast = [Management.Automation.Language.Parser]::ParseFile(
66 $maintenanceScript,
67 [ref]$tokens,
68 [ref]$parseErrors
69 )
70 @($parseErrors).Count | Should Be 0
71
72 $prepare = $ast.Find(
73 {
74 param($node)
75 $node -is [Management.Automation.Language.FunctionDefinitionAst] -and
76 $node.Name -eq 'Prepare-SbmsUpgrade'
77 },
78 $true
79 )
80 $prepare | Should Not BeNullOrEmpty
81
82 $body = $prepare.Extent.Text
83 $stopIndex = $body.IndexOf('Stop-Sbms', [StringComparison]::Ordinal)
84 $snapshotIndex = $body.IndexOf(
85 'Backup-SbmsConfiguration',
86 [StringComparison]::Ordinal
87 )
88 ($stopIndex -ge 0) | Should Be $true
89 ($snapshotIndex -gt $stopIndex) | Should Be $true
90 }
91
92 It 'does not create a backup directory when no configuration exists' {
93 Backup-SbmsConfiguration
94
95 Test-Path -LiteralPath (
96 Join-Path $script:userStateRoot 'upgrade-backups'
97 ) | Should Be $false
98 }
99
100 It 'copies only persistent SBMS configuration files' {
101 $expected = @{
102 'config-v1.json' = '{"version":1,"target":"legacy"}'
103 'config-v2.json' = '{"version":2,"groups":[{"id":0}]}'
104 'config-profiles-v1.json' = '{"version":1,"active_profile":"default","profiles":[]}'
105 'display-overrides-v1.json' = '{"version":1,"displays":{}}'
106 }
107 foreach ($entry in $expected.GetEnumerator()) {
108 [IO.File]::WriteAllText(
109 (Join-Path $script:userStateRoot $entry.Key),
110 $entry.Value,
111 [Text.UTF8Encoding]::new($false)
112 )
113 }
114 [IO.File]::WriteAllText(
115 (Join-Path $script:userStateRoot 'unrelated.txt'),
116 'must not be copied',
117 [Text.UTF8Encoding]::new($false)
118 )
119
120 Backup-SbmsConfiguration
121 $snapshot = @(
122 Get-ChildItem -LiteralPath (
123 Join-Path $script:userStateRoot 'upgrade-backups'
124 ) -Directory
125 )
126 $snapshot.Count | Should Be 1
127 $snapshot = $snapshot[0]
128
129 foreach ($entry in $expected.GetEnumerator()) {
130 $copy = Join-Path $snapshot.FullName $entry.Key
131 Test-Path -LiteralPath $copy -PathType Leaf | Should Be $true
132 [IO.File]::ReadAllText($copy, [Text.Encoding]::UTF8) |
133 Should Be $entry.Value
134 }
135 Test-Path -LiteralPath (
136 Join-Path $snapshot.FullName 'unrelated.txt'
137 ) | Should Be $false
138 }
139
140 It 'computes SHA256 without depending on PowerShell module discovery' {
141 $inputFile = Join-Path $script:userStateRoot 'hash-input.txt'
142 [IO.File]::WriteAllText(
143 $inputFile,
144 'abc',
145 [Text.UTF8Encoding]::new($false)
146 )
147
148 Get-Sha256Hex -LiteralPath $inputFile | Should Be (
149 'BA7816BF8F01CFEA414140DE5DAE2223' +
150 'B00361A396177A9CB410FF61F20015AD'
151 )
152 }
153
154 It 'verifies and marks each snapshot without creating an unused manifest' {
155 $source = Join-Path $script:userStateRoot 'config-v2.json'
156 [IO.File]::WriteAllText(
157 $source,
158 '{"version":2}',
159 [Text.UTF8Encoding]::new($false)
160 )
161
162 Backup-SbmsConfiguration
163 $snapshot = @(
164 Get-ChildItem -LiteralPath (
165 Join-Path $script:userStateRoot 'upgrade-backups'
166 ) -Directory
167 )[0]
168 $copy = Join-Path $snapshot.FullName 'config-v2.json'
169
170 Get-Sha256Hex -LiteralPath $copy |
171 Should Be (Get-Sha256Hex -LiteralPath $source)
172 [IO.File]::ReadAllText(
173 (Join-Path $snapshot.FullName '.sbms-upgrade-snapshot-v1'),
174 [Text.Encoding]::UTF8
175 ) | Should Be 'SBMS upgrade snapshot v1'
176 Test-OwnedUpgradeSnapshot -Snapshot $snapshot -BackupRoot (
177 Join-Path $script:userStateRoot 'upgrade-backups'
178 ) | Should Be $true
179 Test-Path -LiteralPath (
180 Join-Path $snapshot.FullName 'manifest.json'
181 ) | Should Be $false
182 }
183
184 It 'adds a fresh snapshot on repeat upgrade and preserves retained history' {
185 foreach ($name in @(
186 'config-v1.json',
187 'config-v2.json',
188 'config-profiles-v1.json',
189 'display-overrides-v1.json'
190 )) {
191 [IO.File]::WriteAllText(
192 (Join-Path $script:userStateRoot $name),
193 "first-$name",
194 [Text.UTF8Encoding]::new($false)
195 )
196 }
197 Backup-SbmsConfiguration
198 $backupRoot = Join-Path $script:userStateRoot 'upgrade-backups'
199 $firstSnapshots = @(
200 Get-ChildItem -LiteralPath $backupRoot -Directory
201 )
202 $firstSnapshots.Count | Should Be 1
203 $firstSnapshot = $firstSnapshots[0]
204
205 Remove-Item -LiteralPath (
206 Join-Path $script:userStateRoot 'config-v1.json'
207 ) -Force
208 Remove-Item -LiteralPath (
209 Join-Path $script:userStateRoot 'display-overrides-v1.json'
210 ) -Force
211 [IO.File]::WriteAllText(
212 (Join-Path $script:userStateRoot 'config-v2.json'),
213 'second-config-v2',
214 [Text.UTF8Encoding]::new($false)
215 )
216
217 Backup-SbmsConfiguration
218 $snapshots = @(
219 Get-ChildItem -LiteralPath $backupRoot -Directory
220 )
221 $snapshots.Count | Should Be 2
222 $secondSnapshots = @(
223 $snapshots | Where-Object Name -ne $firstSnapshot.Name
224 )
225 $secondSnapshots.Count | Should Be 1
226 $secondSnapshot = $secondSnapshots[0]
227
228 Test-Path -LiteralPath (
229 Join-Path $secondSnapshot.FullName 'config-v1.json'
230 ) | Should Be $false
231 Test-Path -LiteralPath (
232 Join-Path $secondSnapshot.FullName 'display-overrides-v1.json'
233 ) | Should Be $false
234 [IO.File]::ReadAllText(
235 (Join-Path $secondSnapshot.FullName 'config-v2.json'),
236 [Text.Encoding]::UTF8
237 ) | Should Be 'second-config-v2'
238
239 Test-Path -LiteralPath (
240 Join-Path $firstSnapshot.FullName 'config-v1.json'
241 ) -PathType Leaf | Should Be $true
242 Test-Path -LiteralPath (
243 Join-Path $firstSnapshot.FullName 'display-overrides-v1.json'
244 ) -PathType Leaf | Should Be $true
245 }
246
247 It 'deletes only the oldest owned snapshot and preserves unmarked directories' {
248 [IO.File]::WriteAllText(
249 (Join-Path $script:userStateRoot 'config-v2.json'),
250 '{"version":2}',
251 [Text.UTF8Encoding]::new($false)
252 )
253
254 $backupRoot = Join-Path $script:userStateRoot 'upgrade-backups'
255 New-Item -ItemType Directory -Path $backupRoot -Force | Out-Null
256 1..5 | ForEach-Object {
257 $ownedSnapshot = New-Item -ItemType Directory -Path (
258 Join-Path $backupRoot ("20200101T00000000{0}Z" -f $_)
259 ) -Force
260 [IO.File]::WriteAllText(
261 (Join-Path $ownedSnapshot.FullName '.sbms-upgrade-snapshot-v1'),
262 'SBMS upgrade snapshot v1',
263 [Text.UTF8Encoding]::new($false)
264 )
265 }
266 $unmarked = Join-Path $backupRoot '20200101T000000000Z'
267 New-Item -ItemType Directory -Path $unmarked -Force | Out-Null
268
269 Backup-SbmsConfiguration
270
271 $ownedSnapshots = @(
272 Get-ChildItem -LiteralPath $backupRoot -Directory |
273 Where-Object {
274 Test-OwnedUpgradeSnapshot -Snapshot $_ -BackupRoot $backupRoot
275 }
276 )
277 $ownedSnapshots.Count | Should Be 5
278 Test-Path -LiteralPath $unmarked -PathType Container | Should Be $true
279 Test-Path -LiteralPath (
280 Join-Path $backupRoot '20200101T000000001Z'
281 ) | Should Be $false
282 Test-Path -LiteralPath (
283 Join-Path $backupRoot '20200101T000000002Z'
284 ) -PathType Container | Should Be $true
285 }
286}
287