-
Notifications
You must be signed in to change notification settings - Fork 8
/
Initialize-TestEnvironment.ps1
306 lines (255 loc) · 11.6 KB
/
Initialize-TestEnvironment.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
<#
.SYNOPSIS
Initializes an environment for running unit or integration tests
on a DSC resource.
This includes:
1. Updates the $env:PSModulePath to ensure the correct module is tested.
2. Imports the module to test.
3. Sets the PowerShell ExecutionMode to Unrestricted.
4. returns a test environment object to store the settings.
The above changes are reverted by calling the Restore-TestEnvironment
function with the returned object.
Returns a test environment object which must be passed to the
Restore-TestEnvironment function to allow it to restore the system
back to the original state.
.PARAMETER Module
The name of the DSC Module containing the resource that the tests will be
run on.
.PARAMETER DscResourceName
The full name of the DSC resource that the tests will be run on. This is
usually the name of the folder containing the actual resource MOF file.
.PARAMETER TestType
Specifies the type of tests that are being initialized. It can be:
Unit: Initialize for running Unit tests on a DSC resource.
Integration: Initialize for running Integration tests on a DSC resource.
All: Initialize for running end-to-end tests on a DSC resource. These
tests will include both unit and integration type tests and so will
initialize the DSC LCM as well as import the module.
.PARAMETER ResourceType
Specifies if the DscResource under test is mof-based or class-based.
The default value is 'mof'.
It can be:
Mof: The test initialization assumes a Mof-based DscResource folder structure.
Class: The test initialization assumes a Class-based DscResource folder structure.
.PARAMETER ProcessExecutionPolicy
Specifies the process' execution policy to set before running tests.
If not specified, the command will not alter the current process' execution
policy.
.PARAMETER MachineExecutionPolicy
Specifies the machine's execution policy to set before running tests.
If not specified, the command will not alter the machine's execution policy.
.EXAMPLE
$TestEnvironment = Initialize-TestEnvironment `
-DSCModuleName 'xNetworking' `
-DSCResourceName 'MSFT_xFirewall' `
-TestType Unit
This command will initialize the test environment for Unit testing
the MSFT_xFirewall mof-based DSC resource in the xNetworking DSC module.
.EXAMPLE
$TestEnvironment = Initialize-TestEnvironment `
-DSCModuleName 'SqlServerDsc' `
-DSCResourceName 'SqlAGDatabase' `
-TestType Unit
-ResourceType Class
This command will initialize the test environment for Unit testing
the SqlAGDatabase class-based DSC resource in the SqlServer DSC module.
.EXAMPLE
$TestEnvironment = Initialize-TestEnvironment `
-DSCModuleName 'xNetworking' `
-DSCResourceName 'MSFT_xFirewall' `
-TestType Integration
This command will initialize the test environment for Integration testing
the MSFT_xFirewall DSC resource in the xNetworking DSC module.
#>
function Initialize-TestEnvironment
{
[OutputType([Hashtable])]
[CmdletBinding()]
param
(
[Parameter(Mandatory = $true)]
[Alias('DscModuleName')]
[ValidateNotNullOrEmpty()]
[String]
$Module,
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$DscResourceName,
[Parameter(Mandatory = $true)]
[ValidateSet('Unit', 'Integration', 'All')]
[String]
$TestType,
[Parameter()]
[ValidateSet('Mof', 'Class')]
[String]
$ResourceType = 'Mof',
[Parameter()]
[ValidateSet('AllSigned', 'Bypass', 'RemoteSigned', 'Unrestricted')]
[String]
$ProcessExecutionPolicy,
[Parameter()]
[ValidateSet('AllSigned', 'Bypass', 'RemoteSigned', 'Unrestricted')]
[String]
$MachineExecutionPolicy
)
Write-Verbose -Message "Initializing test environment for $TestType testing of $DscResourceName in module $Module"
$ModuleUnderTest = (Import-Module $Module -PassThru -ErrorAction Stop) | Where-Object -FilterScript { $_.Name -eq $Module } # The Where-Object filter is added to fix issue #97
$moduleRootFilePath = $ModuleUnderTest.ModuleBase
$moduleManifestFilePath = Join-Path -Path $moduleRootFilePath -ChildPath "$($ModuleUnderTest.Name).psd1"
if (Test-Path -Path $moduleManifestFilePath)
{
Write-Verbose -Message "Module manifest $($ModuleUnderTest.Name).psd1 detected at $moduleManifestFilePath"
}
else
{
throw "Module manifest could not be found for the module $($ModuleUnderTest.Name) in the root folder $moduleRootFilePath"
}
# Import the module to test
if ($TestType -in ('Unit', 'All'))
{
switch ($ResourceType)
{
'Mof'
{
$resourceTypeFolderName = 'DSCResources'
}
'Class'
{
$resourceTypeFolderName = 'DSCClassResources'
}
}
$dscResourcesFolderFilePath = Join-Path -Path $moduleRootFilePath -ChildPath $resourceTypeFolderName
$dscResourceToTestFolderFilePath = Join-Path -Path $dscResourcesFolderFilePath -ChildPath $DscResourceName
$moduleToImportFilePath = Join-Path -Path $dscResourceToTestFolderFilePath -ChildPath "$DscResourceName.psm1"
}
else
{
$moduleToImportFilePath = $moduleManifestFilePath
}
Import-Module -Name $moduleToImportFilePath -Scope 'Global' -Force
<#
Set the PSModulePath environment variable so that the module path that includes the module
we want to test appears first. LCM will then use this path to locate modules when
integration tests are called. Placing the path we want first ensures the correct module
will be tested.
#>
if ((Split-Path -Leaf $moduleRootFilePath) -as [version])
{
$moduleParentFilePath = Split-Path -Parent -Path (Split-Path -Parent -Path $moduleRootFilePath)
}
else
{
$moduleParentFilePath = Split-Path -Path $moduleRootFilePath -Parent
}
$oldPSModulePath = $env:PSModulePath
if ($null -ne $oldPSModulePath)
{
$oldPSModulePathSplit = $oldPSModulePath.Split([io.path]::PathSeparator)
}
else
{
$oldPSModulePathSplit = $null
}
if ($oldPSModulePathSplit -ccontains $moduleParentFilePath)
{
# Remove the existing module path from the new PSModulePath
$newPSModulePathSplit = $oldPSModulePathSplit | Where-Object { $_ -ne $moduleParentFilePath }
}
else
{
$newPSModulePath = $oldPSModulePath
}
$RequiredModulesPath = Join-Path -Path $moduleParentFilePath 'RequiredModules'
if ($newPSModulePathSplit -cnotcontains $RequiredModulesPath)
{
$newPSModulePathSplit = @($RequiredModulesPath) + $newPSModulePathSplit
}
$newPSModulePathSplit = @($moduleParentFilePath) + $newPSModulePathSplit
$newPSModulePath = $newPSModulePathSplit -join [io.Path]::PathSeparator
Set-PSModulePath -Path $newPSModulePath
if ($TestType -in ('Integration', 'All'))
{
<#
Making sure setting up the LCM & Machine Path makes sense...
$PSEdition does not exist prior to PS5.1 so we need to evaluate the
version in $PSVersionTable too.
#>
if (($IsWindows -or $PSEdition -eq 'Desktop' -or $PSVersionTable.PSVersion -lt [System.Version] '5.1') -and
($Principal = [Security.Principal.WindowsPrincipal]::new([Security.Principal.WindowsIdentity]::GetCurrent())) -and
$Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
)
{
if (!$script:MachineOldPSModulePath)
{
Write-Warning "This will change your Machine Environment Variable"
$script:MachineOldPSModulePath = [System.Environment]::GetEnvironmentVariable('PSModulePath', 'Machine')
}
# Preserve and set the execution policy so that the DSC MOF can be created
$currentMachineExecutionPolicy = Get-ExecutionPolicy -Scope 'LocalMachine'
if ($PSBoundParameters.ContainsKey('MachineExecutionPolicy'))
{
if ($currentMachineExecutionPolicy -ne $MachineExecutionPolicy)
{
Set-ExecutionPolicy -ExecutionPolicy $MachineExecutionPolicy -Scope 'LocalMachine' -Force -ErrorAction Stop
<#
The variable $script:MachineOldExecutionPolicy should
only be set if it has not been set before. If it has been
set before then it means that we have already a value that
has not yet been reverted using Restore-TestEnvironment.
Should only be set after we actually changed the execution
policy because if $script:MachineOldExecutionPolicy is set
to a value `Restore-TestEnvironment` will try to revert
the value.
#>
if ($null -eq $script:MachineOldExecutionPolicy)
{
$script:MachineOldExecutionPolicy = $currentMachineExecutionPolicy
}
$currentMachineExecutionPolicy = $MachineExecutionPolicy
}
}
Write-Verbose -Message ('The machine execution policy is set to ''{0}''' -f $currentMachineExecutionPolicy)
<#
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.
#>
Set-PSModulePath -Path $newPSModulePath -Machine
# Clear the DSC LCM & Configurations
Clear-DscLcmConfiguration
# Setup the Self signed Certificate for Integration tests & get the LCM ready
$null = New-DscSelfSignedCertificate
Initialize-DscTestLcm -DisableConsistency -Encrypt
}
else
{
Write-Warning "Setting up the DSC Integration Test Environment (LCM & Certificate) only works on Windows PS5+ as Admin"
}
}
<#
Preserve and set the execution policy so that the DSC MOF can be created.
`Restore-TestEnvironment` will only revert the value if $oldExecutionPolicy
differ from current execution policy. So we make to always set it to the
current execution policy so that if we don't need to change it then
`Restore-TestEnvironment` will not try to revert the value.
#>
$oldExecutionPolicy = Get-ExecutionPolicy -Scope 'Process'
if ($PSBoundParameters.ContainsKey('ProcessExecutionPolicy'))
{
if ($oldExecutionPolicy -ne $ProcessExecutionPolicy)
{
Set-ExecutionPolicy -ExecutionPolicy $ProcessExecutionPolicy -Scope 'Process' -Force -ErrorAction Stop
}
}
Write-Verbose -Message ('The process execution policy is set to ''{0}''' -f $oldExecutionPolicy)
# Return the test environment
return @{
DSCModuleName = $Module
Module = $ModuleUnderTest
DSCResourceName = $DscResourceName
TestType = $TestType
ImportedModulePath = $moduleToImportFilePath
OldPSModulePath = $oldPSModulePath
OldExecutionPolicy = $oldExecutionPolicy
}
}