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.
文件
../ build-installer-contract.Tests.ps13.0 KBinno-user-state.Tests.ps12.3 KBlaunch-entry-contract.Tests.ps18.1 KBmaintenance-compensation.Tests.ps15.3 KBprepare-upgrade.Tests.ps110.3 KBinstaller/tests/prepare-upgrade.Tests.ps110.3 KB
1
$ErrorActionPreference = 'Stop'2
Set-StrictMode -Version Latest3
4
$maintenanceScript = [IO.Path]::GetFullPath(5
(Join-Path $PSScriptRoot '..\maintenance.ps1')6
)7
8
Describe 'PrepareUpgrade maintenance contract' {9
BeforeAll {10
$loadRoot = Join-Path $TestDrive 'load-root'11
New-Item -ItemType Directory -Path $loadRoot -Force | Out-Null12
13
# Load the real function definitions without dispatching an action. This14
# keeps the contract tests isolated from live SBMS processes, tasks, and15
# drivers.16
$maintenanceSource = [IO.File]::ReadAllText(17
$maintenanceScript,18
[Text.Encoding]::UTF819
)20
$dispatchMarker = 'switch ($Action) {'21
$dispatchIndex = $maintenanceSource.LastIndexOf(22
$dispatchMarker,23
[StringComparison]::Ordinal24
)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 $loadRoot32
}33
34
BeforeEach {35
$script:previousLocalAppData = $env:LOCALAPPDATA36
$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-Null43
New-Item -ItemType Directory -Path $script:installRoot -Force | Out-Null44
$env:LOCALAPPDATA = $script:localAppData45
$script:configRoot = $script:userStateRoot46
}47
48
AfterEach {49
$env:LOCALAPPDATA = $script:previousLocalAppData50
}51
52
It 'exposes PrepareUpgrade as a supported action' {53
$source = [IO.File]::ReadAllText(54
$maintenanceScript,55
[Text.Encoding]::UTF856
)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 = $null64
$parseErrors = $null65
$ast = [Management.Automation.Language.Parser]::ParseFile(66
$maintenanceScript,67
[ref]$tokens,68
[ref]$parseErrors69
)70
@($parseErrors).Count | Should Be 071
72
$prepare = $ast.Find(73
{74
param($node)75
$node -is [Management.Automation.Language.FunctionDefinitionAst] -and76
$node.Name -eq 'Prepare-SbmsUpgrade'77
},78
$true79
)80
$prepare | Should Not BeNullOrEmpty81
82
$body = $prepare.Extent.Text83
$stopIndex = $body.IndexOf('Stop-Sbms', [StringComparison]::Ordinal)84
$snapshotIndex = $body.IndexOf(85
'Backup-SbmsConfiguration',86
[StringComparison]::Ordinal87
)88
($stopIndex -ge 0) | Should Be $true89
($snapshotIndex -gt $stopIndex) | Should Be $true90
}91
92
It 'does not create a backup directory when no configuration exists' {93
Backup-SbmsConfiguration94
95
Test-Path -LiteralPath (96
Join-Path $script:userStateRoot 'upgrade-backups'97
) | Should Be $false98
}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-SbmsConfiguration121
$snapshot = @(122
Get-ChildItem -LiteralPath (123
Join-Path $script:userStateRoot 'upgrade-backups'124
) -Directory125
)126
$snapshot.Count | Should Be 1127
$snapshot = $snapshot[0]128
129
foreach ($entry in $expected.GetEnumerator()) {130
$copy = Join-Path $snapshot.FullName $entry.Key131
Test-Path -LiteralPath $copy -PathType Leaf | Should Be $true132
[IO.File]::ReadAllText($copy, [Text.Encoding]::UTF8) |133
Should Be $entry.Value134
}135
Test-Path -LiteralPath (136
Join-Path $snapshot.FullName 'unrelated.txt'137
) | Should Be $false138
}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-SbmsConfiguration163
$snapshot = @(164
Get-ChildItem -LiteralPath (165
Join-Path $script:userStateRoot 'upgrade-backups'166
) -Directory167
)[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]::UTF8175
) | Should Be 'SBMS upgrade snapshot v1'176
Test-OwnedUpgradeSnapshot -Snapshot $snapshot -BackupRoot (177
Join-Path $script:userStateRoot 'upgrade-backups'178
) | Should Be $true179
Test-Path -LiteralPath (180
Join-Path $snapshot.FullName 'manifest.json'181
) | Should Be $false182
}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-SbmsConfiguration198
$backupRoot = Join-Path $script:userStateRoot 'upgrade-backups'199
$firstSnapshots = @(200
Get-ChildItem -LiteralPath $backupRoot -Directory201
)202
$firstSnapshots.Count | Should Be 1203
$firstSnapshot = $firstSnapshots[0]204
205
Remove-Item -LiteralPath (206
Join-Path $script:userStateRoot 'config-v1.json'207
) -Force208
Remove-Item -LiteralPath (209
Join-Path $script:userStateRoot 'display-overrides-v1.json'210
) -Force211
[IO.File]::WriteAllText(212
(Join-Path $script:userStateRoot 'config-v2.json'),213
'second-config-v2',214
[Text.UTF8Encoding]::new($false)215
)216
217
Backup-SbmsConfiguration218
$snapshots = @(219
Get-ChildItem -LiteralPath $backupRoot -Directory220
)221
$snapshots.Count | Should Be 2222
$secondSnapshots = @(223
$snapshots | Where-Object Name -ne $firstSnapshot.Name224
)225
$secondSnapshots.Count | Should Be 1226
$secondSnapshot = $secondSnapshots[0]227
228
Test-Path -LiteralPath (229
Join-Path $secondSnapshot.FullName 'config-v1.json'230
) | Should Be $false231
Test-Path -LiteralPath (232
Join-Path $secondSnapshot.FullName 'display-overrides-v1.json'233
) | Should Be $false234
[IO.File]::ReadAllText(235
(Join-Path $secondSnapshot.FullName 'config-v2.json'),236
[Text.Encoding]::UTF8237
) | Should Be 'second-config-v2'238
239
Test-Path -LiteralPath (240
Join-Path $firstSnapshot.FullName 'config-v1.json'241
) -PathType Leaf | Should Be $true242
Test-Path -LiteralPath (243
Join-Path $firstSnapshot.FullName 'display-overrides-v1.json'244
) -PathType Leaf | Should Be $true245
}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-Null256
1..5 | ForEach-Object {257
$ownedSnapshot = New-Item -ItemType Directory -Path (258
Join-Path $backupRoot ("20200101T00000000{0}Z" -f $_)259
) -Force260
[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-Null268
269
Backup-SbmsConfiguration270
271
$ownedSnapshots = @(272
Get-ChildItem -LiteralPath $backupRoot -Directory |273
Where-Object {274
Test-OwnedUpgradeSnapshot -Snapshot $_ -BackupRoot $backupRoot275
}276
)277
$ownedSnapshots.Count | Should Be 5278
Test-Path -LiteralPath $unmarked -PathType Container | Should Be $true279
Test-Path -LiteralPath (280
Join-Path $backupRoot '20200101T000000001Z'281
) | Should Be $false282
Test-Path -LiteralPath (283
Join-Path $backupRoot '20200101T000000002Z'284
) -PathType Container | Should Be $true285
}286
}287