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/launch-entry-contract.Tests.ps18.1 KB
1
$ErrorActionPreference = 'Stop'2
Set-StrictMode -Version Latest3
4
$repository = [IO.Path]::GetFullPath(5
(Join-Path $PSScriptRoot '..\..')6
)7
$installerScript = Join-Path $repository 'installer\SBMS.iss'8
$maintenanceScript = Join-Path $repository 'installer\maintenance.ps1'9
$launchBroker = Join-Path $repository 'src\launch_broker.rs'10
11
function Get-InnoSection {12
param(13
[Parameter(Mandatory)]14
[string]$Source,15
16
[Parameter(Mandatory)]17
[string]$Name18
)19
20
$match = [regex]::Match(21
$Source,22
"(?ms)^\[$([regex]::Escape($Name))\]\s*(?<body>.*?)(?=^\[|\z)"23
)24
if (-not $match.Success) {25
throw "Inno Setup section [$Name] was not found."26
}27
$match.Groups['body'].Value28
}29
30
Describe 'SBMS launch entry contract' {31
BeforeAll {32
$script:installerSource = [IO.File]::ReadAllText(33
$installerScript,34
[Text.Encoding]::UTF835
)36
$script:maintenanceSource = [IO.File]::ReadAllText(37
$maintenanceScript,38
[Text.Encoding]::UTF839
)40
$script:launchBrokerSource = [IO.File]::ReadAllText(41
$launchBroker,42
[Text.Encoding]::UTF843
)44
45
$dispatchMarker = 'switch ($Action) {'46
$dispatchIndex = $script:maintenanceSource.LastIndexOf(47
$dispatchMarker,48
[StringComparison]::Ordinal49
)50
if ($dispatchIndex -lt 0) {51
throw 'maintenance.ps1 action dispatcher was not found.'52
}53
$definitions = $script:maintenanceSource.Substring(0, $dispatchIndex)54
$script:loadRoot = Join-Path $TestDrive 'install-root'55
New-Item -ItemType Directory -Path $script:loadRoot -Force | Out-Null56
. ([scriptblock]::Create($definitions)) `57
-Action Stop `58
-InstallRoot $script:loadRoot59
}60
61
It 'marks the Start menu launch as an explicit open request' {62
$icons = Get-InnoSection `63
-Source $script:installerSource `64
-Name 'Icons'65
$shortcut = @(66
$icons -split "`r?`n" |67
Where-Object {68
$_ -match '(?i)^\s*Name:\s*"\{group\}\\SBMS"\s*;'69
}70
)71
72
$shortcut.Count | Should Be 173
$shortcut[0] | Should Match (74
'(?i);\s*Filename:\s*"\{app\}\\sbms-tray\.exe"\s*;' +75
'\s*Parameters:\s*"--open"(?:\s*;|\s*$)'76
)77
}78
79
It 'registers an interactive highest-privilege background tray task' {80
$script:mockTaskAction =81
[Microsoft.Management.Infrastructure.CimInstance]::new('MSFT_TaskAction')82
$script:mockTrigger =83
[Microsoft.Management.Infrastructure.CimInstance]::new('MSFT_TaskTrigger')84
$script:mockPrincipal =85
[Microsoft.Management.Infrastructure.CimInstance]::new('MSFT_TaskPrincipal')86
$script:mockSettings =87
[Microsoft.Management.Infrastructure.CimInstance]::new('MSFT_TaskSettings')88
$script:startedProcess = [pscustomobject]@{ Id = 4242 }89
$script:processScan = 090
$script:taskRegistered = $false91
Mock Assert-InstallIdentity {92
[pscustomobject]@{ Sid = 'S-1-5-21-test' }93
}94
Mock Get-ScheduledTask { $null }95
Mock New-ScheduledTaskAction { $script:mockTaskAction }96
Mock New-ScheduledTaskTrigger { $script:mockTrigger }97
Mock New-ScheduledTaskPrincipal { $script:mockPrincipal }98
Mock New-ScheduledTaskSettingsSet { $script:mockSettings }99
Mock Register-ScheduledTask {100
$marker = [System.Threading.Mutex]::OpenExisting('Local\SBMS-Manual-Launch-Broker-7EB4D7A8')101
$marker.Dispose()102
$script:taskRegistered = $true103
}104
Mock Start-ScheduledTask {}105
$script:readyChecks = 0106
Mock Test-SbmsTrayReady {107
$marker = [System.Threading.Mutex]::OpenExisting('Local\SBMS-Manual-Launch-Broker-7EB4D7A8')108
$marker.Dispose()109
$script:readyChecks++110
$script:readyChecks -ge 2111
}112
Mock Start-Sleep {}113
Mock Get-InstalledSbmsProcesses {114
$script:processScan++115
if ($script:taskRegistered) {116
$script:startedProcess117
}118
}119
120
Install-SbmsTask121
122
Assert-MockCalled New-ScheduledTaskAction -Times 1 -Exactly `123
-ParameterFilter {124
$Execute -eq $script:tray -and125
$Argument -ceq '--background' -and126
$WorkingDirectory -eq $script:loadRoot127
}128
Assert-MockCalled New-ScheduledTaskTrigger -Times 1 -Exactly `129
-ParameterFilter {130
$AtLogOn -and $User -eq 'S-1-5-21-test'131
}132
Assert-MockCalled New-ScheduledTaskPrincipal -Times 1 -Exactly `133
-ParameterFilter {134
$UserId -eq 'S-1-5-21-test' -and135
$LogonType -eq 'Interactive' -and136
$RunLevel -eq 'Highest'137
}138
Assert-MockCalled New-ScheduledTaskSettingsSet -Times 1 -Exactly `139
-ParameterFilter {140
$AllowStartIfOnBatteries -and141
$DontStopIfGoingOnBatteries -and142
$ExecutionTimeLimit -eq [TimeSpan]::Zero -and143
$MultipleInstances.ToString() -eq 'IgnoreNew'144
}145
Assert-MockCalled Register-ScheduledTask -Times 1 -Exactly `146
-ParameterFilter {147
$TaskPath -eq '\SBMS\' -and148
$TaskName -eq 'Tray-7EB4D7A8-16A9-4B6F-82E3-31A77BC81B6A' -and149
$Action.Count -eq 1 -and150
[object]::ReferenceEquals($Action[0], $script:mockTaskAction) -and151
$Trigger.Count -eq 1 -and152
[object]::ReferenceEquals($Trigger[0], $script:mockTrigger) -and153
[object]::ReferenceEquals($Principal, $script:mockPrincipal) -and154
[object]::ReferenceEquals($Settings, $script:mockSettings)155
}156
Assert-MockCalled Start-ScheduledTask -Times 1 -Exactly `157
-ParameterFilter {158
$TaskPath -eq '\SBMS\' -and159
$TaskName -eq 'Tray-7EB4D7A8-16A9-4B6F-82E3-31A77BC81B6A'160
}161
Assert-MockCalled Start-Sleep -Times 1 -Exactly `162
-ParameterFilter { $Milliseconds -eq 200 }163
$script:processScan | Should Be 3164
{ [System.Threading.Mutex]::OpenExisting('Local\SBMS-Manual-Launch-Broker-7EB4D7A8') } | Should Throw165
}166
167
It 'accepts the legacy empty task arguments during an upgrade' {168
Mock Get-ScheduledTask {169
[pscustomobject]@{170
Actions = @(171
[pscustomobject]@{172
Execute = $script:tray173
Arguments = ''174
WorkingDirectory = $script:loadRoot175
}176
)177
}178
}179
180
$task = Get-VerifiedTask -Path '\SBMS\' -Name 'test'181
182
$task | Should Not BeNullOrEmpty183
}184
185
It 'rejects an unexpected action count before indexing the task action' {186
Mock Get-ScheduledTask {187
[pscustomobject]@{ Actions = @() }188
}189
190
$failure = $null191
try {192
Get-VerifiedTask -Path '\SBMS\' -Name 'test'193
}194
catch {195
$failure = $_196
}197
198
$failure | Should Not BeNullOrEmpty199
$failure.Exception.Message | Should Match 'Scheduled task collision'200
}201
202
It 'keeps the registered task name identical in Rust and PowerShell' {203
$rustName = [regex]::Match(204
$script:launchBrokerSource,205
'(?ms)pub const REGISTERED_TASK_NAME:\s*&str\s*=\s*r"([^"]+)";'206
)207
$powerShellPath = [regex]::Match(208
$script:maintenanceSource,209
'(?m)^\$taskPath\s*=\s*''([^'']+)'''210
)211
$powerShellName = [regex]::Match(212
$script:maintenanceSource,213
'(?m)^\$taskName\s*=\s*''([^'']+)'''214
)215
216
$rustName.Success | Should Be $true217
$powerShellPath.Success | Should Be $true218
$powerShellName.Success | Should Be $true219
($powerShellPath.Groups[1].Value + $powerShellName.Groups[1].Value) |220
Should Be $rustName.Groups[1].Value221
}222
}223