#Requires -Version 5.1 <# .SYNOPSIS Pester v5 tests for scripts/_Common.psm1 #> BeforeAll { Import-Module (Join-Path $PSScriptRoot '..\scripts\_Common.psm1') -Force # Fake vmrun: accepts any args, exits with %FAKE_VMRUN_EXIT% (default 0) $script:FakeVmrun = Join-Path $env:TEMP "fake-vmrun-$PID.cmd" Set-Content $script:FakeVmrun -Value @' @echo off echo fake-vmrun-output if "%FAKE_VMRUN_EXIT%"=="" ( exit /b 0 ) else ( exit /b %FAKE_VMRUN_EXIT% ) '@ } AfterAll { Remove-Item $script:FakeVmrun -Force -ErrorAction SilentlyContinue } # ───────────────────────────────────────────────────────────────────────────── Describe 'New-CISessionOption' { It 'returns a PSSessionOption' { $opt = New-CISessionOption $opt | Should -BeOfType [System.Management.Automation.Remoting.PSSessionOption] } It 'has SkipCACheck = true' { (New-CISessionOption).SkipCACheck | Should -Be $true } It 'has SkipCNCheck = true' { (New-CISessionOption).SkipCNCheck | Should -Be $true } It 'has SkipRevocationCheck = true' { (New-CISessionOption).SkipRevocationCheck | Should -Be $true } } # ───────────────────────────────────────────────────────────────────────────── Describe 'Resolve-VmrunPath' { It 'returns the path when the file exists' { $tmp = [System.IO.Path]::GetTempFileName() try { Resolve-VmrunPath -VmrunPath $tmp | Should -Be $tmp } finally { Remove-Item $tmp -Force -ErrorAction SilentlyContinue } } It 'throws with a descriptive message when file is missing' { { Resolve-VmrunPath -VmrunPath 'C:\DoesNotExist\vmrun.exe' } | Should -Throw -ExpectedMessage '*vmrun.exe not found*' } } # ───────────────────────────────────────────────────────────────────────────── Describe 'Invoke-Vmrun' { It 'returns ExitCode 0 and Output when command succeeds' { $env:FAKE_VMRUN_EXIT = '0' $r = Invoke-Vmrun -VmrunPath $script:FakeVmrun -Operation 'list' $r.ExitCode | Should -Be 0 "$($r.Output)" | Should -Match 'fake-vmrun-output' } It 'returns non-zero ExitCode without throwing by default' { $env:FAKE_VMRUN_EXIT = '1' $r = Invoke-Vmrun -VmrunPath $script:FakeVmrun -Operation 'clone' $r.ExitCode | Should -Be 1 } It 'throws when -ThrowOnError and ExitCode is non-zero' { $env:FAKE_VMRUN_EXIT = '1' { Invoke-Vmrun -VmrunPath $script:FakeVmrun -Operation 'clone' -ThrowOnError } | Should -Throw -ExpectedMessage '*clone failed*' } It 'does not throw when -ThrowOnError and ExitCode is 0' { $env:FAKE_VMRUN_EXIT = '0' { Invoke-Vmrun -VmrunPath $script:FakeVmrun -Operation 'start' -ThrowOnError } | Should -Not -Throw } AfterEach { $env:FAKE_VMRUN_EXIT = $null } } # ───────────────────────────────────────────────────────────────────────────── Describe 'Invoke-VmrunBounded' { BeforeAll { # Fake vmrun that sleeps for $FAKE_VMRUN_SLEEP seconds then exits with # $FAKE_VMRUN_EXIT. Both default to 0 if unset. $script:SlowFakeVmrun = Join-Path $env:TEMP "fake-vmrun-slow-$PID.cmd" Set-Content $script:SlowFakeVmrun -Value @' @echo off if "%FAKE_VMRUN_SLEEP%"=="" goto :nosleep ping -n %FAKE_VMRUN_SLEEP% 127.0.0.1 >nul :nosleep echo fake-vmrun-bounded-output if "%FAKE_VMRUN_EXIT%"=="" ( exit /b 0 ) else ( exit /b %FAKE_VMRUN_EXIT% ) '@ } AfterAll { Remove-Item $script:SlowFakeVmrun -Force -ErrorAction SilentlyContinue } AfterEach { $env:FAKE_VMRUN_EXIT = $null $env:FAKE_VMRUN_SLEEP = $null } It 'returns ExitCode 0, TimedOut false and Output when command succeeds quickly' { $env:FAKE_VMRUN_EXIT = '0' $env:FAKE_VMRUN_SLEEP = '0' $r = Invoke-VmrunBounded -VmrunPath $script:SlowFakeVmrun -Operation 'start' -Arguments @('some.vmx', 'nogui') -TimeoutSeconds 30 $r.ExitCode | Should -Be 0 $r.TimedOut | Should -Be $false "$($r.Output)" | Should -Match 'fake-vmrun-bounded-output' $r.ElapsedSeconds | Should -BeGreaterOrEqual 0 } It 'returns non-zero ExitCode without throwing by default' { $env:FAKE_VMRUN_EXIT = '3' $env:FAKE_VMRUN_SLEEP = '0' $r = Invoke-VmrunBounded -VmrunPath $script:SlowFakeVmrun -Operation 'deleteVM' -TimeoutSeconds 30 $r.ExitCode | Should -Be 3 $r.TimedOut | Should -Be $false } It 'throws when -ThrowOnError and ExitCode is non-zero' { $env:FAKE_VMRUN_EXIT = '2' $env:FAKE_VMRUN_SLEEP = '0' { Invoke-VmrunBounded -VmrunPath $script:SlowFakeVmrun -Operation 'stop' -TimeoutSeconds 30 -ThrowOnError } | Should -Throw -ExpectedMessage '*stop failed*' } It 'does not throw when -ThrowOnError and ExitCode is 0' { $env:FAKE_VMRUN_EXIT = '0' $env:FAKE_VMRUN_SLEEP = '0' { Invoke-VmrunBounded -VmrunPath $script:SlowFakeVmrun -Operation 'start' -TimeoutSeconds 30 -ThrowOnError } | Should -Not -Throw } It 'times out and returns TimedOut = true when process exceeds TimeoutSeconds' { # FAKE_VMRUN_SLEEP uses ping -n N which waits roughly (N-1) seconds. # Set sleep >> timeout so the process is guaranteed to still be running. $env:FAKE_VMRUN_SLEEP = '60' $env:FAKE_VMRUN_EXIT = '0' $r = Invoke-VmrunBounded -VmrunPath $script:SlowFakeVmrun -Operation 'start' -TimeoutSeconds 2 $r.TimedOut | Should -Be $true $r.ExitCode | Should -Be -1 $r.ElapsedSeconds | Should -BeLessOrEqual 10 # killed well before 60s } It 'throws when -ThrowOnTimeout and process times out' { $env:FAKE_VMRUN_SLEEP = '60' $env:FAKE_VMRUN_EXIT = '0' { Invoke-VmrunBounded -VmrunPath $script:SlowFakeVmrun -Operation 'deleteVM' -TimeoutSeconds 2 -ThrowOnTimeout } | Should -Throw -ExpectedMessage '*timed out*' } It 'does not throw on timeout when neither flag is set' { $env:FAKE_VMRUN_SLEEP = '60' $env:FAKE_VMRUN_EXIT = '0' { Invoke-VmrunBounded -VmrunPath $script:SlowFakeVmrun -Operation 'start' -TimeoutSeconds 2 } | Should -Not -Throw } It 'ElapsedSeconds is populated and plausible' { $env:FAKE_VMRUN_EXIT = '0' $env:FAKE_VMRUN_SLEEP = '0' $r = Invoke-VmrunBounded -VmrunPath $script:SlowFakeVmrun -Operation 'list' -TimeoutSeconds 30 $r.ElapsedSeconds | Should -BeGreaterOrEqual 0 $r.ElapsedSeconds | Should -BeLessThan 30 } }