Testing/Unit/PowerShell/Support/Test-CyberAssessmentVersion.Tests.ps1
|
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath '../../../../Modules/Support') InModuleScope 'Support' { Describe "Test-CyberAssessmentVersion" { BeforeAll { # Load the RequiredVersions.ps1 file $RequiredVersionsPath = Join-Path -Path $PSScriptRoot -ChildPath "..\..\..\..\RequiredVersions.ps1" if (Test-Path -Path $RequiredVersionsPath) { . $RequiredVersionsPath # Load the CyberAssessment module list to reference later $script:CyberAssessmentModuleList = $ModuleList } else { throw "Could not find RequiredVersions.ps1 at expected path: $RequiredVersionsPath" } # Load the CyberAssessment version from the manifest $ManifestPath = Join-Path -Path $PSScriptRoot -ChildPath "..\..\..\..\CyberAssessment.psd1" if (Test-Path -Path $ManifestPath) { $manifestData = Import-PowerShellDataFile -Path $ManifestPath $script:CurrentCyberAssessmentVersion = [version]$manifestData.ModuleVersion } else { throw "Could not find CyberAssessment.psd1 at expected path: $ManifestPath" } # for GitHub container if (-not (Get-Command -Name 'Get-DependencyStatus' -ErrorAction SilentlyContinue)) { function script:Get-DependencyStatus { } } $script:MockDependencyModules = @{} foreach ($module in $script:CyberAssessmentModuleList) { # Create a mock version that's within the acceptable range $mockVersion = $module.ModuleVersion if ($mockVersion -lt $module.MaximumVersion) { # Use a version slightly higher than minimum but within range $mockVersion = [version]"$($module.ModuleVersion.Major).$($module.ModuleVersion.Minor + 1).0" } $script:MockDependencyModules[$module.ModuleName] = @( @{ Name = $module.ModuleName Version = $mockVersion ModuleBase = "$env:USERPROFILE\Documents\PowerShell\Modules\$($module.ModuleName)\$mockVersion" } ) } # Create mock CyberAssessment module using actual version $script:MockCyberAssessmentModule = @{ Name = 'CyberAssessment' Version = $script:CurrentCyberAssessmentVersion ModuleBase = "$env:USERPROFILE\Documents\PowerShell\Modules\CyberAssessment\$($script:CurrentCyberAssessmentVersion)" } # Simulate a newer version for update testing using CyberAssessment's versioning pattern # CyberAssessment uses versions like 1.4.0, 1.5.0, 1.6.0, so increment minor version $script:MockNewerCyberAssessmentVersion = [version]"$($script:CurrentCyberAssessmentVersion.Major).$($script:CurrentCyberAssessmentVersion.Minor + 1).0" # Create an older version using CyberAssessment's versioning pattern # For current version 1.6.0, older would be 1.5.0 if ($script:CurrentCyberAssessmentVersion.Minor -eq 0) { # If we're at X.0.0, go to (X-1).9.0 (though this is unlikely for CyberAssessment) $script:MockOlderCyberAssessmentVersion = [version]"$($script:CurrentCyberAssessmentVersion.Major - 1).9.0" } else { # Normal case: 1.6.0 -> 1.5.0 $script:MockOlderCyberAssessmentVersion = [version]"$($script:CurrentCyberAssessmentVersion.Major).$($script:CurrentCyberAssessmentVersion.Minor - 1).0" } # Set up default mocks at BeforeAll level to ensure they're available Mock Get-DependencyStatus { return [PSCustomObject]@{ TotalRequired = $script:CyberAssessmentModuleList.Count Installed = $script:CyberAssessmentModuleList.Count Missing = @() MultipleVersions = @() ModuleFileLocations = @() AdminRequired = $false Status = "Optimal" Recommendations = @("All dependencies are installed.") } } Mock Write-Information { } Mock Invoke-RestMethod { } # Mock Find-Module (this will work regardless of whether PowerShellGet is loaded) Mock Find-Module { param($Name) $null = $Name # Satisfy PSScriptAnalyzer if ($Name -eq 'CyberAssessment') { return @{ Version = $script:MockNewerCyberAssessmentVersion } } return $null } } BeforeEach { # Mock Find-Module (this will work regardless of whether PowerShellGet is loaded) Mock Find-Module { param($Name) $null = $Name # Satisfy PSScriptAnalyzer if ($Name -eq 'CyberAssessment') { return @{ Version = $script:MockNewerCyberAssessmentVersion } } return $null } Mock Get-DependencyStatus { return [PSCustomObject]@{ TotalRequired = $script:CyberAssessmentModuleList.Count Installed = $script:CyberAssessmentModuleList.Count Missing = @() MultipleVersions = @() ModuleFileLocations = @() AdminRequired = $false Status = "Optimal" Recommendations = @("All dependencies are installed.") } } Mock Write-Information { } Mock Invoke-RestMethod { } } Context "When CyberAssessment is not installed" { It "Should report CyberAssessment as not installed" { Mock Get-Module { param($Name, $ListAvailable) $null = $Name, $ListAvailable # Satisfy PSScriptAnalyzer return $null } $result = Test-CyberAssessmentVersion $result[0].Status | Should -Be "Not Installed" $result[0].Recommendations | Should -Match "Install-Module CyberAssessment" } } Context "When CyberAssessment is up to date" { It "Should report CyberAssessment as up to date using actual current version" { Mock Get-Module { param($Name, $ListAvailable) $null = $Name, $ListAvailable # Satisfy PSScriptAnalyzer if ($Name -eq 'CyberAssessment' -and $ListAvailable) { # Return a single module as an array return [PSCustomObject]@{ Version = $script:CurrentCyberAssessmentVersion ModuleBase = "$env:USERPROFILE\Documents\PowerShell\Modules\CyberAssessment\$($script:CurrentCyberAssessmentVersion)" } } return $null } Mock Find-Module { param($Name, $Repository) $null = $Name, $Repository # Satisfy PSScriptAnalyzer if ($Name -eq 'CyberAssessment') { return @{ Version = $script:CurrentCyberAssessmentVersion } } return $null } $result = Test-CyberAssessmentVersion $result[0].Status | Should -Be "Up to Date" $result[0].CurrentVersion | Should -Be $script:CurrentCyberAssessmentVersion $result[0].LatestVersion | Should -Be $script:CurrentCyberAssessmentVersion $result[0].CurrentVersion | Should -Be $script:CurrentCyberAssessmentVersion $result[0].LatestVersion | Should -Be $script:CurrentCyberAssessmentVersion } } Context "When CyberAssessment needs update" { It "Should detect when update is needed using real version numbers" { Mock Get-Module { param($Name, $ListAvailable) $null = $Name, $ListAvailable # Satisfy PSScriptAnalyzer if ($Name -eq 'CyberAssessment' -and $ListAvailable) { return @{ Version = $script:CurrentCyberAssessmentVersion ModuleBase = "$env:USERPROFILE\Documents\PowerShell\Modules\CyberAssessment\$($script:CurrentCyberAssessmentVersion)" } } return $null } Mock Find-Module { param($Name, $Repository) $null = $Name, $Repository # Satisfy PSScriptAnalyzer if ($Name -eq 'CyberAssessment') { return @{ Version = $script:MockNewerCyberAssessmentVersion } } return $null } $result = Test-CyberAssessmentVersion $result[0].CurrentVersion | Should -Be $script:CurrentCyberAssessmentVersion $result[0].LatestVersion | Should -Be $script:MockNewerCyberAssessmentVersion $result[0].Recommendations | Should -Match "Update-CyberAssessment" } } Context "When CyberAssessment has multiple versions" { It "Should detect multiple versions and return highest version as current" { # The function sorts by Version -Descending and selects the first (highest) version # as the current version, even when multiple versions are installed Mock Get-Module { param($Name, $ListAvailable) $null = $Name, $ListAvailable # Satisfy PSScriptAnalyzer if ($Name -eq 'CyberAssessment' -and $ListAvailable) { # Put older version first in array, but function will find highest return @( @{ Version = $script:MockOlderCyberAssessmentVersion ModuleBase = "$env:USERPROFILE\Documents\PowerShell\Modules\CyberAssessment\$($script:MockOlderCyberAssessmentVersion)" }, @{ Version = $script:CurrentCyberAssessmentVersion ModuleBase = "$env:USERPROFILE\Documents\PowerShell\Modules\CyberAssessment\$($script:CurrentCyberAssessmentVersion)" } ) } return $null } $result = Test-CyberAssessmentVersion $result[0].MultipleVersionsInstalled | Should -Be $true # Function returns highest version (1.6.0) as current, not first in array $result[0].CurrentVersion | Should -Be $script:CurrentCyberAssessmentVersion # Check for the actual recommendation text that mentions versions $result[0].Recommendations | Should -Match "versions installed" } } Context "When dependencies have multiple versions" { It "Should report multiple versions for real modules" { # Use first two modules from actual requirements for testing $firstModule = $script:CyberAssessmentModuleList[0] $secondModule = $script:CyberAssessmentModuleList[1] # Add Get-Module mock to return CyberAssessment module Mock Get-Module { param($Name, $ListAvailable) if ($Name -eq 'CyberAssessment' -and $ListAvailable) { return @{ Version = $script:CurrentCyberAssessmentVersion ModuleBase = "$env:USERPROFILE\Documents\PowerShell\Modules\CyberAssessment\$($script:CurrentCyberAssessmentVersion)" } } return $null } Mock Get-DependencyStatus { return [PSCustomObject]@{ TotalRequired = $script:CyberAssessmentModuleList.Count Installed = $script:CyberAssessmentModuleList.Count Missing = @() MultipleVersions = @($firstModule.ModuleName, $secondModule.ModuleName) ModuleFileLocations = @( [PSCustomObject]@{ ModuleName = $firstModule.ModuleName VersionCount = 2 MinVersion = $firstModule.ModuleVersion.ToString() MaxVersion = $firstModule.MaximumVersion.ToString() Locations = @( "$($firstModule.ModuleVersion) [OK] (CurrentUser): $env:USERPROFILE\Documents\PowerShell\Modules\$($firstModule.ModuleName)\$($firstModule.ModuleVersion)", "$($firstModule.ModuleVersion.Major).$($firstModule.ModuleVersion.Minor + 1).0 [OK] (CurrentUser): $env:USERPROFILE\Documents\PowerShell\Modules\$($firstModule.ModuleName)\$($firstModule.ModuleVersion.Major).$($firstModule.ModuleVersion.Minor + 1).0" ) }, [PSCustomObject]@{ ModuleName = $secondModule.ModuleName VersionCount = 2 MinVersion = $secondModule.ModuleVersion.ToString() MaxVersion = $secondModule.MaximumVersion.ToString() Locations = @( "$($secondModule.ModuleVersion) [OK] (AllUsers): $env:ProgramFiles\PowerShell\Modules\$($secondModule.ModuleName)\$($secondModule.ModuleVersion)", "$($secondModule.ModuleVersion.Major).$($secondModule.ModuleVersion.Minor + 1).0 [OK] (CurrentUser): $env:USERPROFILE\Documents\PowerShell\Modules\$($secondModule.ModuleName)\$($secondModule.ModuleVersion.Major).$($secondModule.ModuleVersion.Minor + 1).0" ) } ) AdminRequired = $true Status = "Needs Cleanup" Recommendations = @("2 modules have multiple versions installed. Run 'Reset-CyberAssessmentDependencies' to clean up.") } } $result = Test-CyberAssessmentVersion # Test against the dependency component (second element in array) $result[1].MultipleVersionsInstalled | Should -Be $true $result[1].MultipleVersionModules | Should -Contain $firstModule.ModuleName $result[1].MultipleVersionModules | Should -Contain $secondModule.ModuleName $result[1].ModuleFileLocations.Count | Should -Be 2 } } Context "GitHub version check with real version" { It "Should attempt GitHub version check and compare with real version" { # Use CyberAssessment versioning pattern for GitHub mock $mockGitHubVersion = [version]"$($script:CurrentCyberAssessmentVersion.Major).$($script:CurrentCyberAssessmentVersion.Minor + 1).0" # Override the default mock specifically for this test Mock Invoke-RestMethod { return @{ tag_name = "v$mockGitHubVersion" } } -ParameterFilter { $Uri -like "*github.com*" } # Also mock a successful Get-Module call to ensure CyberAssessment is "installed" Mock Get-Module { param($Name, $ListAvailable) $null = $Name, $ListAvailable # Satisfy PSScriptAnalyzer if ($Name -eq 'CyberAssessment' -and $ListAvailable) { return @{ Version = $script:CurrentCyberAssessmentVersion ModuleBase = "$env:USERPROFILE\Documents\PowerShell\Modules\CyberAssessment\$($script:CurrentCyberAssessmentVersion)" } } return $null } $result = Test-CyberAssessmentVersion -CheckGitHub # Should have attempted to check GitHub Assert-MockCalled Invoke-RestMethod -Times 1 -ParameterFilter { $Uri -like "*github.com*" } $result[0].CurrentVersion | Should -Be $script:CurrentCyberAssessmentVersion } } Context "Parameter validation" { It "Should accept CheckGitHub switch parameter" { { Test-CyberAssessmentVersion -CheckGitHub } | Should -Not -Throw } It "Should work without parameters" { { Test-CyberAssessmentVersion } | Should -Not -Throw } } } } |