modules/Azure/Discovery/Tests/Unit/CIEMAzureArmHierarchy.Tests.ps1
|
BeforeAll { Remove-Module Devolutions.CIEM -Force -ErrorAction SilentlyContinue Import-Module (Join-Path $PSScriptRoot '..' '..' '..' '..' '..' 'Devolutions.CIEM.psd1') 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 'Get-CIEMAzureArmHierarchy' { Context 'No data' { BeforeAll { Invoke-CIEMQuery -Query "DELETE FROM azure_arm_resources" } It 'Throws terminating error when no ARM resources in DB' { { Get-CIEMAzureArmHierarchy } | Should -Throw } } Context 'Full tree — 2 subscriptions, 3 resource groups, 5 resources' { BeforeAll { Invoke-CIEMQuery -Query "DELETE FROM azure_arm_resources" # Sub1 / RG-A: 2 VMs Save-CIEMAzureArmResource -Id '/subscriptions/sub1/resourceGroups/rg-a/providers/Microsoft.Compute/virtualMachines/vm1' ` -Type 'microsoft.compute/virtualmachines' -Name 'vm1' -ResourceGroup 'rg-a' -SubscriptionId 'sub1' -TenantId 'tenant1' Save-CIEMAzureArmResource -Id '/subscriptions/sub1/resourceGroups/rg-a/providers/Microsoft.Compute/virtualMachines/vm2' ` -Type 'microsoft.compute/virtualmachines' -Name 'vm2' -ResourceGroup 'rg-a' -SubscriptionId 'sub1' -TenantId 'tenant1' # Sub1 / RG-B: 1 NSG Save-CIEMAzureArmResource -Id '/subscriptions/sub1/resourceGroups/rg-b/providers/Microsoft.Network/networkSecurityGroups/nsg1' ` -Type 'microsoft.network/networksecuritygroups' -Name 'nsg1' -ResourceGroup 'rg-b' -SubscriptionId 'sub1' -TenantId 'tenant1' # Sub2 / RG-C: 2 storage accounts Save-CIEMAzureArmResource -Id '/subscriptions/sub2/resourceGroups/rg-c/providers/Microsoft.Storage/storageAccounts/sa1' ` -Type 'microsoft.storage/storageaccounts' -Name 'sa1' -ResourceGroup 'rg-c' -SubscriptionId 'sub2' -TenantId 'tenant1' Save-CIEMAzureArmResource -Id '/subscriptions/sub2/resourceGroups/rg-c/providers/Microsoft.Storage/storageAccounts/sa2' ` -Type 'microsoft.storage/storageaccounts' -Name 'sa2' -ResourceGroup 'rg-c' -SubscriptionId 'sub2' -TenantId 'tenant1' } It 'Returns PSCustomObject array' { $result = Get-CIEMAzureArmHierarchy $result | Should -Not -BeNullOrEmpty $result[0] | Should -BeOfType [PSCustomObject] } It 'Contains exactly one Tenant node at Depth 0' { $result = Get-CIEMAzureArmHierarchy $tenants = $result | Where-Object { $_.NodeType -eq 'Tenant' } $tenants | Should -HaveCount 1 $tenants[0].Depth | Should -Be 0 } It 'Contains exactly 2 Subscription nodes at Depth 1' { $result = Get-CIEMAzureArmHierarchy $subs = $result | Where-Object { $_.NodeType -eq 'Subscription' } $subs | Should -HaveCount 2 $subs | ForEach-Object { $_.Depth | Should -Be 1 } } It 'Contains exactly 3 ResourceGroup nodes at Depth 3' { $result = Get-CIEMAzureArmHierarchy $rgs = $result | Where-Object { $_.NodeType -eq 'ResourceGroup' } $rgs | Should -HaveCount 3 $rgs | ForEach-Object { $_.Depth | Should -Be 3 } } It 'Contains exactly 5 Resource nodes at Depth 5' { $result = Get-CIEMAzureArmHierarchy $resources = $result | Where-Object { $_.NodeType -eq 'Resource' } $resources | Should -HaveCount 5 $resources | ForEach-Object { $_.Depth | Should -Be 5 } } It 'Populates .Resource on leaf nodes with CIEMAzureArmResource objects' { $result = Get-CIEMAzureArmHierarchy $leafNodes = $result | Where-Object { $_.NodeType -eq 'Resource' } foreach ($node in $leafNodes) { $node.Resource | Should -Not -BeNullOrEmpty $node.Resource.GetType().Name | Should -Be 'CIEMAzureArmResource' } } It 'Resource property is null on non-leaf nodes (Tenant, Subscription, ResourceGroup)' { $result = Get-CIEMAzureArmHierarchy $nonLeaf = $result | Where-Object { $_.NodeType -ne 'Resource' } foreach ($node in $nonLeaf) { $node.Resource | Should -BeNullOrEmpty } } It 'All non-root nodes have Relationship = CONTAINS' { $result = Get-CIEMAzureArmHierarchy $nonRoot = $result | Where-Object { $_.NodeType -ne 'Tenant' } foreach ($node in $nonRoot) { $node.Relationship | Should -Be 'CONTAINS' } } It 'Root Tenant node has null Relationship' { $result = Get-CIEMAzureArmHierarchy $tenant = $result | Where-Object { $_.NodeType -eq 'Tenant' } $tenant.Relationship | Should -BeNullOrEmpty } It 'Each node has a non-empty Label' { $result = Get-CIEMAzureArmHierarchy foreach ($node in $result) { $node.Label | Should -Not -BeNullOrEmpty } } It 'No duplicate NodeIds' { $result = Get-CIEMAzureArmHierarchy $ids = $result | Select-Object -ExpandProperty NodeId ($ids | Select-Object -Unique).Count | Should -Be $ids.Count } It 'Each non-root node has a non-empty ParentNodeId' { $result = Get-CIEMAzureArmHierarchy $nonRoot = $result | Where-Object { $_.NodeType -ne 'Tenant' } foreach ($node in $nonRoot) { $node.ParentNodeId | Should -Not -BeNullOrEmpty } } } Context '-SubscriptionId filter' { BeforeAll { Invoke-CIEMQuery -Query "DELETE FROM azure_arm_resources" Save-CIEMAzureArmResource -Id '/subscriptions/subA/resourceGroups/rg1/providers/Microsoft.Compute/virtualMachines/vm1' ` -Type 'microsoft.compute/virtualmachines' -Name 'vm1' -ResourceGroup 'rg1' -SubscriptionId 'subA' -TenantId 'tenant1' Save-CIEMAzureArmResource -Id '/subscriptions/subB/resourceGroups/rg2/providers/Microsoft.Compute/virtualMachines/vm2' ` -Type 'microsoft.compute/virtualmachines' -Name 'vm2' -ResourceGroup 'rg2' -SubscriptionId 'subB' -TenantId 'tenant1' } It 'Scopes tree to one subscription when -SubscriptionId is specified' { $result = Get-CIEMAzureArmHierarchy -SubscriptionId 'subA' $subs = $result | Where-Object { $_.NodeType -eq 'Subscription' } $subs | Should -HaveCount 1 $subs[0].Label | Should -Be 'subA' } It 'Only returns resource nodes belonging to the specified subscription' { $result = Get-CIEMAzureArmHierarchy -SubscriptionId 'subA' $resources = $result | Where-Object { $_.NodeType -eq 'Resource' } $resources | Should -HaveCount 1 $resources[0].Resource.Name | Should -Be 'vm1' } } } |