modules/Azure/Discovery/Tests/Unit/CIEMAzureDiscoveryRun.Tests.ps1
|
BeforeAll { Remove-Module Devolutions.CIEM -Force -ErrorAction SilentlyContinue Import-Module (Join-Path $PSScriptRoot '..' '..' '..' '..' '..' 'Devolutions.CIEM.psd1') # Create isolated test DB with base + azure + discovery schemas New-CIEMDatabase -Path "$TestDrive/ciem.db" InModuleScope Devolutions.CIEM { $script:DatabasePath = "$TestDrive/ciem.db" } foreach ($schemaPath in @( (Join-Path $PSScriptRoot '..' '..' '..' 'Infrastructure' 'Data' 'azure_schema.sql'), (Join-Path $PSScriptRoot '..' '..' 'Data' 'discovery_schema.sql') )) { foreach ($statement in ((Get-Content $schemaPath -Raw) -split ';\s*\n' | Where-Object { $_.Trim() })) { $trimmed = $statement.Trim() try { Invoke-CIEMQuery -Query $trimmed -AsNonQuery | Out-Null } catch { if ($trimmed -match 'ALTER\s+TABLE' -and $_.Exception.Message -match 'duplicate column') { continue } throw } } } } Describe 'Discovery Run CRUD' { Context 'New-CIEMAzureDiscoveryRun' { BeforeEach { Invoke-CIEMQuery -Query "DELETE FROM azure_discovery_runs" } It 'Creates a run with auto-generated integer Id' { $result = New-CIEMAzureDiscoveryRun -Scope 'All' -Status 'Running' -StartedAt (Get-Date).ToString('o') $result | Should -Not -BeNullOrEmpty $result.Id | Should -BeOfType [int] } It 'Returns CIEMAzureDiscoveryRun with Id > 0' { $result = New-CIEMAzureDiscoveryRun -Scope 'All' -Status 'Running' -StartedAt (Get-Date).ToString('o') $result.Id | Should -BeGreaterThan 0 } It 'Consecutive creates return incrementing Ids' { $r1 = New-CIEMAzureDiscoveryRun -Scope 'All' -Status 'Running' -StartedAt (Get-Date).ToString('o') $r2 = New-CIEMAzureDiscoveryRun -Scope 'ARM' -Status 'Running' -StartedAt (Get-Date).ToString('o') $r2.Id | Should -BeGreaterThan $r1.Id } It 'Accepts optional -PsuJobId' { $result = New-CIEMAzureDiscoveryRun -Scope 'All' -Status 'Running' -StartedAt (Get-Date).ToString('o') -PsuJobId 42 $result.PsuJobId | Should -Be 42 } It 'Accepts -InputObject parameter set' { $obj = InModuleScope Devolutions.CIEM { $o = [CIEMAzureDiscoveryRun]::new() $o.Scope = 'Entra' $o.Status = 'Running' $o.StartedAt = (Get-Date).ToString('o') $o } $result = New-CIEMAzureDiscoveryRun -InputObject $obj $result | Should -Not -BeNullOrEmpty $result.Scope | Should -Be 'Entra' } It 'Mandatory params: -Scope, -Status, -StartedAt' { { New-CIEMAzureDiscoveryRun -Scope 'All' -Status 'Running' -StartedAt (Get-Date).ToString('o') } | Should -Not -Throw # Missing mandatory should throw (ParameterBindingException) { New-CIEMAzureDiscoveryRun -Scope 'All' } | Should -Throw } } Context 'Get-CIEMAzureDiscoveryRun' { BeforeAll { Invoke-CIEMQuery -Query "DELETE FROM azure_discovery_runs" # Seed 3 runs with distinct timestamps for ordering New-CIEMAzureDiscoveryRun -Scope 'All' -Status 'Completed' -StartedAt '2026-01-01T00:00:00Z' New-CIEMAzureDiscoveryRun -Scope 'ARM' -Status 'Failed' -StartedAt '2026-01-02T00:00:00Z' New-CIEMAzureDiscoveryRun -Scope 'Entra' -Status 'Completed' -StartedAt '2026-01-03T00:00:00Z' } It 'Returns CIEMAzureDiscoveryRun typed objects (.GetType().Name -eq CIEMAzureDiscoveryRun)' { $results = Get-CIEMAzureDiscoveryRun $results | ForEach-Object { $_.GetType().Name | Should -Be 'CIEMAzureDiscoveryRun' } } It 'Gets by -Id' { $all = Get-CIEMAzureDiscoveryRun $first = $all | Select-Object -First 1 $result = Get-CIEMAzureDiscoveryRun -Id $first.Id $result | Should -Not -BeNullOrEmpty $result.Id | Should -Be $first.Id } It 'Filters by -Status' { $results = Get-CIEMAzureDiscoveryRun -Status 'Completed' $results | Should -HaveCount 2 } It 'Returns last N runs with -Last parameter' { $results = Get-CIEMAzureDiscoveryRun -Last 2 $results | Should -HaveCount 2 } It '-Last returns newest first (ORDER BY started_at DESC)' { $results = Get-CIEMAzureDiscoveryRun -Last 3 $results[0].StartedAt | Should -Be '2026-01-03T00:00:00Z' $results[2].StartedAt | Should -Be '2026-01-01T00:00:00Z' } } Context 'Update-CIEMAzureDiscoveryRun' { BeforeEach { Invoke-CIEMQuery -Query "DELETE FROM azure_discovery_runs" $script:testRun = New-CIEMAzureDiscoveryRun -Scope 'All' -Status 'Running' -StartedAt '2026-03-01T00:00:00Z' } It 'Updates Status and CompletedAt' { Update-CIEMAzureDiscoveryRun -Id $script:testRun.Id -Status 'Completed' -CompletedAt '2026-03-01T01:00:00Z' $result = Get-CIEMAzureDiscoveryRun -Id $script:testRun.Id $result.Status | Should -Be 'Completed' $result.CompletedAt | Should -Be '2026-03-01T01:00:00Z' } It 'Updates count fields (ArmTypeCount, ArmRowCount, etc.)' { Update-CIEMAzureDiscoveryRun -Id $script:testRun.Id -ArmTypeCount 15 -ArmRowCount 1200 -EntraTypeCount 8 -EntraRowCount 500 $result = Get-CIEMAzureDiscoveryRun -Id $script:testRun.Id $result.ArmTypeCount | Should -Be 15 $result.ArmRowCount | Should -Be 1200 $result.EntraTypeCount | Should -Be 8 $result.EntraRowCount | Should -Be 500 } It 'Partial update preserves unspecified fields' { Update-CIEMAzureDiscoveryRun -Id $script:testRun.Id -Status 'Completed' $result = Get-CIEMAzureDiscoveryRun -Id $script:testRun.Id $result.Scope | Should -Be 'All' $result.StartedAt | Should -Be '2026-03-01T00:00:00Z' } It '-PassThru returns updated object' { $result = Update-CIEMAzureDiscoveryRun -Id $script:testRun.Id -Status 'Failed' -ErrorMessage 'Timeout' -PassThru $result | Should -Not -BeNullOrEmpty $result.GetType().Name | Should -Be 'CIEMAzureDiscoveryRun' $result.Status | Should -Be 'Failed' $result.ErrorMessage | Should -Be 'Timeout' } } Context 'Save-CIEMAzureDiscoveryRun' { BeforeEach { Invoke-CIEMQuery -Query "DELETE FROM azure_discovery_runs" } It 'Inserts new run when Id is 0 (no id yet)' { $obj = InModuleScope Devolutions.CIEM { $o = [CIEMAzureDiscoveryRun]::new() $o.Scope = 'All' $o.Status = 'Running' $o.StartedAt = (Get-Date).ToString('o') $o } Save-CIEMAzureDiscoveryRun -InputObject $obj $results = Get-CIEMAzureDiscoveryRun $results | Should -HaveCount 1 } It 'Updates existing run when Id > 0' { $run = New-CIEMAzureDiscoveryRun -Scope 'All' -Status 'Running' -StartedAt (Get-Date).ToString('o') $run.Status = 'Completed' Save-CIEMAzureDiscoveryRun -InputObject $run $result = Get-CIEMAzureDiscoveryRun -Id $run.Id $result.Status | Should -Be 'Completed' } It 'Accepts -InputObject via pipeline' { $obj = InModuleScope Devolutions.CIEM { $o = [CIEMAzureDiscoveryRun]::new() $o.Scope = 'ARM' $o.Status = 'Running' $o.StartedAt = (Get-Date).ToString('o') $o } $obj | Save-CIEMAzureDiscoveryRun $results = Get-CIEMAzureDiscoveryRun $results | Should -HaveCount 1 } } Context 'Remove-CIEMAzureDiscoveryRun' { BeforeEach { Invoke-CIEMQuery -Query "DELETE FROM azure_discovery_runs" $script:rmRun = New-CIEMAzureDiscoveryRun -Scope 'All' -Status 'Completed' -StartedAt (Get-Date).ToString('o') } It 'Removes by -Id' { Remove-CIEMAzureDiscoveryRun -Id $script:rmRun.Id -Confirm:$false $result = Get-CIEMAzureDiscoveryRun -Id $script:rmRun.Id $result | Should -BeNullOrEmpty } It 'Removes via -InputObject' { $obj = Get-CIEMAzureDiscoveryRun -Id $script:rmRun.Id Remove-CIEMAzureDiscoveryRun -InputObject $obj -Confirm:$false $result = Get-CIEMAzureDiscoveryRun -Id $script:rmRun.Id $result | Should -BeNullOrEmpty } It 'Throws when -All switch is used (safety constraint — discovery runs are audit records)' { { Remove-CIEMAzureDiscoveryRun -All -Confirm:$false } | Should -Throw } } } |