diff --git a/azuredevops-pihole-pester-tests.yml b/azuredevops-pihole-pester-tests.yml index 8472474..f38567b 100644 --- a/azuredevops-pihole-pester-tests.yml +++ b/azuredevops-pihole-pester-tests.yml @@ -14,7 +14,9 @@ pool: name: mmadeja-dt variables: - testResultsFile: '$(System.DefaultWorkingDirectory)/TestResults/pester.xml' + - group: dns3 + - name: testResultsFile + value: '$(System.DefaultWorkingDirectory)/TestResults/pester.xml' steps: - pwsh: | @@ -30,15 +32,16 @@ steps: - pwsh: | $configContent = @" - `$PiHoleServer = [uri]'$env:PIHOLE_TEST_SERVER' - `$PiHoleToken = '$env:PIHOLE_TEST_TOKEN' - `$PiHoleIgnoreSsl = `$true + `$PiHoleServer = [uri]'$env:PIHOLE_SERVER' + `$PiHoleToken = '$env:PIHOLE_TOKEN' + `$PiHoleIgnoreSsl = $env:PIHOLE_IGNORE_SSL "@ Set-Content -Path (Join-Path '$(System.DefaultWorkingDirectory)' 'tests/IntegrationConfig.local.ps1') -Value $configContent -Encoding utf8 displayName: 'Write integration test config' env: - PIHOLE_TEST_SERVER: $(PiHoleTestServer) - PIHOLE_TEST_TOKEN: $(PiHoleTestToken) + PIHOLE_SERVER: $(PiHoleServer) + PIHOLE_TOKEN: $(PiHoleToken) + PIHOLE_IGNORE_SSL: $(PiHoleIgnoreSsl) - pwsh: | Import-Module Pester -MinimumVersion 5.0.0 -Force diff --git a/tests/Restart-PiHoleDnsService.Integration.Tests.ps1 b/tests/Restart-PiHoleDnsService.Integration.Tests.ps1 index abeaad9..31da77c 100644 --- a/tests/Restart-PiHoleDnsService.Integration.Tests.ps1 +++ b/tests/Restart-PiHoleDnsService.Integration.Tests.ps1 @@ -34,6 +34,10 @@ Describe 'Restart-PiHoleDnsService (Integration)' -Tag 'Integration' { } It 'returns the raw API response when RawOutput is set' -Skip:(-not $script:ConfigAvailable) { + # The previous test just restarted pihole-FTL; give it a moment to come back up before + # restarting it again, or this occasionally hits a transient connection failure. + Start-Sleep -Seconds 5 + { Restart-PiHoleDnsService -PiHoleServer $script:PiHoleServer -Password $script:PiHoleToken -IgnoreSsl $script:PiHoleIgnoreSsl -RawOutput $true } | Should -Not -Throw } diff --git a/tests/Set-PiHoleDnsBlocking.Tests.ps1 b/tests/Set-PiHoleDnsBlocking.Tests.ps1 index a855059..fedbfb9 100644 --- a/tests/Set-PiHoleDnsBlocking.Tests.ps1 +++ b/tests/Set-PiHoleDnsBlocking.Tests.ps1 @@ -1,68 +1,57 @@ - # Requires -Module Pester Describe 'Set-PiHoleDnsBlocking' { BeforeAll { - Import-Module .\PiHoleShell\PiHoleShell.psm1 - - Mock -CommandName Request-PiHoleAuth -MockWith { return 'mock-sid' } - Mock -CommandName Invoke-RestMethod -MockWith { + Import-Module .\PiHoleShell\PiHoleShell.psm1 -Force + + # Request-PiHoleAuth and Format-PiHoleSecond are internal helpers that aren't exported, and + # every one of these is called from code running inside the module, so all need -ModuleName + # for the mock to actually intercept those internal calls. + Mock -CommandName Request-PiHoleAuth -ModuleName PiHoleShell -MockWith { return 'mock-sid' } + Mock -CommandName Remove-PiHoleCurrentAuthSession -ModuleName PiHoleShell + Mock -CommandName Format-PiHoleSecond -ModuleName PiHoleShell -MockWith { + return @{ TimeInSeconds = 60 } + } + Mock -CommandName Invoke-RestMethod -ModuleName PiHoleShell -MockWith { return @{ blocking = 'false' timer = 60 } } - Mock -CommandName Remove-PiHoleCurrentAuthSession - Mock -CommandName Format-PiHoleSecond -MockWith { - return @{ TimeInSeconds = 60 } - } + # Sample input values $server = [uri]'http://pihole.local' $password = 'mock-password' - $sid = 'mock-session-id' - - # Mock external functions - Mock -CommandName Request-PiHoleAuth -MockWith { 'mock-sid' } - Mock -CommandName Remove-PiHoleCurrentAuthSession - Mock -CommandName Format-PiHoleSecond -MockWith { - return @{ TimeInSeconds = 60 } - } - - # Mock response from API - Mock -CommandName Invoke-RestMethod -MockWith { - return @{ - blocking = 'false' - timer = 60 - } - } } It 'should call Request-PiHoleAuth and send correct POST body' { Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' -TimeInSeconds 60 | Out-Null # Assert internal functions were called correctly - Assert-MockCalled Request-PiHoleAuth -Times 1 -Exactly -Scope It - Assert-MockCalled Invoke-RestMethod -Times 1 -Scope It - Assert-MockCalled Remove-PiHoleCurrentAuthSession -Times 1 -Scope It + Should -Invoke Request-PiHoleAuth -ModuleName PiHoleShell -Times 1 -Exactly -Scope It + Should -Invoke Invoke-RestMethod -ModuleName PiHoleShell -Times 1 -Exactly -Scope It + Should -Invoke Remove-PiHoleCurrentAuthSession -ModuleName PiHoleShell -Times 1 -Exactly -Scope It } It 'should return a formatted PSCustomObject if RawOutput is $false' { $result = Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' -TimeInSeconds 60 - $result | Should -BeOfType 'System.Object[]' - $result[0].Blocking | Should -Be 'false' - $result[0].TimeInSeconds | Should -Be 60 + + $result.Blocking | Should -Be 'false' + $result.TimeInSeconds | Should -Be 60 } It 'should return raw response if RawOutput is $true' { - $result = Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' -TimeInSeconds 60 -RawOutput - $result | Should -HaveProperty 'blocking' - $result | Should -HaveProperty 'timer' + $result = Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' -TimeInSeconds 60 -RawOutput $true + + $result.blocking | Should -Be 'false' + $result.timer | Should -Be 60 } It 'should handle errors and output them' { - # Mock to simulate error - Mock -CommandName Invoke-RestMethod -MockWith { throw "Test error" } -ParameterFilter { $Body -like '*' } + Mock -CommandName Invoke-RestMethod -ModuleName PiHoleShell -MockWith { throw "Test error" } + + Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' -TimeInSeconds 60 -ErrorVariable errOut -ErrorAction SilentlyContinue - { Set-PiHoleDnsBlocking -PiHoleServer $server -Password $password -Blocking 'False' } | - Should -Throw -ErrorMessage 'Test error' + $errOut | Should -Not -BeNullOrEmpty + $errOut[0].Exception.Message | Should -Be 'Test error' } }