Tests/Unit/Private/Invoke-SCARequest.Tests.ps1
|
Import-Module (Join-Path $PSScriptRoot '../../../psSCA.psd1') -Force Describe 'Invoke-SCARequest' { InModuleScope psSCA { BeforeEach { $script:SCASessions = [ordered]@{ Default = [pscustomobject]@{ PSTypeName = 'psSCA.Session' Name = 'Default' TenantSubdomain = 'contoso' # PSScriptAnalyzer disable-next-line PSAvoidUsingConvertToSecureStringWithPlainText AccessToken = (ConvertTo-SecureString -String 'the-real-token' -AsPlainText -Force) ExpiresAt = [DateTime]::UtcNow.AddMinutes(10) } } $script:SCACurrentSessionName = 'Default' Mock Start-Sleep { } } It 'calls the resolved URI with a Bearer authorization header and returns the parsed body' { Mock Invoke-WebRequest { [pscustomobject]@{ Content = '{"id":"1"}'; StatusCode = 200 } } $result = Invoke-SCARequest -Service 'SCA' -Method GET -Path '/access/sessions' -Operation 'Test' $result.id | Should -Be '1' Should -Invoke Invoke-WebRequest -ParameterFilter { $Uri -eq 'https://contoso.sca.cyberark.cloud/api/access/sessions' -and $Headers.Authorization -eq 'Bearer the-real-token' -and $Method -eq 'GET' } } It 'serializes -Body to JSON and sets Content-Type' { Mock Invoke-WebRequest { [pscustomobject]@{ Content = '{"ok":true}'; StatusCode = 200 } } Invoke-SCARequest -Service 'UAR' -Method POST -Path '/workflows/requests' -Body @{ reason = 'test' } -Operation 'Test' | Out-Null Should -Invoke Invoke-WebRequest -ParameterFilter { $Body -eq '{"reason":"test"}' -and $Headers.'Content-Type' -eq 'application/json' } } It 'retries a GET request on a 503 and succeeds on the next attempt' { $script:callCount = 0 Mock Invoke-WebRequest { $script:callCount++ if ($script:callCount -eq 1) { $exception = [Microsoft.PowerShell.Commands.HttpResponseException]::new( 'Service Unavailable', [System.Net.Http.HttpResponseMessage]::new([System.Net.HttpStatusCode]::ServiceUnavailable)) throw $exception } [pscustomobject]@{ Content = '{"id":"1"}'; StatusCode = 200 } } $result = Invoke-SCARequest -Service 'SCA' -Method GET -Path '/access/sessions' -Operation 'Test' $result.id | Should -Be '1' Should -Invoke Invoke-WebRequest -Times 2 -Exactly Should -Invoke Start-Sleep -Times 1 -Exactly } It 'does not retry a non-idempotent POST on a 503' { Mock Invoke-WebRequest { $exception = [Microsoft.PowerShell.Commands.HttpResponseException]::new( 'Service Unavailable', [System.Net.Http.HttpResponseMessage]::new([System.Net.HttpStatusCode]::ServiceUnavailable)) throw $exception } { Invoke-SCARequest -Service 'UAR' -Method POST -Path '/workflows/requests' -Body @{ x = 1 } -Operation 'Test' } | Should -Throw Should -Invoke Invoke-WebRequest -Times 1 -Exactly Should -Invoke Start-Sleep -Times 0 -Exactly } It 'retries an -Idempotent POST on a 429' { $script:callCount = 0 Mock Invoke-WebRequest { $script:callCount++ if ($script:callCount -eq 1) { $exception = [Microsoft.PowerShell.Commands.HttpResponseException]::new( 'Too Many Requests', [System.Net.Http.HttpResponseMessage]::new([System.Net.HttpStatusCode]::TooManyRequests)) throw $exception } [pscustomobject]@{ Content = '{"items":[]}'; StatusCode = 200 } } Invoke-SCARequest -Service 'CDS' -Method POST -Path '/detections/cloud-service-entitlements/list' -Body @{} -Operation 'Test' -Idempotent | Out-Null Should -Invoke Invoke-WebRequest -Times 2 -Exactly } It 'never writes the plaintext access token to the verbose stream' { Mock Invoke-WebRequest { [pscustomobject]@{ Content = '{"id":"1"}'; StatusCode = 200 } } $verboseOutput = Invoke-SCARequest -Service 'SCA' -Method GET -Path '/access/sessions' -Operation 'Test' -Verbose 4>&1 | Where-Object { $_ -is [System.Management.Automation.VerboseRecord] } ($verboseOutput -join "`n") | Should -Not -Match 'the-real-token' } It 'warns when the response indicates additional pages are available' { Mock Invoke-WebRequest { [pscustomobject]@{ Content = '{"items":[],"nextPageToken":"abc"}'; StatusCode = 200 } } Invoke-SCARequest -Service 'CDS' -Method GET -Path '/detections/cloud-service-entitlements/list' -Operation 'Test' -WarningVariable warnOut -WarningAction SilentlyContinue | Out-Null $warnOut | Should -Not -BeNullOrEmpty } } } |