tests/New-QAFrameworkExecutionPlan.Tests.ps1
|
BeforeAll { $script:ModuleRoot = Split-Path -Parent $PSScriptRoot Import-Module (Join-Path $script:ModuleRoot 'Skyline.DataMiner.QAOps.PipelineLibrary.psd1') -Force function New-PlanTest { param([hashtable]$Override = @{}) $test = @{ name = 'RT_Sample' fixture = 'Standard' diagnosticRunType = $null failover = $null weight = 1 canRunConcurrently = $true targetDma = 'One' } foreach ($key in $Override.Keys) { $test[$key] = $Override[$key] } return [pscustomobject]$test } function New-Agent { param([string]$BridgeId, [int]$DmaId, [bool]$IsFailover = $false, [string]$Partner = $null) return [pscustomobject]@{ BridgeId = $BridgeId Name = $BridgeId DmaId = $DmaId IsFailover = $IsFailover FailoverPartnerBridgeId = $Partner HasDataMiner = $true } } function New-PlanTopology { param([object[]]$Agents, [object[]]$Pairs = @()) return [pscustomobject]@{ Name = 'cluster' Agents = [object[]]$Agents FailoverPairs = [object[]]$Pairs HasFailover = ($Pairs.Count -gt 0) LowestDmaId = ($Agents | Sort-Object DmaId | Select-Object -First 1).DmaId HighestDmaId = ($Agents | Sort-Object DmaId | Select-Object -Last 1).DmaId DataMinerVersion = $null DbmsType = '' IsCentralized = $false IsRedGreen = $false Labels = @{} SolutionVersions = @{} IsClusterKnown = $true } } function New-PlanConfiguration { param([hashtable]$Override = @{}) $config = @{ preRunFilter = 'all' includeNonConcurrent = $true disableFailoverRun = $false agentCapacity = 3 } foreach ($key in $Override.Keys) { $config[$key] = $Override[$key] } return [pscustomobject]$config } $script:ThreeAgents = @( (New-Agent -BridgeId 'b1' -DmaId 10), (New-Agent -BridgeId 'b2' -DmaId 5), (New-Agent -BridgeId 'b3' -DmaId 20) ) } Describe 'New-QAFrameworkExecutionPlan' { Context 'phase assignment' { It 'puts a standard test in the main phase' { $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest) $plan.WorkItems.Count | Should -Be 1 $plan.WorkItems[0].Phase | Should -Be 'Main' $plan.Phases | Should -Be @('Main') } It 'puts a non-concurrent test in its own phase' { $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ canRunConcurrently = $false }) $plan.WorkItems[0].Phase | Should -Be 'NonConcurrent' } It 'skips non-concurrent tests when the run excludes them' { $config = New-PlanConfiguration @{ includeNonConcurrent = $false } $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ canRunConcurrently = $false }) -Configuration $config $plan.WorkItems.Count | Should -Be 0 $plan.Skipped[0].Reason | Should -BeLike '*cannot run concurrently*' } It 'runs a BeforeAndAfter diagnostic test twice' { $test = New-PlanTest @{ fixture = 'Diagnostic'; diagnosticRunType = 'BeforeAndAfter' } $plan = New-QAFrameworkExecutionPlan -Test $test $plan.WorkItems.Phase | Should -Be @('DiagnosticsBefore', 'DiagnosticsAfter') } It 'runs an After diagnostic test only afterwards' { $test = New-PlanTest @{ fixture = 'Diagnostic'; diagnosticRunType = 'After' } (New-QAFrameworkExecutionPlan -Test $test).WorkItems.Phase | Should -Be 'DiagnosticsAfter' } It 'orders the phases the way the legacy runner does' { $tests = @( (New-PlanTest @{ name = 'RT_Main' }), (New-PlanTest @{ name = 'RT_Diag'; fixture = 'Diagnostic'; diagnosticRunType = 'BeforeAndAfter' }), (New-PlanTest @{ name = 'RT_Pre'; fixture = 'PreRun' }), (New-PlanTest @{ name = 'RT_Serial'; canRunConcurrently = $false }) ) $plan = New-QAFrameworkExecutionPlan -Test $tests $plan.Phases | Should -Be @('PreRun', 'DiagnosticsBefore', 'Main', 'NonConcurrent', 'DiagnosticsAfter') } } Context 'pre-run filter' { It 'schedules every pre-run test for all' { $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ fixture = 'PreRun' }) -Configuration (New-PlanConfiguration) $plan.WorkItems.Count | Should -Be 1 } It 'schedules no pre-run test for none' { $config = New-PlanConfiguration @{ preRunFilter = 'none' } $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ fixture = 'PreRun' }) -Configuration $config $plan.WorkItems.Count | Should -Be 0 $plan.Skipped[0].Reason | Should -BeLike '*pre-run filter*' } It 'treats any other value as a regular expression' { $tests = @( (New-PlanTest @{ name = 'RT_PreRun_Upgrade'; fixture = 'PreRun' }), (New-PlanTest @{ name = 'RT_PreRun_Licenses'; fixture = 'PreRun' }) ) $config = New-PlanConfiguration @{ preRunFilter = 'Upgrade' } $plan = New-QAFrameworkExecutionPlan -Test $tests -Configuration $config $plan.WorkItems.Count | Should -Be 1 $plan.WorkItems[0].Name | Should -Be 'RT_PreRun_Upgrade' } } Context 'TargetDMA expansion' { It 'leaves TargetDMA One unpinned' { $topology = New-PlanTopology -Agents $script:ThreeAgents $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest) -Topology $topology $plan.WorkItems.Count | Should -Be 1 $plan.WorkItems[0].TargetBridgeId | Should -BeNullOrEmpty } It 'clones a TargetDMA All test once per agent' { $topology = New-PlanTopology -Agents $script:ThreeAgents $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ targetDma = 'All' }) -Topology $topology $plan.WorkItems.Count | Should -Be 3 ($plan.WorkItems.TargetBridgeId | Sort-Object) | Should -Be @('b1', 'b2', 'b3') ($plan.WorkItems.Id | Select-Object -Unique).Count | Should -Be 3 } It 'pins LowestDMAID to the agent with the lowest DmaId' { $topology = New-PlanTopology -Agents $script:ThreeAgents $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ targetDma = 'LowestDMAID' }) -Topology $topology $plan.WorkItems.Count | Should -Be 1 $plan.WorkItems[0].TargetBridgeId | Should -Be 'b2' $plan.WorkItems[0].TargetDmaId | Should -Be 5 } It 'pins HighestDMAID to the agent with the highest DmaId' { $topology = New-PlanTopology -Agents $script:ThreeAgents $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ targetDma = 'HighestDMAID' }) -Topology $topology $plan.WorkItems[0].TargetBridgeId | Should -Be 'b3' } It 'clones AllFailovers over the failover agents only' { $agents = @( (New-Agent -BridgeId 'b1' -DmaId 1 -IsFailover $true -Partner 'b2'), (New-Agent -BridgeId 'b2' -DmaId 2 -IsFailover $true -Partner 'b1'), (New-Agent -BridgeId 'b3' -DmaId 3) ) $pairs = @([pscustomobject]@{ PairId = 'b1|b2'; Primary = $agents[0]; Partner = $agents[1] }) $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ targetDma = 'AllFailovers' }) -Topology (New-PlanTopology -Agents $agents -Pairs $pairs) ($plan.WorkItems.TargetBridgeId | Sort-Object) | Should -Be @('b1', 'b2') } It 'skips an AllFailovers test when the cluster has no failover agents' { $topology = New-PlanTopology -Agents $script:ThreeAgents $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ targetDma = 'AllFailovers' }) -Topology $topology $plan.WorkItems.Count | Should -Be 0 $plan.Skipped[0].Reason | Should -BeLike '*no failover agents*' } It 'falls back to any agent when the topology is unknown' { $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ targetDma = 'All' }) $plan.WorkItems.Count | Should -Be 1 $plan.WorkItems[0].TargetBridgeId | Should -BeNullOrEmpty } } Context 'failover phases' { BeforeAll { $script:FailoverAgents = @( (New-Agent -BridgeId 'f1' -DmaId 1 -IsFailover $true -Partner 'f2'), (New-Agent -BridgeId 'f2' -DmaId 2 -IsFailover $true -Partner 'f1') ) $script:FailoverPairs = @([pscustomobject]@{ PairId = 'f1|f2'; Primary = $script:FailoverAgents[0]; Partner = $script:FailoverAgents[1] }) $script:FailoverTest = New-PlanTest @{ name = 'RT_Failover' fixture = 'Failover' failover = [pscustomobject]@{ runDirectBeforeSwitch = $true runDirectAfterSwitch = $false runOnNonFailoverSystems = $false hasBeforeSwitch = $true hasAfterSwitch = $true hasAfterSwitchBack = $true } } } It 'creates one work item per failover state' { $topology = New-PlanTopology -Agents $script:FailoverAgents -Pairs $script:FailoverPairs $plan = New-QAFrameworkExecutionPlan -Test $script:FailoverTest -Topology $topology $plan.Phases | Should -Be @('Main', 'FailoverDirectBeforeSwitch', 'FailoverAfterSwitch', 'FailoverAfterSwitchBack') } It 'pins failover phase work items to failover agents' { $agents = $script:FailoverAgents + (New-Agent -BridgeId 'b9' -DmaId 9) $topology = New-PlanTopology -Agents $agents -Pairs $script:FailoverPairs $plan = New-QAFrameworkExecutionPlan -Test $script:FailoverTest -Topology $topology $failoverItems = @($plan.WorkItems | Where-Object { $_.Phase -like 'Failover*' }) $failoverItems.Count | Should -BeGreaterThan 0 $failoverItems.TargetBridgeId | Should -Not -Contain 'b9' } It 'creates no failover phases when the cluster has no pairs' { $plan = New-QAFrameworkExecutionPlan -Test $script:FailoverTest -Topology (New-PlanTopology -Agents $script:ThreeAgents) $plan.Phases | Should -Be @('Main') } It 'creates no failover phases when the run configuration disables them' { $topology = New-PlanTopology -Agents $script:FailoverAgents -Pairs $script:FailoverPairs $config = New-PlanConfiguration @{ disableFailoverRun = $true } $plan = New-QAFrameworkExecutionPlan -Test $script:FailoverTest -Topology $topology -Configuration $config $plan.Phases | Should -Be @('Main') } } Context 'work item shape' { It 'clamps the weight to the agent capacity' { $config = New-PlanConfiguration @{ agentCapacity = 2 } $plan = New-QAFrameworkExecutionPlan -Test (New-PlanTest @{ weight = 3 }) -Configuration $config $plan.WorkItems[0].Weight | Should -Be 2 } It 'starts every work item as pending' { $item = (New-QAFrameworkExecutionPlan -Test (New-PlanTest)).WorkItems[0] $item.State | Should -Be 'Pending' $item.Outcome | Should -BeNullOrEmpty $item.Attempt | Should -Be 0 $item.Test.name | Should -Be 'RT_Sample' } It 'accepts input from the pipeline' { $tests = @((New-PlanTest @{ name = 'RT_A' }), (New-PlanTest @{ name = 'RT_B' })) ($tests | New-QAFrameworkExecutionPlan).WorkItems.Count | Should -Be 2 } It 'returns an empty plan for an empty input' { $plan = New-QAFrameworkExecutionPlan -Test @() $plan.WorkItems.Count | Should -Be 0 $plan.Phases.Count | Should -Be 0 } } } |