AutomatedLabTest.psm1
function Invoke-LabScript { [CmdletBinding()] param ( [Parameter(Mandatory)] [string]$Path, [hashtable]$Replace ) $result = New-Object PSObject -Property ([ordered]@{ ScriptName = Split-Path -Path $Path -Leaf Completed = $false ErrorCount = 0 Errors = $null ScriptFullName = $Path Output = $null RemoveErrors = $null }) $result.PSObject.TypeNames.Insert(0, 'AutomatedLab.TestResult') Write-PSFMessage -Level Host "Invoking script '$Path'" Write-PSFMessage -Level Host '-------------------------------------------------------------' try { Clear-Host $content = Get-Content -Path $Path -Raw foreach ($element in $Replace.GetEnumerator()) { $content = $content -replace $element.Key, $element.Value } $content = [scriptblock]::Create($content) Invoke-Command -ScriptBlock $content -ErrorVariable invokeError $result.Errors = $invokeError $result.Completed = $true } catch { Write-Error -Exception $_.Exception -Message "Error invoking the script '$Path': $($_.Exception.Message)" $result.Errors = $_ $result.Completed = $false } finally { Start-Sleep -Seconds 1 $result.Output = Get-ConsoleText $result.ErrorCount = $result.Errors.Count Clear-Host if (Get-Lab -ErrorAction SilentlyContinue) { Remove-Lab -Confirm:$false -ErrorVariable removeErrors } $result.RemoveErrors = $removeErrors Write-PSFMessage -Level Host '-------------------------------------------------------------' Write-PSFMessage -Level Host "Finished invkoing script '$Path'" $result } } function Import-LabTestResult { [CmdletBinding(DefaultParameterSetName = 'Path')] param( [Parameter(ParameterSetName = 'Single')] [string[]]$Path, [Parameter(ParameterSetName = 'Path')] [string]$LogDirectory = [System.Environment]::GetFolderPath('MyDocuments') ) if ($PSCmdlet.ParameterSetName -eq 'Single') { if (-not (Test-Path -Path $Path -PathType Leaf)) { Write-Error "The file '$Path' could not be found" return } $result = Import-Clixml -Path $Path $result.PSObject.TypeNames.Insert(0, 'AutomatedLab.TestResult') $result } elseif ($PSCmdlet.ParameterSetName -eq 'Path') { $files = Get-Item -Path "$LogDirectory\*" -Filter *.xml foreach ($file in ($files | Where-Object { $_ -match $testResultPattern })) { $result = Import-Clixml -Path $file.FullName $result.PSObject.TypeNames.Insert(0, 'AutomatedLab.TestResult') $result } } } function Invoke-LabPester { [CmdletBinding(DefaultParameterSetName = 'ByLab')] param ( [Parameter(Mandatory, ParameterSetName = 'ByLab', ValueFromPipeline)] [AutomatedLab.Lab] $Lab, [Parameter(Mandatory, ParameterSetName = 'ByName', ValueFromPipeline)] [string] $LabName, [ValidateSet('None', 'Normal', 'Detailed' , 'Diagnostic')] $Show = 'None', [switch] $PassThru, [string] $OutputFile ) process { if (-not $Lab) { $Lab = Import-Lab -Name $LabName -ErrorAction Stop -NoDisplay -NoValidation -PassThru } $global:pesterLab = $Lab # No parameters in Pester v5 yet $configuration = [PesterConfiguration]::Default $configuration.Run.Path = Join-Path -Path $PSCmdlet.MyInvocation.MyCommand.Module.ModuleBase -ChildPath 'tests' $configuration.Run.PassThru = $PassThru.IsPresent [string[]]$tags = 'General' if ($Lab.Machines.Roles.Name) { $tags += $Lab.Machines.Roles.Name } if ($Lab.Machines.PostInstallationActivity | Where-Object IsCustomRole) { $tags += ($Lab.Machines.PostInstallationActivity | Where-Object IsCustomRole).RoleName } if ($Lab.Machines.PreInstallationActivity | Where-Object IsCustomRole) { $tags += ($Lab.Machines.PreInstallationActivity | Where-Object IsCustomRole).RoleName } $configuration.Filter.Tag = $tags $configuration.Should.ErrorAction = 'Continue' $configuration.TestResult.Enabled = $true if ($OutputFile) { $configuration.TestResult.OutputPath = $OutputFile } $configuration.Output.Verbosity = $Show Invoke-Pester -Configuration $configuration Remove-Variable -Name pesterLab -Scope Global } } function New-LabPesterTest { [CmdletBinding()] param ( [Parameter(Mandatory)] [string[]] $Role, [Parameter(Mandatory)] [string] $Path, [Parameter()] [switch] $IsCustomRole ) foreach ($r in $Role) { $line = if ($IsCustomRole.IsPresent) { "(Get-LabVM).Where({`$_.PreInstallationActivity.Where({`$_.IsCustomRole}).RoleName -contains '$r' -or `$_.PostInstallationActivity.Where({`$_.IsCustomRole}).RoleName -contains '$r'})" } else { "(Get-LabVm -Role $r).Count | Should -Be `$(Get-Lab).Machines.Where({`$_.Roles.Name -contains '$r'}).Count" } $fileContent = @" Describe "[`$((Get-Lab).Name)] $r" -Tag $r { Context "Role deployment successful" { It "[$r] Should return the correct amount of machines" { $line } } } "@ if (Test-Path -Path (Join-Path -Path $Path -ChildPath "$r.tests.ps1")) { continue } Set-Content -Path (Join-Path -Path $Path -ChildPath "$r.tests.ps1") -Value $fileContent } } function Test-LabDeployment { [CmdletBinding()] param( [Parameter(ParameterSetName = 'Path')] [string[]]$Path, [Parameter(ParameterSetName = 'All')] [string]$SampleScriptsPath, [Parameter(ParameterSetName = 'All')] [string]$Filter, [Parameter(ParameterSetName = 'All')] [switch]$All, [string]$LogDirectory = [System.Environment]::GetFolderPath('MyDocuments'), [hashtable]$Replace = @{} ) $global:AL_TestMode = 1 #this variable is set to skip the 2nd question when deleting Azure services if ($PSCmdlet.ParameterSetName -eq 'Path') { foreach ($p in $Path) { if (-not (Test-Path -Path $p -PathType Leaf)) { Write-Error "The file '$p' could not be found" return } $result = Invoke-LabScript -Path $p -Replace $Replace $fileName = Join-Path -Path $LogDirectory -ChildPath ("{0:yyMMdd_hhmm}_$([System.IO.Path]::GetFileNameWithoutExtension($p))_Log.xml" -f (Get-Date)) $result | Export-Clixml -Path $fileName $result } } elseif ($PSCmdlet.ParameterSetName -eq 'All') { if (-not (Test-Path -Path $SampleScriptsPath -PathType Container)) { Write-Error "The directory '$SampleScriptsPath' could not be found" return } if (-not $Filter) { $Filter = '*.ps1' } $scripts = Get-ChildItem -Path $SampleScriptsPath -Filter $Filter -Recurse foreach ($script in $scripts) { $result = Invoke-LabScript -Path $script.FullName -Replace $Replace $fileName = Join-Path -Path $LogDirectory -ChildPath ("{0:yyMMdd_hhmm}_$([System.IO.Path]::GetFileNameWithoutExtension($script))_Log.xml" -f (Get-Date)) $result | Export-Clixml -Path $fileName $result } } $global:AL_TestMode = 0 } |