tests/Collect.ApiResources.Tests.ps1
|
#Requires -Version 7.0 #Requires -Modules Pester <# Pester tests for src/collect/Get-ScoutApiResources.ps1 (AB#5639/5645, Epic AB#5638). Get-AzAccessToken / Invoke-RestMethod are mocked throughout -- no live Azure connection is made, and no real bearer token is ever produced or logged. #> BeforeAll { $root = Split-Path $PSScriptRoot -Parent . "$root/src/collect/Get-ScoutApiResources.ps1" # The real function is deliberately polite to ARM (Start-Sleep between calls) -- no need # to actually wait in a unit test. function Start-Sleep { param([Parameter(ValueFromRemainingArguments)] $Rest) } function Get-AzAccessToken { param([Parameter(ValueFromRemainingArguments)] $Rest) [pscustomobject]@{ Token = (ConvertTo-SecureString -String 'fake-token' -AsPlainText -Force) } } $script:subs = @( [pscustomobject]@{ id = 'sub-1'; name = 'sub-one' } [pscustomobject]@{ id = 'sub-2'; name = 'sub-two' } ) } Describe 'Get-ScoutApiResources -- happy path' { It 'returns one row per subscription with every field populated' { function Invoke-RestMethod { param([string] $Uri, [hashtable] $Headers, [string] $Method) if ($Uri -match 'ResourceHealth') { return [pscustomobject]@{ value = @('health-event') } } if ($Uri -match 'ManagedIdentity') { return [pscustomobject]@{ value = @('identity-1') } } if ($Uri -match 'advisorScore') { return [pscustomobject]@{ value = @('score-1') } } if ($Uri -match 'reservationRecommendations') { return [pscustomobject]@{ value = @('reservation-1') } } if ($Uri -match 'policyStates') { return [pscustomobject]@{ value = @('policy-state-1') } } if ($Uri -match 'policySetDefinitions') { return [pscustomobject]@{ value = @('set-def-1') } } if ($Uri -match 'policyDefinitions') { return [pscustomobject]@{ value = @('def-1') } } return [pscustomobject]@{ value = @() } } $result = @(Get-ScoutApiResources -Subscriptions $script:subs) $result.Count | Should -Be 2 $result[0].Subscription | Should -Be 'sub-1' $result[0].ResourceHealth | Should -Be @('health-event') $result[0].ManagedIdentities | Should -Be @('identity-1') $result[0].AdvisorScore | Should -Be @('score-1') $result[0].ReservationRecommendations | Should -Be @('reservation-1') $result[0].PolicyAssignments | Should -Be @('policy-state-1') } } Describe 'Get-ScoutApiResources -- per-call resilience' { It 'degrades only the failing field to $null and keeps every other field and every other subscription' { function Invoke-RestMethod { param([string] $Uri, [hashtable] $Headers, [string] $Method) if ($Uri -match 'ManagedIdentity') { throw 'AuthorizationFailed' } return [pscustomobject]@{ value = @('ok') } } $result = @(Get-ScoutApiResources -Subscriptions $script:subs) $result.Count | Should -Be 2 $result[0].ManagedIdentities | Should -BeNullOrEmpty $result[0].ResourceHealth | Should -Be @('ok') $result[1].ManagedIdentities | Should -BeNullOrEmpty $result[1].ResourceHealth | Should -Be @('ok') } It 'does not throw and returns an empty result when the access token cannot be acquired' { function Get-AzAccessToken { throw 'no context' } { Get-ScoutApiResources -Subscriptions $script:subs -WarningAction SilentlyContinue } | Should -Not -Throw @(Get-ScoutApiResources -Subscriptions $script:subs -WarningAction SilentlyContinue).Count | Should -Be 0 } } Describe 'Get-ScoutApiResources -- SkipPolicy' { It 'skips all three policy calls when -SkipPolicy is supplied' { $script:policyCalls = 0 function Invoke-RestMethod { param([string] $Uri, [hashtable] $Headers, [string] $Method) if ($Uri -match 'policy' -or $Uri -match 'Policy') { $script:policyCalls++ } return [pscustomobject]@{ value = @() } } Get-ScoutApiResources -Subscriptions $script:subs -SkipPolicy | Out-Null $script:policyCalls | Should -Be 0 } } |