Skip to content

Commit

Permalink
Restore-TestEnvironment: New parameter KeepNewMachinePSModulePath (
Browse files Browse the repository at this point in the history
…#128)

- `Restore-TestEnvironment`
  - A new parameter `KeepNewMachinePSModulePath` was added and only works
    if the test type is `Integration` or `All`. The new parameter will
    keep any new paths that was added to the machine environment variable
    `PSModulePath` after the command `Initialize-TestEnvironment` was called.
    This is helpful if a a path is added by an integration test and is needed
    by a second integration test and there is a need to run `Restore-TestEnvironment`
    between tests.
- Added private function `Join-PSModulePath` that will concatenate two
  strings with semi-colon separated paths.
- `Initialize-TestEnvironment`
  - Now `$script:machineOldPSModulePath` is always set when called with the
    test type `Integration` or `All`. Before it reverted to the paths on the
    event `OnRemove` that were the current paths when `Initialize-TestEnvironment`
    was first called. On subsequent calls any new paths were ignored.
  - If there are a subsequent call to `Initialize-TestEnvironment` without the
    command `Restore-TestEnvironment` was called prior the command will now
    fail with a non-terminating exception asking the user to run `Restore-TestEnvironment`
    to avoid the previously saved paths (`$script:machineOldPSModulePath`)
    to be overwritten.
  • Loading branch information
johlju authored May 17, 2023
1 parent 73d6c32 commit b73c287
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 23 deletions.
28 changes: 26 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
# Changelog for DscResource.Test

# Changelog

All notable changes to this project will be documented in this file.

The format is based on and uses the types of changes according to [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- `Restore-TestEnvironment`
- A new parameter `KeepNewMachinePSModulePath` was added and only works
if the test type is `Integration` or `All`. The new parameter will
keep any new paths that was added to the machine environment variable
`PSModulePath` after the command `Initialize-TestEnvironment` was called.
This is helpful if a a path is added by an integration test and is needed
by a second integration test and there is a need to run `Restore-TestEnvironment`
between tests.
- Added private function `Join-PSModulePath` that will concatenate two
strings with semi-colon separated paths.

### Fixed

- `Initialize-TestEnvironment`
- Now `$script:machineOldPSModulePath` is always set when called with the
test type `Integration` or `All`. Before it reverted to the paths on the
event `OnRemove` that were the current paths when `Initialize-TestEnvironment`
was first called. On subsequent calls any new paths were ignored.
- If there are a subsequent call to `Initialize-TestEnvironment` without the
command `Restore-TestEnvironment` was called prior the command will now
fail with a non-terminating exception asking the user to run `Restore-TestEnvironment`
to avoid the previously saved paths (`$script:machineOldPSModulePath`)
to be overwritten.

## [0.16.1] - 2022-04-20

### Changed
Expand Down
2 changes: 0 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ stages:
- stage: Test
dependsOn: Build
jobs:


- job: test_windows_wps
displayName: 'Test Windows (WPS)'
pool:
Expand Down
41 changes: 41 additions & 0 deletions source/Private/Join-PSModulePath.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

<#
.SYNOPSIS
Concatenates two string that contain semi-colon separated strings.
.PARAMETER Path
A string with all the paths separated by semi-colons.
.PARAMETER NewPath
A string with all the paths separated by semi-colons.
.EXAMPLE
Join-PSModulePath -Path '<Path 1>;<Path 2>' -NewPath 'Path3;Path4'
#>
function Join-PSModulePath
{
[CmdletBinding()]
[OutputType([System.String])]
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[System.String]
$Path,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[System.String]
$NewPath
)

foreach ($currentNewPath in ($NewPath -split ';'))
{
if ($Path -cnotmatch [System.Text.RegularExpressions.Regex]::Escape($currentNewPath))
{
$Path = @($Path, $currentNewPath) -join ';'
}
}

return $Path
}
10 changes: 7 additions & 3 deletions source/Public/Initialize-TestEnvironment.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,9 @@ function Initialize-TestEnvironment
$Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
)
{
if (!$script:MachineOldPSModulePath)
if ($script:MachineOldPSModulePath)
{
Write-Warning "This will change your Machine Environment Variable"
$script:MachineOldPSModulePath = [System.Environment]::GetEnvironmentVariable('PSModulePath', 'Machine')
Write-Error -Message 'There were already saved paths of the machine environment variable PSModulePath from a previous call to the command. The previous saved paths will be overwritten if ErrorAction is not set to Stop. To avoid this error run the command Restore-TestEnvironment before subsequent calls of the command Initialize-TestEnvironment' -Category 'InvalidData' -ErrorId 'IT0001' -TargetObject 'PSModulePath'
}

# Preserve and set the execution policy so that the DSC MOF can be created
Expand Down Expand Up @@ -255,6 +254,11 @@ function Initialize-TestEnvironment

Write-Verbose -Message ('The machine execution policy is set to ''{0}''' -f $currentMachineExecutionPolicy)

Write-Warning -Message 'This will change your machine environment variable PSModulePath but can be restored by running the command Restore-TestEnvironment.'

# The variable $script:machineOldPSModulePath is also used in suffix.ps1.
$script:machineOldPSModulePath = [System.Environment]::GetEnvironmentVariable('PSModulePath', 'Machine')

<#
For integration tests we have to set the machine's PSModulePath because otherwise the
DSC LCM won't be able to find the resource module being tested or may use the wrong one.
Expand Down
40 changes: 27 additions & 13 deletions source/Public/Restore-TestEnvironment.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ function Restore-TestEnvironment
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[Hashtable]
$TestEnvironment
[System.Collections.Hashtable]
$TestEnvironment,

[Parameter()]
[System.Management.Automation.SwitchParameter]
$KeepNewMachinePSModulePath
)

