diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d63f86..098c986 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,9 @@ name: CI on: pull_request: +env: + DEBUG: 'true' + jobs: test: runs-on: windows-latest @@ -15,4 +18,8 @@ jobs: - run: | $env:PSModulePath += ";C:\Program Files\Citrix\PowerShellModules" .\test - shell: powershell \ No newline at end of file + shell: powershell + + - name: Setup tmate session + if: ${{ env.DEBUG == 'true' }} + uses: mxschmitt/action-tmate@v3 diff --git a/build.ps1 b/build.ps1 index 57c13c5..9bbeef4 100644 --- a/build.ps1 +++ b/build.ps1 @@ -3,16 +3,18 @@ Import-Module Microsoft.PowerShell.PSResourceGet -ErrorAction Stop $Author = 'Tony Sathre' $CompanyName = 'Tony Sathre' -$Description = 'This module is used to automate the deployment of Citrix virtual desktops in a Citrix Virtual Apps & Desktops environment.' +$Description = 'This module is used to automate the creation of Citrix virtual desktops in a Citrix Virtual Apps & Desktops environment.' $ModuleVersion = '2.0.0.0' $Copyright = "(c) {0} ${Author}. All rights reserved." -f (Get-Date -Format 'yyyy') $ProjectUri = 'https://github.com/tonysathre/CitrixAutodeploy' $BasePath = "${PSScriptRoot}\module\CitrixAutodeploy" +$Path = "${BasePath}\CitrixAutodeploy.psd1" +$RootModule = "${PSScriptRoot}\module\CitrixAutodeploy\CitrixAutodeploy.psm1" $NestedModules = Get-ChildItem -Recurse ${BasePath}\functions\*.ps1 | ForEach-Object { ".\functions\$(Split-Path -Leaf $_.Directory)\$($_.Name)" } $FunctionsToExport = (Get-ChildItem ${BasePath}\functions\public\*.ps1).Name -replace '\.ps1$' $RequiredModules = @('PoShLog') -$ScriptsToProcess = @('.\functions\private\Initialize-InternalLogger.ps1') +#$ScriptsToProcess = @('.\functions\private\Initialize-InternalLogger.ps1') $VariablesToExport = @('InternalLogger') @@ -23,12 +25,16 @@ $ModuleManifest = @{ Copyright = $Copyright ProjectUri = $ProjectUri ModuleVersion = $ModuleVersion - Path = "${BasePath}\CitrixAutodeploy.psd1" + RootModule = $RootModule + Path = $Path FunctionsToExport = $FunctionsToExport NestedModules = $NestedModules RequiredModules = $RequiredModules - ScriptsToProcess = $ScriptsToProcess + #ScriptsToProcess = $ScriptsToProcess VariablesToExport = $VariablesToExport } Update-PSModuleManifest @ModuleManifest + +# Trim trailing whitespace added by Update-PSModuleManifest +(Get-Content $Path).TrimEnd() | Set-Content $Path diff --git a/module/CitrixAutodeploy/CitrixAutodeploy.psd1 b/module/CitrixAutodeploy/CitrixAutodeploy.psd1 index 5b81baf..2b36d3c 100644 --- a/module/CitrixAutodeploy/CitrixAutodeploy.psd1 +++ b/module/CitrixAutodeploy/CitrixAutodeploy.psd1 @@ -3,13 +3,13 @@ # # Generated by: Tony Sathre # -# Generated on: 11/25/2024 +# Generated on: 12/3/2024 # @{ # Script module or binary module file associated with this manifest. -# RootModule = '' +RootModule = 'C:\Users\m89944\git\tonysathre\CitrixAutoDeploy\module\CitrixAutodeploy\CitrixAutodeploy.psm1' # Version number of this module. ModuleVersion = '2.0.0.0' @@ -30,7 +30,7 @@ CompanyName = 'Tony Sathre' Copyright = '(c) 2024 Tony Sathre. All rights reserved.' # Description of the functionality provided by this module -Description = 'This module is used to automate the deployment of Citrix virtual desktops in a Citrix Virtual Apps & Desktops environment.' +Description = 'This module is used to automate the creation of Citrix virtual desktops in a Citrix Virtual Apps & Desktops environment.' # Minimum version of the Windows PowerShell engine required by this module # PowerShellVersion = '' @@ -66,23 +66,24 @@ ScriptsToProcess = '.\functions\private\Initialize-InternalLogger.ps1' # FormatsToProcess = @() # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess -NestedModules = @('.\functions\private\Initialize-InternalLogger.ps1', - '.\functions\public\Get-CtxAutodeployConfig.ps1', - '.\functions\public\Initialize-CtxAutodeployEnv.ps1', - '.\functions\public\Initialize-CtxAutodeployLogger.ps1', - '.\functions\public\Invoke-CtxAutodeployTask.ps1', - '.\functions\public\New-CtxAutodeployVM.ps1', - '.\functions\public\Start-CtxHighLevelLogger.ps1', - '.\functions\public\Stop-CtxHighLevelLogger.ps1', - '.\functions\public\Test-DdcConnection.ps1', - '.\functions\public\Test-MachineCountExceedsLimit.ps1', +NestedModules = @('.\functions\private\Get-PathType.ps1', + '.\functions\private\Initialize-InternalLogger.ps1', + '.\functions\public\Get-CtxAutodeployConfig.ps1', + '.\functions\public\Initialize-CtxAutodeployEnv.ps1', + '.\functions\public\Initialize-CtxAutodeployLogger.ps1', + '.\functions\public\Invoke-CtxAutodeployTask.ps1', + '.\functions\public\New-CtxAutodeployVM.ps1', + '.\functions\public\Start-CtxHighLevelLogger.ps1', + '.\functions\public\Stop-CtxHighLevelLogger.ps1', + '.\functions\public\Test-DdcConnection.ps1', + '.\functions\public\Test-MachineCountExceedsLimit.ps1', '.\functions\public\Wait-ForIdentityPoolUnlock.ps1') # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = 'Get-CtxAutodeployConfig', 'Initialize-CtxAutodeployEnv', - 'Initialize-CtxAutodeployLogger', 'Invoke-CtxAutodeployTask', - 'New-CtxAutodeployVM', 'Start-CtxHighLevelLogger', - 'Stop-CtxHighLevelLogger', 'Test-DdcConnection', +FunctionsToExport = 'Get-CtxAutodeployConfig', 'Initialize-CtxAutodeployEnv', + 'Initialize-CtxAutodeployLogger', 'Invoke-CtxAutodeployTask', + 'New-CtxAutodeployVM', 'Start-CtxHighLevelLogger', + 'Stop-CtxHighLevelLogger', 'Test-DdcConnection', 'Test-MachineCountExceedsLimit', 'Wait-ForIdentityPoolUnlock' # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. diff --git a/module/CitrixAutodeploy/CitrixAutodeploy.psm1 b/module/CitrixAutodeploy/CitrixAutodeploy.psm1 index eed3f31..e99a956 100644 --- a/module/CitrixAutodeploy/CitrixAutodeploy.psm1 +++ b/module/CitrixAutodeploy/CitrixAutodeploy.psm1 @@ -1 +1,9 @@ -# TODO: may not even need this \ No newline at end of file +# dot-source private functions +foreach ($Folder in @('private')) { + $Root = Join-Path -Path $PSScriptRoot -ChildPath $Folder + if (Test-Path -Path $Root) { + Write-Verbose "processing folder $Root" + $Files = Get-ChildItem -Path $Root -Filter *.ps1 -Recurse + $Files | ForEach-Object { Write-Verbose $_.basename; . $PSItem.FullName } + } +} diff --git a/module/CitrixAutodeploy/functions/private/Get-PathType.ps1 b/module/CitrixAutodeploy/functions/private/Get-PathType.ps1 new file mode 100644 index 0000000..74a865e --- /dev/null +++ b/module/CitrixAutodeploy/functions/private/Get-PathType.ps1 @@ -0,0 +1,34 @@ +function Get-PathType { + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [string]$Path + ) + + Write-VerboseLog -Message 'Function {MyCommand} called with parameters: {PSBoundParameters}' -PropertyValues $MyInvocation.MyCommand, ($PSBoundParameters | Out-String) + + if ($Path -match '^https?://') { + return 'Uri' + } + + # PowerShell 5.1 uses .NET 4.0.30319.42000 + # [System.IO.Path]::GetInvalidPathChars() contains these printable characters: "<>\|☺☻♥♦♣\t\n\f\r►◄↕‼¶§▬↨↑↓→∟↔▲▼ + # There are also several non-printable characters in the array. + $InvalidPathChars = [System.IO.Path]::InvalidPathChars + $Pattern = [regex]::Escape(($InvalidPathChars -join '')) + + if ($Path -match "[$Pattern]") { + throw [System.IO.IOException]::new('The provided file path contains invalid characters: {0}' -f $Path) + } + + if ([System.IO.Path]::GetExtension($Path)) { + return 'LocalFile' + } + + if (Test-Path $Path -PathType Container) { + return 'Directory' + } + + return 'Unknown' +} diff --git a/module/CitrixAutodeploy/functions/public/Get-CtxAutodeployConfig.ps1 b/module/CitrixAutodeploy/functions/public/Get-CtxAutodeployConfig.ps1 index 19ebf24..ce4ed38 100644 --- a/module/CitrixAutodeploy/functions/public/Get-CtxAutodeployConfig.ps1 +++ b/module/CitrixAutodeploy/functions/public/Get-CtxAutodeployConfig.ps1 @@ -1,21 +1,60 @@ function Get-CtxAutodeployConfig { [CmdletBinding()] - [OutputType([PSCustomObject])] - param( + param ( [Parameter()] - [System.IO.FileInfo]$FilePath = $env:CITRIX_AUTODEPLOY_CONFIG + [ValidateNotNullOrEmpty()] + [string]$Path = $env:CITRIX_AUTODEPLOY_CONFIG ) - Write-VerboseLog -Message "Function {MyCommand} called with parameters: {PSBoundParameters}" -PropertyValues $MyInvocation.MyCommand, ($PSBoundParameters | Out-String) - Write-InfoLog -Message "Loading configuration from file: {FilePath}" -PropertyValues $FilePath + Write-VerboseLog -Message 'Function {MyCommand} called with parameters: {PSBoundParameters}' -PropertyValues $MyInvocation.MyCommand, ($PSBoundParameters | Out-String) + + $PathType = Get-PathType -Path $Path + Write-DebugLog -Message 'PathType: {PathType}' -PropertyValues $PathType + + switch ($PathType) { + 'Uri' { + try { + Write-VerboseLog -Message 'Downloading configuration from URL: {Path}' -PropertyValues $Path + $Response = Invoke-WebRequest -Uri $Path -UseBasicParsing + $ConfigContent = $Response.Content + } + catch { + Write-ErrorLog -Message 'Failed to download the configuration file from URL: {Path}' -Exception $_.Exception -ErrorRecord $_ -PropertyValues $Path + throw + } + } + 'LocalFile' { + try { + Write-VerboseLog -Message 'Reading configuration from local file: {Path}' -PropertyValues $Path + $ConfigContent = Get-Content -Path $Path -Raw -ErrorAction Stop + + if ($ConfigContent.Length -eq 0) { + Write-ErrorLog -Message 'The configuration file is empty: {Path}' -PropertyValues $Path + throw [System.IO.IOException]::new('The configuration file is empty: {0}' -f $Path) + } + } + catch { + Write-FatalLog -Message 'Failed to read the configuration file from local path: {Path}' -Exception $_.Exception -ErrorRecord $_ -PropertyValues $Path + throw + } + } + 'Directory' { + Write-FatalLog -Message 'The provided path is a directory: {Path}' -Exception ([System.Management.Automation.ItemNotFoundException]::new('Directory path')) -PropertyValues $Path + throw + } + default { + Write-FatalLog -Message 'The provided path is neither a valid URL nor a local file path: {Path}' -Exception ([System.Management.Automation.ItemNotFoundException]::new('Invalid path or URL')) -PropertyValues $Path + throw + } + } try { - $Config = Get-Content -Path $FilePath -Raw -ErrorAction Stop | ConvertFrom-Json + $Config = ConvertFrom-Json -InputObject $ConfigContent + + return $Config } catch { - Write-FatalLog -Message "Failed to load configuration from file {FilePath}" -Exception $_.Exception -ErrorRecord $_ -PropertyValues $FilePath + Write-ErrorLog -Message 'Failed to parse the configuration content as JSON: {ConfigContent}' -Exception $_.Exception -ErrorRecord $_ -PropertyValues $ConfigContent throw } - - return $Config } diff --git a/test.ps1 b/test.ps1 index d430f12..7b172b2 100644 --- a/test.ps1 +++ b/test.ps1 @@ -31,22 +31,20 @@ param ( try { if ($PSBoundParameters['Verbose']) { . ${PSScriptRoot}\module\CitrixAutodeploy\functions\public\Initialize-CtxAutodeployLogger.ps1 4> $null - $VerbosePreference -eq 'Continue' $Logger = Initialize-CtxAutodeployLogger -LogLevel Verbose -AddEnrichWithExceptionDetails } if ($PSBoundParameters['Debug']) { . ${PSScriptRoot}\module\CitrixAutodeploy\functions\public\Initialize-CtxAutodeployLogger.ps1 4> $null - $DebugPreference -eq 'Continue' $Logger = Initialize-CtxAutodeployLogger -LogLevel Debug -AddEnrichWithExceptionDetails } $PesterConfiguration = New-PesterConfiguration - $PesterConfiguration.Output.Verbosity = $Output - $PesterConfiguration.Run.Path = $Tests - $PesterConfiguration.Output.StackTraceVerbosity = $StackTraceVerbosity - $PesterConfiguration.CodeCoverage.Enabled = $CodeCoverageEnabled - $PesterConfiguration.CodeCoverage.Path = $Tests + $PesterConfiguration.Output.Verbosity = $Output + $PesterConfiguration.Run.Path = $Tests + $PesterConfiguration.Output.StackTraceVerbosity = $StackTraceVerbosity + $PesterConfiguration.CodeCoverage.Enabled = $CodeCoverageEnabled + $PesterConfiguration.CodeCoverage.Path = $Tests $PesterConfiguration.CodeCoverage.CoveragePercentTarget = 75 1..$Iterations | ForEach-Object { @@ -54,9 +52,13 @@ try { } } -catch {} +catch { + throw $_ +} finally { Close-Logger -} + $global:VerbosePreference = 'SilentlyContinue' + $global:DebugPreference = 'SilentlyContinue' +} diff --git a/tests/Get-CtxAutodeployConfig.Tests.ps1 b/tests/Get-CtxAutodeployConfig.Tests.ps1 index 68d382e..8bac14a 100644 --- a/tests/Get-CtxAutodeployConfig.Tests.ps1 +++ b/tests/Get-CtxAutodeployConfig.Tests.ps1 @@ -3,62 +3,101 @@ param () Describe 'Get-CtxAutodeployConfig' { BeforeAll { - Import-Module ${PSScriptRoot}\Pester.Helper.psm1 -Force -ErrorAction Stop 3> $null 4> $null + Import-Module "${PSScriptRoot}\Pester.Helper.psm1" -Force -ErrorAction Stop 3> $null 4> $null + Import-CitrixAutodeployModule -Scope Global . "${PSScriptRoot}\..\module\CitrixAutodeploy\functions\public\Get-CtxAutodeployConfig.ps1" } - Context 'When the configuration file exists' { - It 'Should return a configuration object' { - $FilePath = "${PSScriptRoot}\test_config.json" - $Config = Get-CtxAutodeployConfig -FilePath $FilePath - $Config | Should -Not -BeNullOrEmpty - $Config.AutodeployMonitors.AutodeployMonitor[0].AdminAddress | Should -Be 'test-admin-address' + BeforeEach { + $script:FilePath = "${PSScriptRoot}\temp_config.json" + @' +{ + "AutodeployMonitors": { + "AutodeployMonitor": [ + { + "AdminAddress": "test-admin-address", + "BrokerCatalog": "TestCatalog1", + "DesktopGroupName": "TestGroup1", + "MinAvailableMachines": 2, + "PreTask": "", + "PostTask": "" + } + ] + } +} +'@ | Set-Content -Path $FilePath + } + + Context 'Valid Config File' { + It 'Should return expected configuration object when a valid file is provided' { + $Result = Get-CtxAutodeployConfig -Path $FilePath + $Result | Should -BeOfType [PSCustomObject] + $Result.AutodeployMonitors.AutodeployMonitor[0].AdminAddress | Should -Be 'test-admin-address' } } - Context 'When the configuration file does not exist' { - It 'Should throw an error' { - $FilePath = "${PSScriptRoot}\non_existent_config.json" - { Get-CtxAutodeployConfig -FilePath $FilePath } | Should -Throw + Context 'Config File Set via $env:CITRIX_AUTODEPLOY_CONFIG' { + It 'Should return expected configuration object when a valid file path is set via environment variable' { + $env:CITRIX_AUTODEPLOY_CONFIG = $FilePath + + $Result = Get-CtxAutodeployConfig + $Result | Should -BeOfType [PSCustomObject] + $Result.AutodeployMonitors.AutodeployMonitor[0].AdminAddress | Should -Be 'test-admin-address' } } - Context 'When the configuration file is invalid JSON' { - It 'Should throw an error' { - $InvalidJson = @' -{ - "AutodeployMonitors": { - "AutodeployMonitor": [ - { - "AdminAddress": "test-admin-address", - "BrokerCatalog": "test-broker-catalog", - "DesktopGroupName": "test-desktop-group-name", + Context 'Invalid File Path' { + It 'Should throw an [PathNotFound] exception when file does not exist' { + { Get-CtxAutodeployConfig -Path "${PSScriptRoot}\non_existent_config.json" } | Should -Throw -ErrorId 'PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand' -ExpectedMessage 'Cannot find path*' } } -} -'@ | Set-Content -Path "${PSScriptRoot}\invalid_config.json" - $FilePath = "${PSScriptRoot}\invalid_config.json" - { Get-CtxAutodeployConfig -FilePath $FilePath } | Should -Throw + + Context 'Unsupported File Format' { + It 'Should throw an error when an unsupported file format is used' { + Set-Content -Path $FilePath -Value 'Invalid Content' + + { Get-CtxAutodeployConfig -Path $FilePath } | Should -Throw -ErrorId 'System.ArgumentException,Microsoft.PowerShell.Commands.ConvertFromJsonCommand' -ExpectedMessage 'Invalid JSON primitive: Invalid.' + + Remove-Item -Path $FilePath -Force } + } + + Context 'Download Config Over <_>' -ForEach 'HTTP', 'HTTPS' { + It 'Should successfully download and parse a valid JSON config from an <_> URL' { + $Uri = "{0}://example.com/config.json" -f $_ - AfterAll { - Remove-Item "${PSScriptRoot}\invalid_config.json" + Mock Invoke-WebRequest { + return [PSCustomObject]@{ + StatusCode = 200 + StatusCodeDescription = 'OK' + Content = '{ "Key": "Value" }' + } + } -ModuleName CitrixAutodeploy + + $Result = Get-CtxAutodeployConfig -Path $Uri + + $Result | Should -BeOfType [PSCustomObject] + $Result.Key | Should -Be 'Value' } } - Context 'When no FilePath is provided and environment variable is set' { - It 'Should use the environment variable for the file path' { - $env:CITRIX_AUTODEPLOY_CONFIG = "${PSScriptRoot}\test_config.json" - $Config = Get-CtxAutodeployConfig - $Config | Should -Not -BeNullOrEmpty - $Config.AutodeployMonitors.AutodeployMonitor[0].AdminAddress | Should -Be 'test-admin-address' + Context 'Invalid JSON Format' { + It 'Should throw an [System.ArgumentException] exception for invalid JSON format' { + Set-Content -Path $FilePath -Value '{Invalid:Json}' + + { Get-CtxAutodeployConfig -Path $FilePath } | Should -Throw -ErrorId 'System.ArgumentException,Microsoft.PowerShell.Commands.ConvertFromJsonCommand' -ExpectedMessage 'Invalid JSON primitive: Json.' + + Remove-Item -Path $FilePath -Force } } - Context 'When no FilePath is provided and environment variable is not set' { - It 'Should throw an error' { - $env:CITRIX_AUTODEPLOY_CONFIG = $null - { Get-CtxAutodeployConfig } | Should -Throw + Context 'Empty Config File' { + It 'Should throw an error when the file is exists, but is empty' { + Set-Content -Path $FilePath -Value $null + + { Get-CtxAutodeployConfig -Path $FilePath } | Should -Throw -ExpectedMessage 'The configuration file is empty*' + + Remove-Item -Path $FilePath -Force } } -} \ No newline at end of file +} diff --git a/tests/Get-PathType.Tests.ps1 b/tests/Get-PathType.Tests.ps1 new file mode 100644 index 0000000..3202c16 --- /dev/null +++ b/tests/Get-PathType.Tests.ps1 @@ -0,0 +1,91 @@ +[CmdletBinding()] +param () + +Describe 'Get-PathType' { + BeforeAll { + . "${PSScriptRoot}\..\module\CitrixAutodeploy\functions\private\Get-PathType.ps1" + } + + Context 'Valid <_> URLs' -ForEach 'HTTP', 'HTTPS' { + It "Should return 'Uri' for an <_> URL" { + $Result = Get-PathType -Path ('{0}://example.com' -f $_) + $Result | Should -Be 'Uri' + } + + It "Should return 'Uri' for an <_> URL with query parameters" { + $Result = Get-PathType -Path ('{0}://example.com?param=value' -f $_) + $Result | Should -Be 'Uri' + } + + It "Should return 'Uri' for an <_> URL with port number" { + $Result = Get-PathType -Path ('{0}://example.com:8080' -f $_) + $Result | Should -Be 'Uri' + } + } + + Context 'Valid Local File Paths' { + BeforeAll { + New-Item -Path "$PSScriptRoot\TestFile1.txt" -ItemType File -Force | Out-Null + New-Item -Path "$PSScriptRoot\TestFile2.json" -ItemType File -Force | Out-Null + } + + AfterAll { + Remove-Item -Path "$PSScriptRoot\TestFile1.txt", "$PSScriptRoot\TestFile2.json" -Force + } + + It "Should return 'LocalFile' for a valid local file path" { + $Result = Get-PathType -Path "$PSScriptRoot\TestFile1.txt" + $Result | Should -Be 'LocalFile' + } + + It "Should return 'LocalFile' for another valid local file path" { + $Result = Get-PathType -Path "$PSScriptRoot\TestFile2.json" + $Result | Should -Be 'LocalFile' + } + + It "Should return 'LocalFile' for a non-existent file path" { + $Result = Get-PathType -Path "$PSScriptRoot\NonExistentFile.txt" + $Result | Should -Be 'LocalFile' + } + } + + Context 'Valid Directory Paths' { + It "Should return 'Directory' for a valid directory path" { + $Result = Get-PathType -Path "$PSScriptRoot" + $Result | Should -Be 'Directory' + } + + It "Should return 'Directory' for another valid directory path" { + $Result = Get-PathType -Path "$env:TEMP" + $Result | Should -Be 'Directory' + } + } + + Context 'Invalid Paths' { + It "Should return 'Unknown' for a random string" { + $Result = Get-PathType -Path 'randomstring' + $Result | Should -Be 'Unknown' + } + + It "Should return 'Unknown' for a malformed URL" { + $Result = Get-PathType -Path 'htp:/malformed-url' + $Result | Should -Be 'Unknown' + } + + It 'Should throw an [ParameterArgumentValidationError] exception for an empty string' { + { Get-PathType -Path '' } | Should -Throw -ErrorId 'ParameterArgumentValidationError,Get-PathType' -ExceptionType ([System.Exception]) -ExpectedMessage "*The argument is null or empty*" + } + + It 'Should throw an exception for a file path with invalid characters' { + { Get-PathType -Path 'C:\Invalid|Path.txt' } | Should -Throw -ExpectedMessage "The provided file path contains invalid characters*" + } + } + + Context 'Edge Cases' { + It "Should return 'Uri' for a URL with a long query string" { + $LongUrl = 'https://example.com?' + ('param=value&' * 100) + $Result = Get-PathType -Path $LongUrl + $Result | Should -Be 'Uri' + } + } +} diff --git a/tests/Initialize-CtxAutodeployLogger.Tests.ps1 b/tests/Initialize-CtxAutodeployLogger.Tests.ps1 index ae43e00..d624ac3 100644 --- a/tests/Initialize-CtxAutodeployLogger.Tests.ps1 +++ b/tests/Initialize-CtxAutodeployLogger.Tests.ps1 @@ -4,8 +4,7 @@ param () Describe 'Initialize-CtxAutodeployLogger' { BeforeAll { . "${PSScriptRoot}\..\module\CitrixAutodeploy\functions\public\Initialize-CtxAutodeployLogger.ps1" - Import-Module ${PSScriptRoot}\Pester.Helper.psm1 -Force -ErrorAction Stop 3> $null 4> $null - Import-CitrixAutodeployModule 3> $null 4> $null + Import-CitrixAutodeployModule -Scope Global } AfterAll { diff --git a/tests/Pester.Helper.psm1 b/tests/Pester.Helper.psm1 index ef71d88..e309db0 100644 --- a/tests/Pester.Helper.psm1 +++ b/tests/Pester.Helper.psm1 @@ -7,7 +7,7 @@ function Import-CitrixPowerShellModules { 'Citrix.Broker.Commands', 'Citrix.ConfigurationLogging.Commands', 'Citrix.MachineCreation.Commands' - ) | Import-Module -Force -ErrorAction Stop 3> $null 4> $null + ) | Import-Module -Force -ErrorAction Stop } function Remove-CitrixPowerShellModules { @@ -24,9 +24,13 @@ function Remove-CitrixPowerShellModules { function Import-CitrixAutodeployModule { [CmdletBinding()] - param () + param ( + [Parameter()] + [ValidateSet('Global', 'Local')] + [string]$Scope = 'Global' + ) - Import-Module "${PSScriptRoot}\..\module\CitrixAutodeploy" -Force -ErrorAction Stop + Import-Module "${PSScriptRoot}\..\module\CitrixAutodeploy" -Scope $Scope -Force -ErrorAction Stop } function Remove-CitrixAutodeployModule { diff --git a/tests/Test-DdcConnection.Tests.ps1 b/tests/Test-DdcConnection.Tests.ps1 index d08c5f0..8002c3d 100644 --- a/tests/Test-DdcConnection.Tests.ps1 +++ b/tests/Test-DdcConnection.Tests.ps1 @@ -14,7 +14,7 @@ Describe 'Test-DdcConnection' { } Context 'When connection fails' { - It 'Should return $false using protocol <_>' -ForEach $Protocols { + It "Should return $false using protocol <_>" -ForEach $Protocols { Mock Invoke-RestMethod { return $false } $Result = Test-DdcConnection -AdminAddress 'test-admin-address' -Protocol 'https' diff --git a/tests/Test-MachineCountExceedsLimit.Tests.ps1 b/tests/Test-MachineCountExceedsLimit.Tests.ps1 index 309a6d4..4842bd8 100644 --- a/tests/Test-MachineCountExceedsLimit.Tests.ps1 +++ b/tests/Test-MachineCountExceedsLimit.Tests.ps1 @@ -4,7 +4,7 @@ param () Describe 'Test-MachineCountExceedsLimit' { BeforeDiscovery { Import-Module ${PSScriptRoot}\Pester.Helper.psm1 -Force -ErrorAction Stop 3> $null 4> $null - Import-CitrixPowerShellModules + Import-CitrixPowerShellModules 3> $null 4> $null } BeforeAll { diff --git a/tests/Wait-ForIdentityPoolUnlock.Tests.ps1 b/tests/Wait-ForIdentityPoolUnlock.Tests.ps1 index eb81045..a7797ca 100644 --- a/tests/Wait-ForIdentityPoolUnlock.Tests.ps1 +++ b/tests/Wait-ForIdentityPoolUnlock.Tests.ps1 @@ -46,12 +46,11 @@ Describe 'Wait-ForIdentityPoolUnlock' { # A bit janky but it works for now $Buffer = .5 $global:CallCount = 0 - $Timeout = 2 $Params = @{ AdminAddress = New-MockAdminAddress IdentityPool = Get-AcctIdentityPoolMock -Lock $true - Timeout = $Timeout + Timeout = 2 } $StartTime = Get-Date @@ -60,14 +59,14 @@ Describe 'Wait-ForIdentityPoolUnlock' { $ExecutionTime = $EndTime - $StartTime $ExecutionTime.TotalSeconds | Should -BeGreaterThan 1 - $ExecutionTime.TotalSeconds | Should -BeLessOrEqual ($Timeout + $Buffer) + $ExecutionTime.TotalSeconds | Should -BeLessOrEqual ($Params.Timeout + $Buffer) } } Context 'When the identity pool remains locked beyond the timeout period' { It 'Should exit after the specified timeout period' { Mock Get-AcctIdentityPool { return Get-AcctIdentityPoolMock -Lock $true } - + $Buffer = 2 $Params = @{ AdminAddress = New-MockAdminAddress IdentityPool = Get-AcctIdentityPoolMock -Lock $true @@ -79,7 +78,7 @@ Describe 'Wait-ForIdentityPoolUnlock' { } $ExecutionTime.TotalSeconds | Should -BeGreaterOrEqual 2 - $ExecutionTime.TotalSeconds | Should -BeLessThan 3 + $ExecutionTime.TotalSeconds | Should -BeLessThan ($Params.Timeout + $Buffer) # 2 second buffer to account for execution overhead Should -Invoke Get-AcctIdentityPool -Times 2 -Scope It }