Testing/Unit/PowerShell/Orchestrator/Invoke-CyberConfig.Tests.ps1

using module '..\..\..\..\Modules\CyberConfig\CyberConfig.psm1'
BeforeDiscovery {
    $ModuleRootPath = Join-Path -Path $PSScriptRoot -ChildPath '..\..\..\..\Modules'
    
    # Import the branch version of Orchestrator
    Import-Module (Join-Path -Path $ModuleRootPath -ChildPath 'Orchestrator.psm1') -Force
}

InModuleScope Orchestrator {
    BeforeAll {
        # Set up all mocks ONCE for all tests
        $script:TestSplat = @{}
        
        # Define stub functions that will be mocked
        function ConvertTo-ResultsCsv {throw 'this will be mocked'}
        function Disconnect-CyberAssessmentTenant {throw 'this will be mocked'}
        
        Mock -ModuleName Orchestrator Remove-Resources {}
        Mock -ModuleName Orchestrator Import-Resources {}
        Mock -ModuleName Orchestrator Invoke-Connection {
            if ($CyberConfig) { $script:TestSplat['LogIn'] = $CyberConfig.LogIn }
        }
        Mock -ModuleName Orchestrator Get-TenantDetail { '{"DisplayName": "displayName"}' }
        Mock -ModuleName Orchestrator Invoke-ProviderList {
            if ($CyberConfig) {
                $script:TestSplat['AppID'] = $CyberConfig.AppID
                $script:TestSplat['Organization'] = $CyberConfig.Organization
                $script:TestSplat['CertificateThumbprint'] = $CyberConfig.CertificateThumbprint
            }
        }
        Mock -ModuleName Orchestrator Invoke-RunRego {
            if ($CyberConfig) {
                $script:TestSplat['OPAPath'] = $CyberConfig.OPAPath
                $script:TestSplat['OutProviderFileName'] = $CyberConfig.OutProviderFileName
                $script:TestSplat['OutRegoFileName'] = $CyberConfig.OutRegoFileName
            }
        }
        Mock -ModuleName Orchestrator Invoke-ReportCreation {
            if ($CyberConfig) {
                $script:TestSplat['ProductNames'] = $CyberConfig.ProductNames
                $script:TestSplat['M365Environment'] = $CyberConfig.M365Environment
                $script:TestSplat['OutPath'] = $CyberConfig.OutPath
                $script:TestSplat['OutFolderName'] = $CyberConfig.OutFolderName
                $script:TestSplat['OutReportName'] = $CyberConfig.OutReportName
            }
        }
        Mock -ModuleName Orchestrator Merge-JsonOutput {
            if ($CyberConfig) { $script:TestSplat['OutJsonFileName'] = $CyberConfig.OutJsonFileName }
        }
        Mock -ModuleName Orchestrator ConvertTo-ResultsCsv {}
        Mock -ModuleName Orchestrator Disconnect-CyberAssessmentTenant {
            if ($CyberConfig) { $script:TestSplat['DisconnectOnExit'] = $CyberConfig.DisconnectOnExit }
        }
        Mock -CommandName New-Item {}
        Mock -CommandName Copy-Item {}
    }

    Context  "Parameter override test"{

        Describe -Tag 'Orchestrator' -Name 'Invoke-Cyber config with no command line override' {
            BeforeAll {
                # Reset TestSplat for this test
                $script:TestSplat = @{}
                
                function global:ConvertFrom-Yaml {
                    @{
                        ProductNames=@("teams")
                        M365Environment='commercial'
                        OPAPath=$PSScriptRoot
                        LogIn=$true
                        DisconnectOnExit=$false
                        OutPath=$PSScriptRoot
                        OutFolderName='CyberReports'
                        OutProviderFileName='ProviderSettingsExport'
                        OutRegoFileName='TestResults'
                        OutReportName='BaselineReports'
                        OutJsonFileName='CyberResults'
                        Organization='sub.domain.com'
                        AppID='12345678-1234-1234-1234-123456789012'
                        CertificateThumbprint='1234567890ABCDEF1234567890ABCDEF12345678'
                    }
                }
                Invoke-CyberAssessment -ConfigFilePath (Join-Path -Path $PSScriptRoot -ChildPath "orchestrator_config_test.yaml")
            }

            It "Verify parameter ""<parameter>"" with value ""<value>""" -ForEach @(
                @{ Parameter = "M365Environment";       Value = "commercial"           },
                @{ Parameter = "ProductNames";          Value = @("teams")             },
                @{ Parameter = "LogIn";                 Value = $true                  },
                @{ Parameter = "OutFolderName";         Value = "CyberReports"         },
                @{ Parameter = "OutProviderFileName";   Value = "ProviderSettingsExport" },
                @{ Parameter = "OutRegoFileName";       Value = "TestResults"          },
                @{ Parameter = "OutReportName";         Value = "BaselineReports"      },
                @{ Parameter = "OutJsonFileName";       Value = "CyberResults"         },
                @{ Parameter = "Organization";          Value = "sub.domain.com"       },
                @{ Parameter = "AppID";                 Value = "12345678-1234-1234-1234-123456789012"  },
                @{ Parameter = "CertificateThumbprint"; Value = "1234567890ABCDEF1234567890ABCDEF12345678"  }
                ){
                    $script:TestSplat[$Parameter] | Should -BeExactly $Value -Because "got $($script:TestSplat[$Parameter])"
            }
        }
        
        Describe -Tag 'Orchestrator' -Name 'Invoke-Cyber with command line ProductNames wild card override' {
            BeforeAll {
                # Reset TestSplat for this test
                $script:TestSplat = @{}
                
                function global:ConvertFrom-Yaml {
                    @{
                        ProductNames=@("teams")
                        M365Environment='commercial'
                        OPAPath=$PSScriptRoot
                        LogIn=$true
                        DisconnectOnExit=$false
                        OutPath=$PSScriptRoot
                        OutFolderName='CyberReports'
                        OutProviderFileName='ProviderSettingsExport'
                        OutRegoFileName='TestResults'
                        OutReportName='BaselineReports'
                        OutJsonFileName='CyberResults'
                        Organization='sub.domain.com'
                        AppID='12345678-1234-1234-1234-123456789012'
                        CertificateThumbprint='1234567890ABCDEF1234567890ABCDEF12345678'
                    }
                }
                Invoke-CyberAssessment `
                  -ProductNames "*" `
                  -ConfigFilePath (Join-Path -Path $PSScriptRoot -ChildPath "orchestrator_config_test.yaml")
            }

            It "Verify parameter, ProductNames, with wildcard CLI override"{
                $script:TestSplat['ProductNames'] | Should -BeExactly @('aad', 'defender', 'exo', 'powerplatform', 'sharepoint', 'teams') -Because "got $($script:TestSplat['ProductNames'])"
            }
        }

        Describe -Tag 'Orchestrator' -Name 'Invoke-Cyber with config file ProductNames wild card' {
            BeforeAll {
                # Reset TestSplat for this test
                $script:TestSplat = @{}
                
                function global:ConvertFrom-Yaml {
                    @{
                        ProductNames=@('aad', 'defender', 'exo', 'powerplatform', 'sharepoint', 'teams')
                        M365Environment='commercial'
                        OPAPath=$PSScriptRoot
                        Login=$true
                        OutPath=$PSScriptRoot
                        OutFolderName='CyberReports'
                        OutProviderFileName='TenantSettingsExport'
                        OutRegoFileName='CyberTestResults'
                        OutReportName='CyberReports'
                        Organization='sub.domain.com'
                        AppID='12345678-1234-1234-1234-123456789012'
                        CertificateThumbprint='1234567890ABCDEF1234567890ABCDEF12345678'
                    }
                }
                Invoke-CyberAssessment `
                  -ConfigFilePath (Join-Path -Path $PSScriptRoot -ChildPath "product_wildcard_config_test.yaml")
            }

            It "Verify parameter, ProductNames, reflects all products"{
                $script:TestSplat['ProductNames'] | Should -BeExactly @('aad', 'defender', 'exo', 'powerplatform', 'sharepoint', 'teams') -Because "got $($script:TestSplat['ProductNames'])"
            }
        }
    }
}
AfterAll {
    Remove-Module Orchestrator -ErrorAction SilentlyContinue
}