Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
4 changes: 4 additions & 0 deletions staging/cse/windows/README
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
1. Run unit test:
- look at the pipeline for how to do this. It has a comment about how to use Tags to run only a particular test:
- .github/workflows/validate-windows-ut.yml
- Example commands:
- `Invoke-Pester parts/windows/*.tests.ps1 -Passthru`
- `Invoke-Pester staging/cse/windows/*.tests.ps1 -Passthru`
- `Invoke-Pester vhdbuilder/packer/windows/*.tests.ps1 -Passthru`
1. Watch out different powershell versions. Sometimes JSON parsing works differently in your local powershell and in the pipeline. Which is annoying.

# Test with AKS RP
Expand Down
1 change: 1 addition & 0 deletions staging/cse/windows/all.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

# Dot-source cse scripts with functions that are bundled on the VHD
. $PSScriptRoot\helpers.ps1
. c:\AzureData\windows\azurecnifunc.ps1
. c:\AzureData\windows\calicofunc.ps1
. c:\AzureData\windows\configfunc.ps1
Expand Down
43 changes: 43 additions & 0 deletions staging/cse/windows/helpers.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# common helper functions

function Remove-ServiceIfExists
{
param(
[Parameter(Mandatory = $true)][string]$ServiceName
)
# A prior provisioning attempt may have already registered this service (e.g. CSE re-invoked
# after a partial failure). Best-effort remove it so the subsequent nssm.exe install doesn't
# fail against an already-existing service.
$svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($null -ne $svc) {
sc.exe delete $ServiceName
# sc.exe delete can legitimately return non-zero here (e.g. 1072 - service already marked for deletion)
# since this is best-effort cleanup of a pre-existing service, don't treat that as fatal.
if ($LASTEXITCODE -ne 0) { Write-Log "sc.exe failed to delete existing $ServiceName service (exit code $LASTEXITCODE), continuing anyway" }
}
}

function Invoke-NssmExe
{
# Thin wrapper around the path-qualified nssm.exe invocation so tests can Mock it;
# Pester cannot intercept a call like `& "$KubeDir\nssm.exe"` directly since path-qualified
# commands bypass function/command name resolution.
param(
[Parameter(Mandatory = $true)][string]$KubeDir,
[Parameter(Mandatory = $true, ValueFromRemainingArguments = $true)][string[]]$NssmArguments
)
& "$KubeDir\nssm.exe" @NssmArguments
}

function Invoke-Nssm
{
param(
[Parameter(Mandatory = $true)][string]$KubeDir,
[Parameter(Mandatory = $true, ValueFromRemainingArguments = $true)][string[]]$NssmArguments
)
Invoke-NssmExe -KubeDir $KubeDir -NssmArguments $NssmArguments | RemoveNulls
if ($LASTEXITCODE -ne 0)
Comment thread
timmy-wright marked this conversation as resolved.
{
throw "nssm.exe $( $NssmArguments -join ' ' ) failed (exit code $LASTEXITCODE)"
}
}
82 changes: 82 additions & 0 deletions staging/cse/windows/helpers.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
BeforeAll {
. $PSScriptRoot\..\..\..\parts\windows\windowscsehelper.ps1
. $PSCommandPath.Replace('.tests.ps1', '.ps1')

# Get-Service and sc.exe are Windows-only; stub them so Mock can override them when
# tests run in isolation (e.g. locally on non-Windows, outside the full suite).
function Get-Service {}
function sc.exe {}
}

Describe 'Remove-ServiceIfExists' {
Context 'when the service does not exist' {
BeforeEach {
$script:scExeCallCount = 0
Mock Get-Service -MockWith { return $null }
Mock sc.exe -MockWith { $script:scExeCallCount++ }
}

It 'does not call sc.exe' {
Remove-ServiceIfExists -ServiceName 'some-service'

$script:scExeCallCount | Should -Be 0
}
}

Context 'when the service already exists' {
BeforeEach {
$script:scExeCallCount = 0
$mockExistingSvc = [PSCustomObject]@{Name = 'some-service'; Status = 'Stopped'}
Mock Get-Service -MockWith { return $mockExistingSvc }
}

It 'calls sc.exe delete to remove the existing service' {
Mock sc.exe -MockWith { $script:scExeCallCount++; $global:LASTEXITCODE = 0 }

Remove-ServiceIfExists -ServiceName 'some-service'

$script:scExeCallCount | Should -Be 1
}

It 'does not throw when sc.exe delete succeeds' {
Mock sc.exe -MockWith { $global:LASTEXITCODE = 0 }

{ Remove-ServiceIfExists -ServiceName 'some-service' } | Should -Not -Throw
}

It 'does not throw when sc.exe delete fails (best-effort cleanup)' {
Mock sc.exe -MockWith { $global:LASTEXITCODE = 1 }

{ Remove-ServiceIfExists -ServiceName 'some-service' } | Should -Not -Throw
}
}
}

Describe 'Invoke-Nssm' {
BeforeEach {
$script:nssmInvocations = @()
}

It 'does not throw when nssm.exe succeeds' {
Mock Invoke-NssmExe -MockWith {
$script:nssmInvocations += , @($NssmArguments)
$global:LASTEXITCODE = 0
return 'ok'
}

{ Invoke-Nssm -KubeDir 'C:\k' -NssmArguments 'install', 'some-service', 'C:\k\some-service.exe' } | Should -Not -Throw

$script:nssmInvocations.Count | Should -Be 1
$script:nssmInvocations[0] | Should -Be @('install', 'some-service', 'C:\k\some-service.exe')
}

It 'throws with the exit code when nssm.exe fails' {
Mock Invoke-NssmExe -MockWith {
$global:LASTEXITCODE = 1
return $null
}

{ Invoke-Nssm -KubeDir 'C:\k' -NssmArguments 'install', 'some-service', 'C:\k\some-service.exe' } |
Should -Throw '*failed (exit code 1)*'
}
}
Loading