forked from pester/Pester
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Pester.RSpec.InNewProcess.ts.ps1
228 lines (185 loc) · 9.25 KB
/
Pester.RSpec.InNewProcess.ts.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
param ([switch] $PassThru)
Get-Module Pester.Runtime, Pester.Utility, P, Pester, Axiom, Stack | Remove-Module
Import-Module $PSScriptRoot\p.psm1 -DisableNameChecking
Import-Module $PSScriptRoot\axiom\Axiom.psm1 -DisableNameChecking
& "$PSScriptRoot\..\build.ps1"
Import-Module $PSScriptRoot\..\bin\Pester.psd1
$global:PesterPreference = @{
Debug = @{
ShowFullErrors = $true
}
}
$PSDefaultParameterValues = @{}
function Invoke-InNewProcess ([ScriptBlock] $ScriptBlock) {
# get the path of the currently loaded Pester to re-import it in the child process
$pesterPath = Get-Module Pester | Select-Object -ExpandProperty Path
$powershell = Get-Process -Id $pid | Select-Object -ExpandProperty Path
# run any scriptblock in a separate process to be able to grab all the output
# doesn't enforce Invoke-Pester usage so we can test other public functions directly
$command = {
param ($PesterPath, [ScriptBlock] $ScriptBlock)
Import-Module $PesterPath
. $ScriptBlock
}.ToString()
# we need to escape " with \" because otherwise the " are eaten when the process we are starting recieves them
$cmd = "& { $command } -PesterPath ""$PesterPath"" -ScriptBlock { $($ScriptBlock -replace '"','\"') }"
& $powershell -NoProfile -ExecutionPolicy Bypass -Command $cmd
}
i -PassThru:$PassThru {
b "Interactive execution" {
t "Works with directly invoked testfile using Describe" {
# https://github.com/pester/Pester/issues/1771
$temp = [IO.Path]::GetTempPath()
$testpath = Join-Path $temp "$([Guid]::NewGuid().Guid).tests.ps1"
try {
$c = 'Describe "d" { It "i" { 1 | Should -Be 1 } }'
Set-Content -Path $testpath -Value $c
$sb = [scriptblock]::Create("`$global:PesterPreference = [PesterConfiguration]@{Output=@{Verbosity='Detailed'}}; & $testpath")
$output = Invoke-InNewProcess -ScriptBlock $sb
$passedTests = $output | Select-String -SimpleMatch -Pattern '[+]' -Context 1, 0
$passedTests | Verify-NotNull
@($passedTests).Count | Verify-Equal 1
$passedTests.Context.PreContext | Verify-Equal "Describing d"
}
finally {
Remove-Item -Path $testpath
}
}
t "Works with directly invoked testfile using Context" {
$temp = [IO.Path]::GetTempPath()
$testpath = Join-Path $temp "$([Guid]::NewGuid().Guid).tests.ps1"
try {
$c = 'Context "c" { It "i" { 1 | Should -Be 1 } }'
Set-Content -Path $testpath -Value $c
$sb = [scriptblock]::Create("`$global:PesterPreference = [PesterConfiguration]@{Output=@{Verbosity='Detailed'}}; & $testpath")
$output = Invoke-InNewProcess -ScriptBlock $sb
$passedTests = $output | Select-String -SimpleMatch -Pattern '[+]' -Context 1, 0
$passedTests | Verify-NotNull
@($passedTests).Count | Verify-Equal 1
$passedTests.Context.PreContext | Verify-Equal "Context c"
}
finally {
Remove-Item -Path $testpath
}
}
t "Works with directly invoked parameterized testfile using Describe" {
# https://github.com/pester/Pester/issues/1784
$temp = [IO.Path]::GetTempPath()
$testpath = Join-Path $temp "$([Guid]::NewGuid().Guid).tests.ps1"
try {
$c = 'param([Parameter(Mandatory)]$File, $MyValue = 1) Describe "d - <File>" { It "i" { $MyValue | Should -Be 1 } }'
Set-Content -Path $testpath -Value $c
$sb = [scriptblock]::Create("`$global:PesterPreference = [PesterConfiguration]@{Output=@{Verbosity='Detailed'}}; & $testpath -File 'demo.ps1'")
$output = Invoke-InNewProcess -ScriptBlock $sb
$passedTests = $output | Select-String -SimpleMatch -Pattern '[+]' -Context 1, 0
$passedTests | Verify-NotNull
@($passedTests).Count | Verify-Equal 1
$passedTests.Context.PreContext | Verify-Equal "Describing d - demo.ps1"
}
finally {
Remove-Item -Path $testpath
}
}
t "Works with directly invoked parameterized testfile using Context" {
$temp = [IO.Path]::GetTempPath()
$testpath = Join-Path $temp "$([Guid]::NewGuid().Guid).tests.ps1"
try {
$c = 'param([Parameter(Mandatory)]$File, $MyValue = 1) Context "c - <File>" { It "i" { $MyValue | Should -Be 1 } }'
Set-Content -Path $testpath -Value $c
$sb = [scriptblock]::Create("`$global:PesterPreference = [PesterConfiguration]@{Output=@{Verbosity='Detailed'}}; & $testpath -File 'demo.ps1'")
$output = Invoke-InNewProcess -ScriptBlock $sb
$passedTests = $output | Select-String -SimpleMatch -Pattern '[+]' -Context 1, 0
$passedTests | Verify-NotNull
@($passedTests).Count | Verify-Equal 1
$passedTests.Context.PreContext | Verify-Equal "Context c - demo.ps1"
}
finally {
Remove-Item -Path $testpath
}
}
}
b "Exit codes" {
t "Exitcode is set to 0 without exiting the process when tests pass, even when some executable fails within test" {
$temp = [IO.Path]::GetTempPath()
$testpath = Join-Path $temp "$([Guid]::NewGuid().Guid).tests.ps1"
$powershell = (Get-Process -Id $pid).Path
try {
$c = "
Describe 'd' {
It 'i' {
# an executable exits with 99 (we use powershell as the executable, because we know it will work cross platform)
& '$powershell' -Command { exit 99 }
`$LASTEXITCODE | Should -Be 99
}
}"
Set-Content -Path $testpath -Value $c
$sb = [scriptblock]::Create("
try {
Invoke-Pester -Path $testpath -EnableExit
`$exitCode = `$LASTEXITCODE
}
finally {
# exitcode was set to 99 in the test because the test passed,
# BUT after the run the exit code should be 0 because all tests pass
# AND we should NOT exit the process even though the -EnableExit is used
# to allow running multiple successful runs in the same process.
# So to ensure we did not exit too early we set exitcode and
# check it in finally.
if (`$null -eq `$exitCode) {
throw 'Pester exited the process prematurely, `$exitcode variable was not set.'
}
if (0 -ne `$exitCode) {
throw `"`$exitCode is not 0.`"
}
}
")
$output = Invoke-InNewProcess -ScriptBlock $sb
$passedTests = $output | Select-String -SimpleMatch -Pattern '[+]'
$passedTests | Verify-NotNull
@($passedTests).Count | Verify-Equal 1
$LASTEXITCODE | Verify-Equal 0
}
finally {
Remove-Item -Path $testpath
}
}
t "Exitcode is set to the number of failed tests and the process exits when tests fail, even when some executable fails within test" {
$temp = [IO.Path]::GetTempPath()
$testpath = Join-Path $temp "$([Guid]::NewGuid().Guid).tests.ps1"
$powershell = (Get-Process -Id $pid).Path
try {
$c = "
Describe 'd' {
It 'i' {
# an executable exits with 99 (we use powershell as the executable, because we know it will work cross platform)
# we use this to fail the test
& '$powershell' -Command { exit 99 }
`$LASTEXITCODE | Should -Be 0
}
}"
Set-Content -Path $testpath -Value $c
$sb = [scriptblock]::Create("
try {
Invoke-Pester -Path $testpath -EnableExit
`$codeAfterPester = `$true
}
finally {
# exitcode was set to 99 because one test failed in the test
# but some test failed we should immediately fail and the codeAfterPester should not run
if (`$codeAfterPester) {
throw 'Pester did not exit the process immediately, `$codeAfterPester should not run.'
}
}
")
$output = Invoke-InNewProcess -ScriptBlock $sb
$passedTests = $output | Select-String -SimpleMatch -Pattern '[-]'
$passedTests | Verify-NotNull
@($passedTests).Count | Verify-Equal 1
$LASTEXITCODE | Verify-Equal 1
}
finally {
Remove-Item -Path $testpath
}
}
}
}