Skip to content

Commit 0b93a89

Browse files
committed
test: cover install bootstrap integrity
1 parent 9a25f90 commit 0b93a89

1 file changed

Lines changed: 191 additions & 0 deletions

File tree

tests/powershell/Install.Tests.ps1

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
BeforeAll {
2+
$repositoryRoot = Split-Path -Parent $PSScriptRoot
3+
$repositoryRoot = Split-Path -Parent $repositoryRoot
4+
$installScriptPath = Join-Path $repositoryRoot 'install.ps1'
5+
$originalLocalAppData = $env:LOCALAPPDATA
6+
$realProfilePath = $PROFILE
7+
$realProfileSnapshot = if (Test-Path -LiteralPath $realProfilePath -PathType Leaf) {
8+
[pscustomobject]@{ Exists = $true; Hash = (Get-FileHash -LiteralPath $realProfilePath -Algorithm SHA256).Hash }
9+
}
10+
else {
11+
[pscustomobject]@{ Exists = $false; Hash = $null }
12+
}
13+
}
14+
15+
AfterAll {
16+
$env:LOCALAPPDATA = $originalLocalAppData
17+
$currentSnapshot = if (Test-Path -LiteralPath $realProfilePath -PathType Leaf) {
18+
[pscustomobject]@{ Exists = $true; Hash = (Get-FileHash -LiteralPath $realProfilePath -Algorithm SHA256).Hash }
19+
}
20+
else {
21+
[pscustomobject]@{ Exists = $false; Hash = $null }
22+
}
23+
$currentSnapshot.Exists | Should -Be $realProfileSnapshot.Exists
24+
$currentSnapshot.Hash | Should -Be $realProfileSnapshot.Hash
25+
}
26+
27+
Describe 'install.ps1 release bootstrap behavior' {
28+
BeforeEach {
29+
$env:LOCALAPPDATA = "C:\Users\Profile'Test\AppData\Local"
30+
$global:installDownloadUris = [System.Collections.Generic.List[string]]::new()
31+
$global:installDownloadPaths = [System.Collections.Generic.List[string]]::new()
32+
$global:installCopyRecords = [System.Collections.Generic.List[object]]::new()
33+
$global:installRemovedPaths = [System.Collections.Generic.List[string]]::new()
34+
$global:installNewItemPaths = [System.Collections.Generic.List[string]]::new()
35+
$global:installHashRecords = [System.Collections.Generic.List[object]]::new()
36+
$global:installImportRecords = [System.Collections.Generic.List[object]]::new()
37+
$global:installProfileAdds = [System.Collections.Generic.List[object]]::new()
38+
$global:installProfileExists = $false
39+
$global:installExistingProfileContent = @()
40+
$global:installHashMismatchCall = 0
41+
$global:installHashCall = 0
42+
$global:installHostArchitecture = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture
43+
$global:installExpectedAsset = switch ($global:installHostArchitecture) {
44+
'X64' { 'dev-windows-x86_64.exe' }
45+
'Arm64' { 'dev-windows-aarch64.exe' }
46+
default { throw "Unsupported test host architecture: $global:installHostArchitecture" }
47+
}
48+
49+
Mock Invoke-WebRequest {
50+
param($Uri, $OutFile)
51+
[void] $global:installDownloadUris.Add($Uri)
52+
[void] $global:installDownloadPaths.Add($OutFile)
53+
}
54+
Mock Get-Content {
55+
param($LiteralPath, $Raw)
56+
if ($LiteralPath -like '*.sha256') {
57+
return @(
58+
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $($global:installExpectedAsset)",
59+
'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB DevNav.psm1'
60+
)
61+
}
62+
if ($global:installProfileExists) { return $global:installExistingProfileContent }
63+
return ''
64+
}
65+
Mock Get-FileHash {
66+
param($LiteralPath, $Algorithm)
67+
$global:installHashCall++
68+
[void] $global:installHashRecords.Add([pscustomobject]@{ LiteralPath = $LiteralPath; Algorithm = $Algorithm })
69+
if ($global:installHashMismatchCall -eq $global:installHashCall) {
70+
return [pscustomobject]@{ Hash = 'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC' }
71+
}
72+
if ($LiteralPath -like '*.psm1') { return [pscustomobject]@{ Hash = 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB' } }
73+
return [pscustomobject]@{ Hash = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' }
74+
}
75+
Mock New-Item {
76+
param($Path)
77+
[void] $global:installNewItemPaths.Add($Path)
78+
[pscustomobject]@{ FullName = $Path }
79+
}
80+
Mock Copy-Item {
81+
param($LiteralPath, $Destination, $Force)
82+
[void] $global:installCopyRecords.Add([pscustomobject]@{ LiteralPath = $LiteralPath; Destination = $Destination; Force = $Force })
83+
}
84+
Mock Remove-Item {
85+
param($LiteralPath)
86+
[void] $global:installRemovedPaths.Add($LiteralPath)
87+
}
88+
Mock Import-Module {
89+
param($Name, $Force)
90+
[void] $global:installImportRecords.Add([pscustomobject]@{ Name = $Name; Force = $Force })
91+
}
92+
Mock Test-Path {
93+
param($LiteralPath, $PathType)
94+
return $global:installProfileExists
95+
}
96+
Mock Add-Content {
97+
param($LiteralPath, $Value)
98+
[void] $global:installProfileAdds.Add([pscustomobject]@{ LiteralPath = $LiteralPath; Value = $Value })
99+
}
100+
}
101+
102+
It 'downloads and installs the verified x64 release with SHA-256 checks' {
103+
& $installScriptPath -ModifyProfile:$false
104+
105+
$global:installDownloadUris | Should -Be @(
106+
"https://github.com/JacobOptimiza/dev-nav/releases/latest/download/$($global:installExpectedAsset)",
107+
'https://github.com/JacobOptimiza/dev-nav/releases/latest/download/DevNav.psm1',
108+
'https://github.com/JacobOptimiza/dev-nav/releases/latest/download/SHA256SUMS.txt'
109+
)
110+
$global:installDownloadPaths.Count | Should -Be 3
111+
$global:installHashRecords.Count | Should -Be 2
112+
$global:installHashRecords.Algorithm | Should -Be @('SHA256', 'SHA256')
113+
$global:installHashRecords.LiteralPath | Should -Be @($global:installDownloadPaths[0], $global:installDownloadPaths[1])
114+
$global:installCopyRecords.Count | Should -Be 2
115+
$global:installCopyRecords.LiteralPath | Should -Be @($global:installDownloadPaths[0], $global:installDownloadPaths[1])
116+
$global:installCopyRecords.Destination | Should -Be @(
117+
"C:\Users\Profile'Test\AppData\Local\Programs\DevNav\dev.exe",
118+
"C:\Users\Profile'Test\AppData\Local\Programs\DevNav\DevNav.psm1"
119+
)
120+
$global:installCopyRecords.Force | Should -Be @($true, $true)
121+
$global:installImportRecords.Count | Should -Be 1
122+
$global:installImportRecords.Name | Should -Be "C:\Users\Profile'Test\AppData\Local\Programs\DevNav\DevNav.psm1"
123+
$global:installImportRecords.Force | Should -BeTrue
124+
$global:installProfileAdds.Count | Should -Be 0
125+
$global:installRemovedPaths | Should -Be $global:installDownloadPaths
126+
Should -Invoke Test-Path -Times 0 -Scope It
127+
Should -Invoke Add-Content -Times 0 -Scope It
128+
}
129+
130+
It 'imports the installed module with a safely quoted profile path' {
131+
& $installScriptPath
132+
133+
$global:installProfileAdds.Count | Should -Be 1
134+
$global:installProfileAdds[0].LiteralPath | Should -Be $PROFILE
135+
$global:installProfileAdds[0].Value | Should -Be "`nImport-Module 'C:\Users\Profile''Test\AppData\Local\Programs\DevNav\DevNav.psm1'"
136+
$global:installRemovedPaths | Should -Be $global:installDownloadPaths
137+
}
138+
139+
It 'does not append a duplicate import when the profile already contains it' {
140+
$global:installProfileExists = $true
141+
$global:installExistingProfileContent = "Import-Module 'C:\Users\Profile''Test\AppData\Local\Programs\DevNav\DevNav.psm1'"
142+
143+
& $installScriptPath
144+
145+
$global:installProfileAdds.Count | Should -Be 0
146+
}
147+
148+
It 'fails when the executable checksum entry is missing' {
149+
Mock Get-Content {
150+
param($LiteralPath, $Raw)
151+
if ($LiteralPath -like '*.sha256') { return 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB DevNav.psm1' }
152+
return ''
153+
}
154+
155+
{ & $installScriptPath -ModifyProfile:$false } | Should -Throw "*No se encontró el checksum publicado para $($global:installExpectedAsset).*"
156+
$global:installCopyRecords | Should -BeNullOrEmpty
157+
$global:installImportRecords.Count | Should -Be 0
158+
$global:installRemovedPaths | Should -Be $global:installDownloadPaths
159+
}
160+
161+
It 'fails when the module checksum entry is missing' {
162+
Mock Get-Content {
163+
param($LiteralPath, $Raw)
164+
if ($LiteralPath -like '*.sha256') { return "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA $($global:installExpectedAsset)" }
165+
return ''
166+
}
167+
168+
{ & $installScriptPath -ModifyProfile:$false } | Should -Throw '*No se encontró el checksum publicado para DevNav.psm1.*'
169+
$global:installCopyRecords | Should -BeNullOrEmpty
170+
$global:installImportRecords.Count | Should -Be 0
171+
$global:installRemovedPaths | Should -Be $global:installDownloadPaths
172+
}
173+
174+
It 'fails when the executable checksum does not match' {
175+
$global:installHashMismatchCall = 1
176+
177+
{ & $installScriptPath -ModifyProfile:$false } | Should -Throw "*El checksum de $($global:installExpectedAsset) no coincide*"
178+
$global:installCopyRecords | Should -BeNullOrEmpty
179+
$global:installImportRecords.Count | Should -Be 0
180+
$global:installRemovedPaths | Should -Be $global:installDownloadPaths
181+
}
182+
183+
It 'fails when the module checksum does not match' {
184+
$global:installHashMismatchCall = 2
185+
186+
{ & $installScriptPath -ModifyProfile:$false } | Should -Throw '*El checksum de DevNav.psm1 no coincide*'
187+
$global:installCopyRecords | Should -BeNullOrEmpty
188+
$global:installImportRecords.Count | Should -Be 0
189+
$global:installRemovedPaths | Should -Be $global:installDownloadPaths
190+
}
191+
}

0 commit comments

Comments
 (0)