返回 CodeWhale
installer-path-regression.tests.ps1
根目录 / scripts / installer / installer-path-regression.tests.ps1
1 [CmdletBinding()]
2 param(
3 [switch] $AllowUserPathMutation
4 )
5
6 $ErrorActionPreference = 'Stop'
7 Set-StrictMode -Version Latest
8
9 if ([System.Environment]::OSVersion.Platform -ne [System.PlatformID]::Win32NT) {
10 throw 'The installer PATH regression only supports Windows.'
11 }
12 if (-not $AllowUserPathMutation) {
13 throw 'Pass -AllowUserPathMutation to confirm this test may temporarily replace the current-user PATH.'
14 }
15
16 function Get-RawUserPath {
17 param(
18 [Parameter(Mandatory = $true)]
19 [Microsoft.Win32.RegistryKey] $EnvironmentKey
20 )
21
22 if (-not (@($EnvironmentKey.GetValueNames()) -contains 'Path')) {
23 return $null
24 }
25
26 return [string] $EnvironmentKey.GetValue(
27 'Path',
28 $null,
29 [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames
30 )
31 }
32
33 $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
34 $testRoot = Join-Path `
35 ([System.IO.Path]::GetTempPath()) `
36 "codewhale-installer-path-$PID-$([guid]::NewGuid().ToString('N'))"
37 $stageRoot = Join-Path $testRoot 'source'
38 $stageInstallerDir = Join-Path $stageRoot 'scripts\installer'
39 $installDir = Join-Path $testRoot 'installed'
40 $environmentKey = [Microsoft.Win32.Registry]::CurrentUser.CreateSubKey('Environment')
41 if ($null -eq $environmentKey) {
42 throw 'Could not open or create the current-user Environment registry key.'
43 }
44
45 $originalPathExists = @($environmentKey.GetValueNames()) -contains 'Path'
46 if ($originalPathExists) {
47 $originalPath = Get-RawUserPath -EnvironmentKey $environmentKey
48 $originalPathKind = $environmentKey.GetValueKind('Path')
49 }
50 else {
51 $originalPath = $null
52 $originalPathKind = [Microsoft.Win32.RegistryValueKind]::ExpandString
53 }
54
55 try {
56 [void] (New-Item -ItemType Directory -Path $stageInstallerDir -Force)
57 Copy-Item -LiteralPath (Join-Path $repoRoot 'LICENSE') -Destination (Join-Path $stageRoot 'LICENSE')
58 Copy-Item `
59 -LiteralPath (Join-Path $PSScriptRoot 'codewhale.nsi') `
60 -Destination (Join-Path $stageInstallerDir 'codewhale.nsi')
61 Copy-Item `
62 -LiteralPath (Join-Path $PSScriptRoot 'update-user-path.ps1') `
63 -Destination (Join-Path $stageInstallerDir 'update-user-path.ps1')
64
65 foreach ($binary in @('codewhale.exe', 'codew.exe', 'codewhale-tui.exe')) {
66 [System.IO.File]::WriteAllBytes(
67 (Join-Path $stageInstallerDir $binary),
68 [byte[]] @(0x4d, 0x5a)
69 )
70 }
71
72 $makensisCandidates = @(
73 "${env:ProgramFiles(x86)}\NSIS\makensis.exe",
74 "$env:ProgramFiles\NSIS\makensis.exe"
75 )
76 $makensis = $makensisCandidates |
77 Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } |
78 Select-Object -First 1
79 if ([string]::IsNullOrWhiteSpace($makensis)) {
80 throw 'makensis.exe was not found after installing NSIS.'
81 }
82
83 Push-Location $stageInstallerDir
84 try {
85 & $makensis '/DVERSION=0.0.0-test' 'codewhale.nsi'
86 if ($LASTEXITCODE -ne 0) {
87 throw "makensis.exe exited with code $LASTEXITCODE."
88 }
89 }
90 finally {
91 Pop-Location
92 }
93
94 $installer = Join-Path $stageInstallerDir 'CodeWhaleSetup.exe'
95 if (-not (Test-Path -LiteralPath $installer -PathType Leaf)) {
96 throw 'CodeWhaleSetup.exe was not produced.'
97 }
98
99 $canaries = [System.Collections.Generic.List[string]]::new()
100 $index = 1
101 while ((($canaries -join ';').Length) -lt 1800) {
102 $canaries.Add(('C:\CWCanary\DevelopmentTool{0:D4}\bin' -f $index))
103 $index++
104 }
105 $seedPath = $canaries -join ';'
106 $environmentKey.SetValue(
107 'Path',
108 $seedPath,
109 [Microsoft.Win32.RegistryValueKind]::ExpandString
110 )
111
112 $installArguments = [System.Collections.Generic.List[string]]::new()
113 $installArguments.Add('/S')
114 $installArguments.Add("/D=$installDir")
115 $installProcess = Start-Process `
116 -FilePath $installer `
117 -ArgumentList @($installArguments) `
118 -Wait `
119 -PassThru
120 if ($installProcess.ExitCode -ne 0) {
121 throw "CodeWhaleSetup.exe exited with code $($installProcess.ExitCode)."
122 }
123
124 $expectedBin = Join-Path $installDir 'bin'
125 $afterInstall = Get-RawUserPath -EnvironmentKey $environmentKey
126 if (([string] $afterInstall) -cne "$seedPath;$expectedBin") {
127 throw "The installer did not preserve the seeded long PATH exactly. Before=$($seedPath.Length), after=$(([string] $afterInstall).Length)."
128 }
129 if ($environmentKey.GetValueKind('Path') -ne [Microsoft.Win32.RegistryValueKind]::ExpandString) {
130 throw 'The installer changed the user PATH registry value kind.'
131 }
132
133 $uninstaller = Join-Path $installDir 'Uninstall.exe'
134 if (-not (Test-Path -LiteralPath $uninstaller -PathType Leaf)) {
135 throw 'Uninstall.exe was not produced.'
136 }
137 $uninstallProcess = Start-Process `
138 -FilePath $uninstaller `
139 -ArgumentList '/S' `
140 -Wait `
141 -PassThru
142 if ($uninstallProcess.ExitCode -ne 0) {
143 throw "Uninstall.exe exited with code $($uninstallProcess.ExitCode)."
144 }
145
146 $afterUninstall = Get-RawUserPath -EnvironmentKey $environmentKey
147 if (([string] $afterUninstall) -cne $seedPath) {
148 throw 'Install followed by uninstall did not restore the seeded long PATH exactly.'
149 }
150
151 Write-Host "Full NSIS installer PATH regression passed with $($seedPath.Length) characters."
152 }
153 finally {
154 $uninstaller = Join-Path $installDir 'Uninstall.exe'
155 if (Test-Path -LiteralPath $uninstaller -PathType Leaf) {
156 try {
157 [void] (Start-Process -FilePath $uninstaller -ArgumentList '/S' -Wait -PassThru)
158 }
159 catch {
160 Write-Warning "Best-effort test uninstallation failed: $_"
161 }
162 }
163
164 if ($originalPathExists) {
165 $environmentKey.SetValue('Path', $originalPath, $originalPathKind)
166 }
167 else {
168 $environmentKey.DeleteValue('Path', $false)
169 }
170 $environmentKey.Close()
171
172 if (Test-Path -LiteralPath $testRoot) {
173 Remove-Item -LiteralPath $testRoot -Recurse -Force -ErrorAction SilentlyContinue
174 }
175 }
176
176 lines Plain Text