Write-Verbose -Message "Cleaning up Test Environment after $($TestEnvironment.TestType) testing of $($TestEnvironment.DSCResourceName) in module $($TestEnvironment.DSCModuleName)."
Expand All @@ -32,18 +36,33 @@ function Restore-TestEnvironment
{
# Clear the DSC LCM & Configurations
Clear-DscLcmConfiguration

if ($script:machineOldPSModulePath)
{
if ($KeepNewMachinePSModulePath.IsPresent)
{
$currentMachinePSModulePath = [System.Environment]::GetEnvironmentVariable('PSModulePath', 'Machine')

if ($currentMachinePSModulePath)
{
$script:machineOldPSModulePath = Join-PSModulePath -Path $script:machineOldPSModulePath -NewPath $currentMachinePSModulePath
}
}

<#
Restore the machine PSModulePath. The variable $script:machineOldPSModulePath
is also used in suffix.ps1.
#>
Set-PSModulePath -Path $script:machineOldPSModulePath -Machine -ErrorAction 'Stop'

$script:machineOldPSModulePath = $null
}
}

# Restore PSModulePath
if ($TestEnvironment.OldPSModulePath -ne $env:PSModulePath)
{
Set-PSModulePath -Path $TestEnvironment.OldPSModulePath

if ($TestEnvironment.TestType -in ('Integration','All'))
{
# Restore the machine PSModulePath for integration tests.
Set-PSModulePath -Path $TestEnvironment.OldPSModulePath -Machine
}
}

# Restore the Execution Policy
Expand All @@ -52,11 +71,6 @@ function Restore-TestEnvironment
Set-ExecutionPolicy -ExecutionPolicy $TestEnvironment.OldExecutionPolicy -Scope 'Process' -Force
}

if ($script:MachineOldPSModulePath)
{
[System.Environment]::SetEnvironmentVariable('PSModulePath', $script:MachineOldPSModulePath, 'Machine')
}

if ($script:MachineOldExecutionPolicy)
{
Set-ExecutionPolicy -ExecutionPolicy $script:MachineOldExecutionPolicy -Scope LocalMachine -Force -ErrorAction Stop
Expand Down
6 changes: 4 additions & 2 deletions source/suffix.ps1
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
if ($script:MachineOldPSModulePath)
if ($script:machineOldPSModulePath)
{
[System.Environment]::SetEnvironmentVariable('PSModulePath', $script:MachineOldPSModulePath, 'Machine')
Set-PSModulePath -Path $script:machineOldPSModulePath -Machine -ErrorAction 'Stop'

$script:machineOldPSModulePath = $null
}

if ($script:MachineOldExecutionPolicy)
Expand Down
14 changes: 14 additions & 0 deletions tests/Unit/Public/Initialize-TestEnvironment.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ Import-Module $ProjectName -Force

InModuleScope $ProjectName {
Describe 'Initialize-TestEnvironment' {
BeforeAll {
if ($script:machineOldPSModulePath)
{
throw 'The script variable $script:machineOldPSModulePath was already set, cannot run unit test. This should not happen unless the test is run in the context of an integration test.'
}
}

AfterEach {
<#
Make sure to set this to $null so that the unit tests won't fail.
#>
$script:machineOldPSModulePath = $null
}

Context 'When initializing the test environment' {
BeforeAll {
$mockDscModuleName = 'TestModule'
Expand Down
36 changes: 35 additions & 1 deletion tests/Unit/Public/Restore-TestEnvironment.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,44 @@ InModuleScope $ProjectName {
$Path -eq $testEnvironmentParameter.OldPSModulePath `
-and $PSBoundParameters.ContainsKey('Machine') -eq $false
} -Exactly -Times 1 -Scope It
}
}

Context 'When restoring the test environment from an integration test that changed the machine PSModulePath' {
BeforeAll {
if ($script:machineOldPSModulePath)
{
throw 'The script variable $script:machineOldPSModulePath was already set, cannot run unit test. This should not happen unless the test is run in the context of an integration test.'
}

$script:machineOldPSModulePath = 'SavedPath'
}

AfterAll {
$script:machineOldPSModulePath = $null
}

It 'Should restore without throwing and call the correct mocks' {
$testEnvironmentParameter = @{
DSCModuleName = 'TestModule'
DSCResourceName = 'TestResource'
TestType = 'Integration'
ImportedModulePath = $moduleToImportFilePath
OldPSModulePath = 'Wrong paths'
OldExecutionPolicy = Get-ExecutionPolicy
}

{ Restore-TestEnvironment -TestEnvironment $testEnvironmentParameter -KeepNewMachinePSModulePath } | Should -Not -Throw

Assert-MockCalled -CommandName 'Clear-DscLcmConfiguration' -Exactly -Times 1 -Scope It

Assert-MockCalled -CommandName 'Set-PSModulePath' -ParameterFilter {
$Path -eq $testEnvironmentParameter.OldPSModulePath `
-and $PSBoundParameters.ContainsKey('Machine') -eq $false
} -Exactly -Times 1 -Scope It

Assert-MockCalled -CommandName 'Set-PSModulePath' -ParameterFilter {
$Path -match 'SavedPath' `
-and $PSBoundParameters.ContainsKey('Machine') -eq $true
} -Exactly -Times 1 -Scope It
}
Expand Down Expand Up @@ -126,5 +161,4 @@ InModuleScope $ProjectName {
}
}
}

}

0 comments on commit b73c287

Please sign in to comment.