Skip to content

Commit b21b720

Browse files
Pester 6 - Drop stale v4/v5 references and take the version out of names (#10520)
1 parent 966913e commit b21b720

9 files changed

Lines changed: 65 additions & 74 deletions

File tree

.devcontainer/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ RUN echo "export HISTFILE=/commandhistory/.bash_history" >> "/root/.bashrc" \
2323
SHELL ["/opt/microsoft/powershell/7/pwsh", "-c"]
2424
RUN Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
2525

26-
# Install Pester, has to be 4.4.3 because 4.4.2 has bug in Unix machines
26+
# Install Pester, pinned to the version the test suite runs on
2727
SHELL ["/opt/microsoft/powershell/7/pwsh", "-c"]
28-
RUN $ErrorActionPreference='Stop'; Install-Module -Name Pester -Force -SkipPublisherCheck -MaximumVersion 4.4.3;
28+
RUN $ErrorActionPreference='Stop'; Install-Module -Name Pester -Force -SkipPublisherCheck -RequiredVersion 6.0.0;
2929

3030
# Install PSScriptAnalyzer
3131
SHELL ["/opt/microsoft/powershell/7/pwsh", "-c"]

.github/prompts/prompt.md

Lines changed: 0 additions & 13 deletions
This file was deleted.

.github/runners/tests/runner-policy.Tests.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ Describe "Get-DesiredRunnerPools demand-driven sizing" {
344344

345345
Describe "Get-PoolJobDemandFromJobs" {
346346
BeforeAll {
347-
# Defined in BeforeAll, not the Describe body: Pester 5 runs the Describe body
347+
# Defined in BeforeAll, not the Describe body: Pester runs the Describe body
348348
# during discovery, so a function declared there does not exist when the It
349349
# blocks execute. This matches the helper idiom in the top-level BeforeAll.
350350
function New-TestJob {

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ msbuild.binlog
2121
# Local constant file
2222
tests/constants.local.ps1
2323

24-
# Local coverage file produced by pester5
24+
# Local coverage file produced by Pester
2525
coverage.xml
2626

2727
# For those that want to use Docker images for testing

private/testing/Invoke-ManualPester.ps1

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ function Invoke-ManualPester {
9393
Every test file has to carry this requirement in its first line:
9494
#Requires -Module @{ ModuleName="Pester"; ModuleVersion="5.0" }
9595
96-
A file without it is reported and skipped rather than run, because dbatools no longer has
97-
Pester 4 tests and a missing header is a mistake in the test file.
96+
A file without it is reported and skipped rather than run, because a missing header is a
97+
mistake in the test file and not a request for a different runtime.
9898
#>
9999
[CmdletBinding()]
100100
param (
@@ -171,9 +171,9 @@ function Invoke-ManualPester {
171171
return (Get-ChildItem @splatCommandFile | Select-Object -First 1).FullName
172172
}
173173

174-
# Every test file has to declare the Pester 5 requirement. dbatools has no Pester 4 tests
175-
# left, so a file without the header is a mistake in the file and not a request for an
176-
# older runtime - it is reported instead of being run with something else.
174+
# Every test file has to declare the minimum Pester version it needs. A file without the
175+
# header is a mistake in the file and not a request for a different runtime - it is
176+
# reported instead of being run with something else.
177177
function Test-PesterTestHeader($testFilePath) {
178178
$testFileContent = Get-Content -Path $testFilePath -Raw
179179
return $testFileContent -match "#Requires\s+-Module\s+@\{\s+ModuleName=`"Pester`";\s+ModuleVersion=`"5\."
@@ -198,10 +198,12 @@ function Invoke-ManualPester {
198198

199199
$invokeFormatterVersion = (Get-Command Invoke-Formatter -ErrorAction SilentlyContinue).Version
200200
$HasScriptAnalyzer = $null -ne $invokeFormatterVersion
201-
# Pester 5 introduced the configuration object this function builds, and every test file in
202-
# the repository requires it. The CI pins 6.0.0 in tests\appveyor.prep.ps1.
203-
$MinimumPesterVersion = [Version] "5.0.0.0"
204-
$MaximumPesterVersion = [Version] "7.0.0.0"
201+
# The suite runs on Pester 6, which the CI pins to 6.0.0 in tests\appveyor.prep.ps1. A local
202+
# run is gated to the same major version so a local pass means the same thing CI does.
203+
# Three components, not four: Pester reports itself as 6.0.0, and [Version] treats an absent
204+
# revision as -1, so "6.0.0" would compare as lower than "6.0.0.0" and reject the pinned build.
205+
$MinimumPesterVersion = [Version] "6.0.0"
206+
$MaximumPesterVersion = [Version] "7.0.0"
205207
$PesterVersion = (Get-Command Invoke-Pester -ErrorAction SilentlyContinue).Version
206208
$HasPester = $null -ne $PesterVersion
207209
$ScriptAnalyzerCorrectVersion = "1.18.2"
@@ -365,7 +367,7 @@ function Invoke-ManualPester {
365367

366368
foreach ($f in $AllTestsWithinScenario) {
367369
if (-not (Test-PesterTestHeader -testFilePath $f.FullName)) {
368-
Write-Warning "$($f.Name) does not declare the mandatory Pester 5 header, skipping it. See tests\CLAUDE.md."
370+
Write-Warning "$($f.Name) does not declare the mandatory Pester header, skipping it. See tests\CLAUDE.md."
369371
continue
370372
}
371373

@@ -394,40 +396,40 @@ function Invoke-ManualPester {
394396
}
395397

396398
Write-DetailedMessage "Running tests $($f.Name)"
397-
$pester5Config = New-PesterConfiguration
398-
$pester5Config.Run.Path = $f.FullName
399-
$pester5Config.Run.PassThru = $true
400-
$pester5Config.Output.Verbosity = $Show
399+
$pesterConfig = New-PesterConfiguration
400+
$pesterConfig.Run.Path = $f.FullName
401+
$pesterConfig.Run.PassThru = $true
402+
$pesterConfig.Output.Verbosity = $Show
401403
if ($Coverage) {
402404
if ($CoverFiles.Count -eq 0) {
403405
Write-Warning "Cannot measure coverage for $($f.Name), no command file found for it"
404406
} else {
405-
$pester5Config.CodeCoverage.Enabled = $true
407+
$pesterConfig.CodeCoverage.Enabled = $true
406408
Write-DetailedMessage "We're going to target these files for coverage:"
407409
foreach ($cf in $CoverFiles) {
408410
Write-DetailedMessage "$cf"
409411
}
410-
$pester5Config.CodeCoverage.Path = $CoverFiles
412+
$pesterConfig.CodeCoverage.Path = $CoverFiles
411413
}
412414
}
413415
if (!($testInt)) {
414-
$pester5Config.Filter.ExcludeTag = "IntegrationTests"
416+
$pesterConfig.Filter.ExcludeTag = "IntegrationTests"
415417
}
416-
$pester5Result = Invoke-Pester -Configuration $pester5Config
418+
$pesterResult = Invoke-Pester -Configuration $pesterConfig
417419

418420
$runSummary += [PSCustomObject]@{
419421
TestFileName = $f.Name
420-
Result = $pester5Result.Result
421-
TotalCount = $pester5Result.TotalCount
422-
PassedCount = $pester5Result.PassedCount
423-
FailedCount = $pester5Result.FailedCount
424-
SkippedCount = $pester5Result.SkippedCount
425-
DurationSeconds = [int]$pester5Result.Duration.TotalSeconds
426-
Failed = $pester5Result.Failed
422+
Result = $pesterResult.Result
423+
TotalCount = $pesterResult.TotalCount
424+
PassedCount = $pesterResult.PassedCount
425+
FailedCount = $pesterResult.FailedCount
426+
SkippedCount = $pesterResult.SkippedCount
427+
DurationSeconds = [int]$pesterResult.Duration.TotalSeconds
428+
Failed = $pesterResult.Failed
427429
}
428430

429431
if ($PassThru) {
430-
$pester5Result
432+
$pesterResult
431433
}
432434

433435
if ($ScriptAnalyzer) {

tests/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ A `BeforeDiscovery` block inside the `Describe` is the tidier home for the same
285285

286286
Pester reads a test file twice. First it **discovers** the tests: it runs the file top to bottom, evaluates every `Describe`, `Context` and `It` *header*, and builds the tree. Only then does it **run** the tests: the `BeforeAll`, `BeforeEach`, `It` and `AfterAll` *bodies*.
287287

288-
Anything a header needs - `-Skip:`, `-ForEach`, the test name - has to exist at discovery time. Anything a body needs has to exist at run time. The two do not share variables, and this is the single biggest source of confusion left over from Pester v4.
288+
Anything a header needs - `-Skip:`, `-ForEach`, the test name - has to exist at discovery time. Anything a body needs has to exist at run time. The two do not share variables, and this is the single biggest source of confusion when writing a test file.
289289

290290
`BeforeDiscovery` is the block for discovery-time code. It keeps that code out of the `Describe` body while still running early enough:
291291

tests/Invoke-DbaDbCorruption.Tests.ps1

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,11 @@ Describe $CommandName -Tag IntegrationTests {
5757

5858
Context "Validating Database Input" {
5959
BeforeAll {
60-
# The command does not respect -WarningAction SilentlyContinue inside of this pester test - still don't know why, retest with pester 5
61-
$systemWarnVar = $null
62-
Invoke-DbaDbCorruption -SqlInstance $TestConfig.InstanceSingle -Database "master" -WarningVariable systemWarnVar 3> $null
60+
Invoke-DbaDbCorruption -SqlInstance $TestConfig.InstanceSingle -Database "master" -WarningAction SilentlyContinue
6361
}
6462

6563
It "Should not allow you to corrupt system databases." {
66-
$systemWarnVar -match "may not corrupt system databases" | Should -Be $true
64+
$WarnVar | Should -Match "may not corrupt system databases"
6765
}
6866

6967
It "Should fail if more than one database is specified" {

tests/appveyor.pester.ps1

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ $global:dbatools_dotsourcemodule = $true
6161
# imports the psm1 to be able to use internal functions in tests
6262
Import-Module "$ModuleBase\dbatools.psm1" -Force
6363

64+
# The one place this script names a Pester version. It has to match tests\appveyor.prep.ps1, which
65+
# is what actually installs the module on the build worker.
66+
$PesterRequiredVersion = "6.0.0"
67+
6468
function Split-ArrayInParts($array, [int]$parts) {
6569
#splits an array in "equal" parts
6670
$size = $array.Length / $parts
@@ -179,7 +183,7 @@ function Get-ComprehensiveErrorMessage {
179183
$debugInfo = @()
180184

181185
try {
182-
# Pester 5 error extraction with multiple fallbacks
186+
# Pester error extraction with multiple fallbacks
183187
if ($TestResult.ErrorRecord -and $TestResult.ErrorRecord.Count -gt 0) {
184188
foreach ($errorRec in $TestResult.ErrorRecord) {
185189
if ($errorRec.Exception) {
@@ -244,7 +248,7 @@ function Get-ComprehensiveErrorMessage {
244248
$errorMessages += "StdErr: $($TestResult.StandardError)"
245249
}
246250

247-
# Check Block.ErrorRecord for container-level errors (common in Pester 5)
251+
# Check Block.ErrorRecord for container-level errors
248252
if ($TestResult.Block -and $TestResult.Block.ErrorRecord) {
249253
foreach ($blockError in $TestResult.Block.ErrorRecord) {
250254
if ($blockError.Exception) {
@@ -325,7 +329,6 @@ function Export-TestFailureSummary {
325329

326330
$failedTests = @()
327331

328-
# Pester 5 format
329332
$failedTests = $PesterRun.Tests | Where-Object { $PSItem.Passed -eq $false } | ForEach-Object {
330333
# Extract line number from stack trace
331334
$lineNumber = $null
@@ -357,17 +360,17 @@ function Export-TestFailureSummary {
357360
if ($failedTests.Count -gt 0) {
358361
$summary = @{
359362
TestFile = $TestFile.Name
360-
PesterVersion = "5"
363+
PesterVersion = $PesterRequiredVersion
361364
TotalTests = $PesterRun.TotalCount
362365
PassedTests = $PesterRun.PassedCount
363366
FailedTests = $PesterRun.FailedCount
364367
Duration = $PesterRun.Duration.TotalMilliseconds
365368
Failures = $failedTests
366369
}
367370

368-
$summaryFile = "$ModuleBase\TestFailureSummary_Pester5_${Counter}.json"
371+
$summaryFile = "$ModuleBase\TestFailureSummary_${Counter}.json"
369372
$summary | ConvertTo-Json -Depth 10 | Out-File $summaryFile -Encoding UTF8
370-
Push-AppveyorArtifact $summaryFile -FileName "TestFailureSummary_Pester5_${Counter}.json"
373+
Push-AppveyorArtifact $summaryFile -FileName "TestFailureSummary_${Counter}.json"
371374
}
372375
}
373376

@@ -386,8 +389,7 @@ if (-not $Finalize) {
386389

387390
# Remove any previously loaded pester module
388391
Remove-Module -Name Pester -ErrorAction SilentlyContinue
389-
# Import Pester 6 release candidate
390-
Import-Module -Name Pester -RequiredVersion 6.0.0
392+
Import-Module -Name Pester -RequiredVersion $PesterRequiredVersion
391393
Write-Host -Object "appveyor.pester: Running with Pester Version $((Get-Command Invoke-Pester -ErrorAction SilentlyContinue).Version)" -ForegroundColor DarkGreen
392394

393395
# invoking a single invoke-pester consumes too much memory, let's go file by file
@@ -449,18 +451,18 @@ if (-not $Finalize) {
449451
foreach ($f in $AllTestsWithinScenario) {
450452
$Counter += 1
451453

452-
$pester5Config = New-PesterConfiguration
453-
$pester5Config.Run.Path = $f.FullName
454-
$pester5config.Run.PassThru = $true
455-
$pester5config.Output.Verbosity = "None"
454+
$pesterConfig = New-PesterConfiguration
455+
$pesterConfig.Run.Path = $f.FullName
456+
$pesterConfig.Run.PassThru = $true
457+
$pesterConfig.Output.Verbosity = "None"
456458

457459
#opt-in
458460
if ($IncludeCoverage) {
459461
$CoverFiles = Get-CoverageIndications -Path $f -ModuleBase $ModuleBase
460-
$pester5Config.CodeCoverage.Enabled = $true
461-
$pester5Config.CodeCoverage.Path = $CoverFiles
462-
$pester5Config.CodeCoverage.OutputFormat = "JaCoCo"
463-
$pester5Config.CodeCoverage.OutputPath = "$ModuleBase\Pester5Coverage$PSVersion$Counter.xml"
462+
$pesterConfig.CodeCoverage.Enabled = $true
463+
$pesterConfig.CodeCoverage.Path = $CoverFiles
464+
$pesterConfig.CodeCoverage.OutputFormat = "JaCoCo"
465+
$pesterConfig.CodeCoverage.OutputPath = "$ModuleBase\PesterCoverage$PSVersion$Counter.xml"
464466
}
465467

466468
$trialNo = 1
@@ -481,9 +483,9 @@ if (-not $Finalize) {
481483
} catch {
482484
Write-Host -Object "appveyor.pester: could not write the heartbeat. $($PSItem.Exception.Message)" -ForegroundColor Yellow
483485
}
484-
$PesterRun = Invoke-Pester -Configuration $pester5config
486+
$PesterRun = Invoke-Pester -Configuration $pesterConfig
485487
Write-Host -Object "`rCompleted $($f.FullName) in $([int]$PesterRun.Duration.TotalMilliseconds)ms" -ForegroundColor Cyan
486-
$PesterRun | Export-Clixml -Path "$ModuleBase\Pester5Results$PSVersion$Counter.xml"
488+
$PesterRun | Export-Clixml -Path "$ModuleBase\PesterResults$PSVersion$Counter.xml"
487489

488490
# Export failure summary for easier retrieval
489491
Export-TestFailureSummary -TestFile $f -PesterRun $PesterRun -Counter $Counter -ModuleBase $ModuleBase
@@ -516,7 +518,7 @@ if (-not $Finalize) {
516518
Outcome = "Failed"
517519
FailedCount = $PesterRun.FailedCount
518520
Duration = $PesterRun.Duration.TotalMilliseconds
519-
PesterVersion = "5"
521+
PesterVersion = $PesterRequiredVersion
520522
}
521523
} else {
522524
Update-AppveyorTest -Name $appvTestName -Framework NUnit -FileName $f.FullName -Outcome "Passed" -Duration $PesterRun.Duration.TotalMilliseconds
@@ -527,7 +529,7 @@ if (-not $Finalize) {
527529
Attempt = $trialNo
528530
Outcome = "Passed"
529531
Duration = $PesterRun.Duration.TotalMilliseconds
530-
PesterVersion = "5"
532+
PesterVersion = $PesterRequiredVersion
531533
}
532534
break
533535
}
@@ -591,7 +593,7 @@ if (-not $Finalize) {
591593
}
592594

593595
# What failed? How many tests did we run ?
594-
$results = @(Get-ChildItem -Path "$ModuleBase\Pester5Results*.xml" | Import-Clixml)
596+
$results = @(Get-ChildItem -Path "$ModuleBase\PesterResults*.xml" | Import-Clixml)
595597
$failedcount = $results | Select-Object -ExpandProperty FailedCount | Measure-Object -Sum | Select-Object -ExpandProperty Sum
596598
$faileditems = $results | Select-Object -ExpandProperty Tests | Where-Object { $PSItem.Passed -notlike $True }
597599
if ($faileditems) {
@@ -616,7 +618,7 @@ if (-not $Finalize) {
616618

617619
# Save detailed failure information as artifact
618620
$detailedFailureSummary = @{
619-
PesterVersion = "5"
621+
PesterVersion = $PesterRequiredVersion
620622
TotalFailedTests = $faileditems.Count
621623
DetailedFailures = $detailedFailures | ForEach-Object {
622624
@{
@@ -631,9 +633,9 @@ if (-not $Finalize) {
631633
}
632634
}
633635

634-
$detailedFailureFile = "$ModuleBase\DetailedTestFailures_Pester5.json"
636+
$detailedFailureFile = "$ModuleBase\DetailedTestFailures.json"
635637
$detailedFailureSummary | ConvertTo-Json -Depth 10 | Out-File $detailedFailureFile -Encoding UTF8
636-
Push-AppveyorArtifact $detailedFailureFile -FileName "DetailedTestFailures_Pester5.json"
638+
Push-AppveyorArtifact $detailedFailureFile -FileName "DetailedTestFailures.json"
637639

638640
throw "$failedcount tests failed."
639641
}

tests/appveyor.post.ps1

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ $sw = [system.diagnostics.stopwatch]::startNew()
33
Write-Host -Object "appveyor.post: Sending coverage data" -ForeGroundColor DarkGreen
44
$ProjectRoot = $env:APPVEYOR_BUILD_FOLDER
55
$ModuleBase = $ProjectRoot
6-
$pester5CoverageFiles = Get-ChildItem -Path "$ModuleBase\Pester5Coverage*.xml"
7-
foreach ($coverageFile in $pester5CoverageFiles) {
6+
$pesterCoverageFiles = Get-ChildItem -Path "$ModuleBase\PesterCoverage*.xml"
7+
foreach ($coverageFile in $pesterCoverageFiles) {
88
Write-Host -Object "appveyor.post: Sending $($coverageFile.FullName)" -ForeGroundColor DarkGreen
99
Push-AppveyorArtifact $coverageFile.FullName -FileName $coverageFile.Name
10+
# The flag still says pester5 on purpose. codecov keys its history off the flag name, so
11+
# renaming it starts a new series and loses the trend on the existing dashboards.
1012
codecov -f $coverageFile.FullName --flag "pester5_$($env:SCENARIO.ToLowerInvariant())" | Out-Null
1113
}
1214

0 commit comments

Comments
 (0)