microsoft/hve-core

Public

mirrored from https://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
ci/2086-enforce-powershell-coverage

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

scripts/tests/devcontainer/Test-DevcontainerLockfile.Tests.ps1

207lines · modecode

1#Requires -Modules Pester
2# Copyright (c) Microsoft Corporation.
3# SPDX-License-Identifier: MIT
4
5BeforeAll {
6 . (Join-Path $PSScriptRoot '../../devcontainer/Test-DevcontainerLockfile.ps1')
7 Import-Module (Join-Path $PSScriptRoot '../../lib/Modules/CIHelpers.psm1') -Force
8
9 $script:FixturesPath = Join-Path $PSScriptRoot '../fixtures/Devcontainer'
10
11 Mock Write-Host {}
12 Mock Write-CIAnnotation {}
13}
14
15Describe 'Test-LockfileExists' -Tag 'Unit' {
16 Context 'when lockfile exists' {
17 It 'Returns Passed true' {
18 $lockDir = Join-Path $TestDrive '.devcontainer'
19 New-Item -ItemType Directory -Path $lockDir -Force | Out-Null
20 '{}' | Set-Content -Path (Join-Path $lockDir 'devcontainer-lock.json')
21
22 $result = Test-LockfileExists -RepoRoot $TestDrive
23
24 $result.Passed | Should -BeTrue
25 }
26 }
27
28 Context 'when lockfile is missing' {
29 It 'Returns Passed false' {
30 $result = Test-LockfileExists -RepoRoot $TestDrive
31
32 $result.Passed | Should -BeFalse
33 }
34 }
35}
36
37Describe 'Test-FeatureIntegrity' -Tag 'Unit' {
38 Context 'when all features have valid integrity' {
39 It 'Returns Passed true with no violations' {
40 $lockfile = Join-Path $script:FixturesPath 'valid-lock.json'
41
42 $result = Test-FeatureIntegrity -LockfilePath $lockfile
43
44 $result.Passed | Should -BeTrue
45 $result.Violations | Should -HaveCount 0
46 }
47 }
48
49 Context 'when feature is missing integrity' {
50 It 'Returns violation for missing integrity' {
51 $lockfile = Join-Path $script:FixturesPath 'missing-integrity-lock.json'
52
53 $result = Test-FeatureIntegrity -LockfilePath $lockfile
54
55 $result.Passed | Should -BeFalse
56 $result.Violations | Should -HaveCount 1
57 }
58 }
59
60 Context 'when feature is missing resolved' {
61 It 'Returns violation for missing resolved' {
62 $lockfile = Join-Path $script:FixturesPath 'missing-resolved-lock.json'
63
64 $result = Test-FeatureIntegrity -LockfilePath $lockfile
65
66 $result.Passed | Should -BeFalse
67 $result.Violations.Count | Should -BeGreaterThan 0
68 }
69 }
70
71 Context 'when integrity has wrong prefix' {
72 It 'Returns violation for non-sha256 hash' {
73 $lockfile = Join-Path $script:FixturesPath 'wrong-hash-lock.json'
74
75 $result = Test-FeatureIntegrity -LockfilePath $lockfile
76
77 $result.Passed | Should -BeFalse
78 }
79 }
80
81 Context 'when features object is empty' {
82 It 'Returns Passed true' {
83 $lockfile = Join-Path $script:FixturesPath 'empty-features-lock.json'
84
85 $result = Test-FeatureIntegrity -LockfilePath $lockfile
86
87 $result.Passed | Should -BeTrue
88 }
89 }
90}
91
92Describe 'Test-FeatureCoverage' -Tag 'Unit' {
93 Context 'when all config features are in lockfile' {
94 It 'Returns Passed true' {
95 $lockfile = Join-Path $script:FixturesPath 'valid-lock.json'
96 $config = Join-Path $script:FixturesPath 'valid-config.json'
97
98 $result = Test-FeatureCoverage -LockfilePath $lockfile -ConfigPath $config
99
100 $result.Passed | Should -BeTrue
101 $result.MissingKeys | Should -HaveCount 0
102 }
103 }
104
105 Context 'when config has extra features' {
106 It 'Returns MissingKeys containing the extra feature' {
107 $lockfile = Join-Path $script:FixturesPath 'valid-lock.json'
108 $config = Join-Path $script:FixturesPath 'extra-config-features.json'
109
110 $result = Test-FeatureCoverage -LockfilePath $lockfile -ConfigPath $config
111
112 $result.Passed | Should -BeFalse
113 $result.MissingKeys | Should -Contain 'ghcr.io/devcontainers/features/go:1'
114 }
115 }
116
117 Context 'when both have empty features' {
118 It 'Returns Passed true' {
119 $lockfile = Join-Path $script:FixturesPath 'empty-features-lock.json'
120 $config = Join-Path $script:FixturesPath 'empty-features-config.json'
121
122 $result = Test-FeatureCoverage -LockfilePath $lockfile -ConfigPath $config
123
124 $result.Passed | Should -BeTrue
125 }
126 }
127
128 Context 'when comparison is case-insensitive' {
129 It 'Matches features regardless of case' {
130 $lockDir = Join-Path $TestDrive 'case-test'
131 New-Item -ItemType Directory -Path $lockDir -Force | Out-Null
132
133 $lockContent = @{
134 features = @{
135 'ghcr.io/devcontainers/features/Node:1' = @{
136 resolved = 'ghcr.io/devcontainers/features/node@sha256:abc123'
137 integrity = 'sha256:abc123'
138 }
139 }
140 } | ConvertTo-Json -Depth 5
141 $lockPath = Join-Path $lockDir 'lock.json'
142 $lockContent | Set-Content -Path $lockPath
143
144 $configContent = @{
145 features = @{
146 'ghcr.io/devcontainers/features/node:1' = @{}
147 }
148 } | ConvertTo-Json -Depth 5
149 $configPath = Join-Path $lockDir 'config.json'
150 $configContent | Set-Content -Path $configPath
151
152 $result = Test-FeatureCoverage -LockfilePath $lockPath -ConfigPath $configPath
153
154 $result.Passed | Should -BeTrue
155 }
156 }
157}
158
159Describe 'Invoke-LockfileValidation' -Tag 'Unit' {
160 Context 'when all checks pass' {
161 It 'Returns FailedChecks 0' {
162 $devDir = Join-Path $TestDrive '.devcontainer'
163 New-Item -ItemType Directory -Path $devDir -Force | Out-Null
164
165 $lockContent = Get-Content -Path (Join-Path $script:FixturesPath 'valid-lock.json') -Raw
166 $lockContent | Set-Content -Path (Join-Path $devDir 'devcontainer-lock.json')
167
168 $configContent = Get-Content -Path (Join-Path $script:FixturesPath 'valid-config.json') -Raw
169 $configContent | Set-Content -Path (Join-Path $devDir 'devcontainer.json')
170
171 $result = Invoke-LockfileValidation -RepoRoot $TestDrive
172
173 $result.FailedChecks | Should -Be 0
174 }
175 }
176
177 Context 'when lockfile is missing' {
178 It 'Returns FailedChecks greater than 0' {
179 $devDir = Join-Path $TestDrive '.devcontainer'
180 New-Item -ItemType Directory -Path $devDir -Force | Out-Null
181
182 $configContent = Get-Content -Path (Join-Path $script:FixturesPath 'valid-config.json') -Raw
183 $configContent | Set-Content -Path (Join-Path $devDir 'devcontainer.json')
184
185 $result = Invoke-LockfileValidation -RepoRoot $TestDrive
186
187 $result.FailedChecks | Should -BeGreaterThan 0
188 }
189 }
190
191 Context 'when integrity violations exist' {
192 It 'Calls Write-CIAnnotation' {
193 $devDir = Join-Path $TestDrive '.devcontainer'
194 New-Item -ItemType Directory -Path $devDir -Force | Out-Null
195
196 $lockContent = Get-Content -Path (Join-Path $script:FixturesPath 'missing-integrity-lock.json') -Raw
197 $lockContent | Set-Content -Path (Join-Path $devDir 'devcontainer-lock.json')
198
199 $configContent = Get-Content -Path (Join-Path $script:FixturesPath 'valid-config.json') -Raw
200 $configContent | Set-Content -Path (Join-Path $devDir 'devcontainer.json')
201
202 Invoke-LockfileValidation -RepoRoot $TestDrive
203
204 Should -Invoke Write-CIAnnotation -Times 1
205 }
206 }
207}
208