modules/Azure/Discovery/Tests/Integration/StreamingDiscoveryWrite.Tests.ps1
|
BeforeAll { Remove-Module Devolutions.CIEM -Force -ErrorAction SilentlyContinue Import-Module (Join-Path $PSScriptRoot '..' '..' '..' '..' '..' 'Devolutions.CIEM.psd1') function Initialize-StreamingDiscoveryTestDatabase { 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'), (Join-Path $PSScriptRoot '..' '..' '..' '..' 'Devolutions.CIEM.Graph' 'Data' 'graph_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 'Start-CIEMAzureDiscovery streaming writes' { BeforeEach { Remove-Item "$TestDrive/ciem.db" -Force -ErrorAction SilentlyContinue Initialize-StreamingDiscoveryTestDatabase Mock -ModuleName Devolutions.CIEM Write-CIEMLog {} Mock -ModuleName Devolutions.CIEM Write-Progress {} InModuleScope Devolutions.CIEM { $script:AzureAuthContext = [CIEMAzureAuthContext]::new() $script:AzureAuthContext.IsConnected = $true $script:AzureAuthContext.TenantId = 'tenant-1' $script:AzureAuthContext.SubscriptionIds = @('sub-1') $script:AzureAuthContext.ARMToken = 'arm-token' $script:AzureAuthContext.GraphToken = 'graph-token' $script:AzureAuthContext.KeyVaultToken = 'kv-token' $script:AuthContext = @{ Azure = $script:AzureAuthContext } } Mock -ModuleName Devolutions.CIEM Get-CIEMAzureDiscoveryRun { @() } Mock -ModuleName Devolutions.CIEM New-CIEMAzureDiscoveryRun { [pscustomobject]@{ Id = 1; Scope = $Scope; Status = $Status } } Mock -ModuleName Devolutions.CIEM Update-CIEMAzureDiscoveryRun { [pscustomobject]@{ Id = $Id Status = $Status ArmRowCount = $ArmRowCount EntraRowCount = $EntraRowCount WarningCount = $WarningCount ErrorMessage = $ErrorMessage } } Mock -ModuleName Devolutions.CIEM GetCIEMBuiltInRoleDefinitions { @() } Mock -ModuleName Devolutions.CIEM InvokeCIEMGraphNodeBuild { 0 } Mock -ModuleName Devolutions.CIEM InvokeCIEMGraphEdgeBuild { 0 } Mock -ModuleName Devolutions.CIEM InvokeCIEMGraphComputedEdgeBuild { 0 } Mock -ModuleName Devolutions.CIEM InvokeCIEMAzureEffectiveRoleAssignmentBuild { 0 } } It 'Commits ARM rows before Entra collection starts' { $script:armSeenBeforeEntra = $false Mock -ModuleName Devolutions.CIEM InvokeCIEMResourceGraphQuery { @( [pscustomobject]@{ Id = '/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-1' Type = 'microsoft.compute/virtualmachines' Name = 'vm-1' ResourceGroup = 'rg-1' SubscriptionId = 'sub-1' TenantId = 'tenant-1' CollectedAt = '2026-01-01T00:00:00Z' LastSeenAt = 0 } ) } Mock -ModuleName Devolutions.CIEM InvokeCIEMEntraEntityCollection { $count = @(Get-CIEMAzureArmResource).Count if ($count -eq 1) { $script:armSeenBeforeEntra = $true } @( [pscustomobject]@{ Id = 'user-1' Type = 'user' DisplayName = 'User 1' CollectedAt = '2026-01-01T00:00:00Z' LastSeenAt = 0 } ) } Mock -ModuleName Devolutions.CIEM InvokeCIEMEntraPermissionCollection { @() } Mock -ModuleName Devolutions.CIEM InvokeCIEMEntraRelationshipCollection { @() } $run = Start-CIEMAzureDiscovery -Scope All $script:armSeenBeforeEntra | Should -BeTrue $run.Status | Should -Be 'Completed' @(Get-CIEMAzureArmResource) | Should -HaveCount 1 } It 'Keeps committed ARM rows when the Entra phase fails' { Mock -ModuleName Devolutions.CIEM InvokeCIEMResourceGraphQuery { @( [pscustomobject]@{ Id = '/subscriptions/sub-1/resourceGroups/rg-1/providers/Microsoft.Compute/virtualMachines/vm-1' Type = 'microsoft.compute/virtualmachines' Name = 'vm-1' ResourceGroup = 'rg-1' SubscriptionId = 'sub-1' TenantId = 'tenant-1' CollectedAt = '2026-01-01T00:00:00Z' LastSeenAt = 0 } ) } Mock -ModuleName Devolutions.CIEM InvokeCIEMEntraEntityCollection { throw 'entra failed' } Mock -ModuleName Devolutions.CIEM InvokeCIEMEntraPermissionCollection { @() } Mock -ModuleName Devolutions.CIEM InvokeCIEMEntraRelationshipCollection { @() } $run = Start-CIEMAzureDiscovery -Scope All $run.Status | Should -Be 'Partial' @(Get-CIEMAzureArmResource) | Should -HaveCount 1 } } |