Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ step-templates/*.sh
step-templates/*.py
/.vs
!.vscode
*copy.ps1
40 changes: 14 additions & 26 deletions step-templates/tests/Invoke-PesterTests.ps1
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
param(
[string] $Filter = "*"
)

$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";

$thisScript = $MyInvocation.MyCommand.Path;
$thisFolder = [System.IO.Path]::GetDirectoryName($thisScript);
$rootFolder = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($thisFolder, "..", "..")); # Adjust to always point to the root
$testFiles = Get-ChildItem -Path "$thisFolder" -Filter "*.tests.ps1" -Recurse
$sharedRunner = Join-Path $rootFolder "tools" "Invoke-SharedPesterTests.ps1"

function Unpack-Scripts-Under-Test {
$testFiles = Get-ChildItem -Path "$thisFolder" -Filter "*.tests.ps1" -Recurse

foreach ($testFile in $testFiles) {
$baseName = $testFile.BaseName -replace "\.ScriptBody.Tests$"
$scriptFileName = "$baseName.ScriptBody.ps1"
Expand Down Expand Up @@ -35,28 +41,10 @@ function Unpack-Scripts-Under-Test {
}
}

function Import-Pester {
# Attempt to use local Pester module, fallback to global if not found
try {
$packagesFolder = [System.IO.Path]::Combine($rootFolder, "packages")
$pester3Path = [System.IO.Path]::Combine($packagesFolder, "Pester\tools\Pester")
# Import the specific version of Pester 3.4.0
Import-Module -Name $pester3Path -RequiredVersion 3.4.0 -ErrorAction Stop
} catch {
Write-Host "Using globally installed Pester module version 3.4.0."
# Specify the exact version of Pester 3.x you have installed
Import-Module -Name Pester -RequiredVersion 3.4.0 -ErrorAction Stop
}
}

function Run-Tests {
# Find and run all Pester test files in the tests directory
foreach ($testFile in $testFiles) {
Write-Host "Running tests in: $($testFile.FullName)"
Invoke-Pester -Path $testFile.FullName
}
}

Import-Pester
Unpack-Scripts-Under-Test
Run-Tests
& $sharedRunner `
-TestRoot $thisFolder `
-Filter $Filter `
-BeforeRun ${function:Unpack-Scripts-Under-Test} `
-UsePassThruFailureCheck `
-PreferredPesterVersion "3.4.0" `
-SuiteName "step-templates"
4 changes: 2 additions & 2 deletions step-templates/tests/sql-backup-database.ScriptBody.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";

. "$PSScriptRoot\..\sql-backup-database.ScriptBody.ps1"
. (Join-Path $PSScriptRoot ".." "sql-backup-database.ScriptBody.ps1")

function SetupTestEnvironment {
param(
Expand Down Expand Up @@ -79,7 +79,7 @@ function SetupTestEnvironment {
Describe "ApplyRetentionPolicy Tests" {

BeforeAll {
$script:BackupDirectory = "C:\Backups"
$script:BackupDirectory = Join-Path ([System.IO.Path]::GetTempPath()) "OctopusDeployLibrary-SqlBackupTests"
$script:DatabaseName = "ExampleDB"
$script:StartDate = Get-Date
$script:timestampFormat = "yyyy-MM-dd-HHmmss"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";

. "$PSScriptRoot\..\windows-scheduled-task-create.ScriptBody.ps1"
. (Join-Path $PSScriptRoot ".." "windows-scheduled-task-create.ScriptBody.ps1")

Describe "Create-ScheduledTask" {

Expand Down
133 changes: 133 additions & 0 deletions tools/Invoke-SharedPesterTests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
param(
[Parameter(Mandatory = $true)]
[string] $TestRoot,
[string] $Filter = "*",
[scriptblock] $BeforeRun,
[string[]] $ImportModules = @(),
[switch] $UsePassThruFailureCheck,
[string] $PreferredPesterVersion,
[string] $SuiteName = "tests"
)

$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";

$testRootPath = [System.IO.Path]::GetFullPath($TestRoot)
$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot ".."))
$originalSystemRoot = $env:SystemRoot
$originalTemp = $env:TEMP

function Get-PesterModuleSpec {
$packagesFolder = Join-Path $repoRoot "packages"
$attempts = @()
$localPesterPaths = @()

if ($PreferredPesterVersion) {
$localPesterPaths += (Join-Path $packagesFolder ("Pester.{0}" -f $PreferredPesterVersion) "tools" "Pester")
}
$localPesterPaths += (Join-Path $packagesFolder "Pester" "tools" "Pester")

foreach ($localPesterPath in $localPesterPaths | Select-Object -Unique) {
$attempts += $localPesterPath
if (Test-Path -Path $localPesterPath) {
$localManifestPath = Join-Path $localPesterPath "Pester.psd1"
$modulePath = $localPesterPath
if (Test-Path -Path $localManifestPath) {
$modulePath = $localManifestPath
}

$module = Test-ModuleManifest -Path $modulePath -ErrorAction Stop
if ($module.Version.Major -eq 3 -and ((-not $PreferredPesterVersion) -or $module.Version -eq [version]$PreferredPesterVersion)) {
return [pscustomobject]@{
ModulePath = $module.Path
Version = $module.Version.ToString()
Source = "repository packages"
}
}
}
}

$availablePesterModules = @(Get-Module -ListAvailable Pester | Sort-Object Version -Descending)
$globalPester = $null

if ($PreferredPesterVersion) {
$globalPester = $availablePesterModules | Where-Object { $_.Version -eq [version]$PreferredPesterVersion } | Select-Object -First 1
}

if (-not $globalPester) {
$globalPester = $availablePesterModules | Where-Object { $_.Version.Major -eq 3 } | Select-Object -First 1
}

if ($globalPester) {
return [pscustomobject]@{
ModulePath = $globalPester.Path
Version = $globalPester.Version.ToString()
Source = "installed modules"
}
}

$preferredVersionMessage = if ($PreferredPesterVersion) { "preferred version $PreferredPesterVersion" } else { "a Pester 3.x version" }
$attemptedPathsMessage = if ($attempts.Count -gt 0) { " Tried package paths: $($attempts -join ', ')." } else { "" }
throw "Pester $preferredVersionMessage for suite '$SuiteName' was not found in the repository packages folder or installed modules.$attemptedPathsMessage"
}

function Invoke-SelectedTests {
param(
[Parameter(Mandatory = $true)]
[System.IO.FileInfo[]] $TestFiles
)

foreach ($testFile in $TestFiles) {
Write-Host "Running tests in: $($testFile.FullName)"
if ($UsePassThruFailureCheck) {
$result = Invoke-Pester -Path $testFile.FullName -PassThru
if ($result.FailedCount -gt 0) {
throw "Tests failed in $($testFile.FullName)."
}
} else {
Invoke-Pester -Path $testFile.FullName
}
}
}

try {
if (-not $env:SystemRoot) {
$env:SystemRoot = "C:\Windows"
}
if (-not $env:TEMP) {
$env:TEMP = [System.IO.Path]::GetTempPath()
}

foreach ($modulePath in $ImportModules) {
Import-Module -Name $modulePath -ErrorAction Stop
}

if ($BeforeRun) {
& $BeforeRun
}

$testFiles = @(Get-ChildItem -Path $testRootPath -Filter "*.tests.ps1" -Recurse)
if (-not [string]::IsNullOrWhiteSpace($Filter) -and $Filter -ne "*") {
$testFiles = @($testFiles | Where-Object { $_.Name -like $Filter -or $_.FullName -like $Filter })
}

if ($testFiles.Count -eq 0) {
Write-Host "No matching test files found under $testRootPath for filter '$Filter'."
return
}

if ($PSVersionTable.PSEdition -eq "Core" -and -not $IsWindows) {
$referenceAssembliesPath = Join-Path $PSHOME "ref"
if (-not (Test-Path -Path $referenceAssembliesPath)) {
throw "Pester 3.4.3 on macOS requires a compatible pwsh installation with reference assemblies under '$referenceAssembliesPath'. This runner is intentionally lean and does not patch Pester at runtime."
}
}

$pesterModule = Get-PesterModuleSpec
Write-Host "Using Pester module version $($pesterModule.Version) from $($pesterModule.Source)."
Import-Module -Name $pesterModule.ModulePath -RequiredVersion $pesterModule.Version -ErrorAction Stop
Invoke-SelectedTests -TestFiles $testFiles
} finally {
$env:SystemRoot = $originalSystemRoot
$env:TEMP = $originalTemp
}
12 changes: 6 additions & 6 deletions tools/StepTemplatePacker/tests/ConvertTo-OctopusJson.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";
. (Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "Test-JsonAssertions.ps1")

Describe "ConvertTo-OctopusDeploy" {

Expand Down Expand Up @@ -55,8 +56,7 @@ Describe "ConvertTo-OctopusDeploy" {
It "InputObject is a populated array" {
$input = @( $null, 100, "my string" );
$expected = "[`r`n null,`r`n 100,`r`n `"my string`"`r`n]";
ConvertTo-OctopusJson -InputObject $input `
| Should Be $expected;
ConvertTo-OctopusJson -InputObject $input | Should BeJsonEquivalent $expected
}

It "InputObject is an empty PSCustomObject" {
Expand Down Expand Up @@ -90,15 +90,15 @@ Describe "ConvertTo-OctopusDeploy" {
"myPsObject": {
"childProperty": "childValue"
}
}
}
"@
ConvertTo-OctopusJson -InputObject $input `
| Should Be $expected;
$expected = $expected.Trim()
ConvertTo-OctopusJson -InputObject $input | Should BeJsonEquivalent $expected
}

It "InputObject is an unhandled type" {
{ ConvertTo-OctopusJson -InputObject ([System.Guid]::NewGuid()) } `
| Should Throw "Unhandled input object type 'System.Guid'.";
}

}
}
23 changes: 12 additions & 11 deletions tools/StepTemplatePacker/tests/Invoke-PesterTests.ps1
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
param(
[string] $Filter = "*"
)

$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";

$thisScript = $MyInvocation.MyCommand.Path;
$thisFolder = [System.IO.Path]::GetDirectoryName($thisScript);

$packagesFolder = $thisFolder;
$packagesFolder = [System.IO.Path]::GetDirectoryName($packagesFolder);
$packagesFolder = [System.IO.Path]::GetDirectoryName($packagesFolder);
$packagesFolder = [System.IO.Path]::GetDirectoryName($packagesFolder);
$packagesFolder = [System.IO.Path]::Combine($packagesFolder, "packages");

$repoRoot = [System.IO.Path]::GetFullPath((Join-Path $thisFolder ".." ".." ".."));
$packer = [System.IO.Path]::GetDirectoryName($thisFolder);
$sharedRunner = Join-Path $repoRoot "tools" "Invoke-SharedPesterTests.ps1";

Import-Module -Name $packer;
Import-Module -Name ([System.IO.Path]::Combine($packagesFolder, "Pester.3.4.3\tools\Pester"));

Invoke-Pester;
& $sharedRunner `
-TestRoot $thisFolder `
-Filter $Filter `
-ImportModules @($packer) `
-PreferredPesterVersion "3.4.3" `
-SuiteName "StepTemplatePacker";
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";
. (Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "Test-JsonAssertions.ps1")

Describe "Set-OctopusStepTemplateProperty" {

Expand All @@ -9,8 +10,7 @@ Describe "Set-OctopusStepTemplateProperty" {
-PropertyName "Octopus.Action.Script.Syntax" `
-Value "PowerShell";
$expected = "{`r`n `"Properties`": {`r`n `"Octopus.Action.Script.Syntax`": `"PowerShell`"`r`n }`r`n}";
ConvertTo-OctopusJson -InputObject $stepJson `
| Should Be $expected;
ConvertTo-OctopusJson -InputObject $stepJson | Should BeJsonEquivalent $expected
}

It "No properties exist" {
Expand All @@ -19,8 +19,7 @@ Describe "Set-OctopusStepTemplateProperty" {
-PropertyName "Octopus.Action.Script.Syntax" `
-Value "PowerShell";
$expected = "{`r`n `"Properties`": {`r`n `"Octopus.Action.Script.Syntax`": `"PowerShell`"`r`n }`r`n}";
ConvertTo-OctopusJson -InputObject $stepJson `
| Should Be $expected;
ConvertTo-OctopusJson -InputObject $stepJson | Should BeJsonEquivalent $expected
}

It "Specified property does not exist" {
Expand All @@ -29,8 +28,7 @@ Describe "Set-OctopusStepTemplateProperty" {
-PropertyName "Octopus.Action.Script.Syntax" `
-Value "PowerShell";
$expected = "{`r`n `"Properties`": {`r`n `"otherProperty`": `"`",`r`n `"Octopus.Action.Script.Syntax`": `"PowerShell`"`r`n }`r`n}";
ConvertTo-OctopusJson -InputObject $stepJson `
| Should Be $expected;
ConvertTo-OctopusJson -InputObject $stepJson | Should BeJsonEquivalent $expected
}

It "Property does not exist" {
Expand All @@ -39,8 +37,7 @@ Describe "Set-OctopusStepTemplateProperty" {
-PropertyName "Octopus.Action.Script.Syntax" `
-Value "PowerShell";
$expected = "{`r`n `"Properties`": {`r`n `"Octopus.Action.Script.Syntax`": `"PowerShell`"`r`n }`r`n}";
ConvertTo-OctopusJson -InputObject $stepJson `
| Should Be $expected;
ConvertTo-OctopusJson -InputObject $stepJson | Should BeJsonEquivalent $expected
}

It "Property exists with a null value" {
Expand All @@ -49,8 +46,7 @@ Describe "Set-OctopusStepTemplateProperty" {
-PropertyName "Octopus.Action.Script.Syntax" `
-Value "PowerShell";
$expected = "{`r`n `"Properties`": {`r`n `"Octopus.Action.Script.Syntax`": `"PowerShell`"`r`n }`r`n}";
ConvertTo-OctopusJson -InputObject $stepJson `
| Should Be $expected;
ConvertTo-OctopusJson -InputObject $stepJson | Should BeJsonEquivalent $expected
}

It "Property exists with an empty string value" {
Expand All @@ -59,8 +55,7 @@ Describe "Set-OctopusStepTemplateProperty" {
-PropertyName "Octopus.Action.Script.Syntax" `
-Value "PowerShell";
$expected = "{`r`n `"Properties`": {`r`n `"Octopus.Action.Script.Syntax`": `"PowerShell`"`r`n }`r`n}";
ConvertTo-OctopusJson -InputObject $stepJson `
| Should Be $expected;
ConvertTo-OctopusJson -InputObject $stepJson | Should BeJsonEquivalent $expected
}

It "Property exists with a string value" {
Expand All @@ -69,9 +64,8 @@ Describe "Set-OctopusStepTemplateProperty" {
-PropertyName "Octopus.Action.Script.Syntax" `
-Value "PowerShell";
$expected = "{`r`n `"Properties`": {`r`n `"Octopus.Action.Script.Syntax`": `"PowerShell`"`r`n }`r`n}";
ConvertTo-OctopusJson -InputObject $stepJson `
| Should Be $expected;
ConvertTo-OctopusJson -InputObject $stepJson | Should BeJsonEquivalent $expected
}


}
}
20 changes: 20 additions & 0 deletions tools/StepTemplatePacker/tests/Test-JsonAssertions.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function global:ConvertTo-CompressedJsonForAssertion {
param(
[Parameter(Mandatory = $true)]
[string] $Json
)

return (ConvertFrom-Json -InputObject $Json | ConvertTo-Json -Depth 10 -Compress)
}

function global:PesterBeJsonEquivalent($value, $expected) {
return (ConvertTo-CompressedJsonForAssertion -Json $value) -eq (ConvertTo-CompressedJsonForAssertion -Json $expected)
}

function global:PesterBeJsonEquivalentFailureMessage($value, $expected) {
return "Expected JSON equivalent to: {$expected}`nBut was: {$value}"
}

function global:NotPesterBeJsonEquivalentFailureMessage($value, $expected) {
return "Expected JSON not equivalent to: {$expected}`nBut was: {$value}"
}
Loading