windows/test/PSRemoteOperations.Tests.ps1
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingComputerNameHardcoded', '')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingConvertToSecureStringwithPlainText', '')] Param() $moduleName = (Get-Item -path $PSScriptRoot).Parent.Name $ModuleManifestName = "$modulename.psd1" $ModuleManifestPath = "$PSScriptRoot\..\$ModuleManifestName" import-module $ModuleManifestPath -Force Describe $ModuleName { $myModule = Test-ModuleManifest -Path $ModuleManifestPath Context Manifest { It 'Passes Test-ModuleManifest' { $myModule | Should Not BeNullOrEmpty } It "Should have a root module" { $myModule.RootModule | Should Not BeNullOrEmpty } It "Contains exported commands" { $myModule.ExportedCommands | Should Not BeNullOrEmpty } It "Should have a module description" { $myModule.Description | Should Not BeNullOrEmpty } It "Should have a company" { $myModule.Description | Should Not BeNullOrEmpty } It "Should have an author of 'Jeff Hicks'" { $mymodule.Author | Should Be 'Jeff Hicks' } It "Should have tags" { $mymodule.Tags | Should Not BeNullOrEmpty } It "Should have a license URI" { $mymodule.LicenseUri | should Not BeNullOrEmpty } It "Should have a project URI" { $mymodule.ProjectUri | Should Not BeNullOrEmpty } } Context Exports { $exported = Get-Command -Module $ModuleName -CommandType Function $names = 'New-PSRemoteOperation', 'Invoke-PSRemoteOperation', 'Get-PSRemoteOperationResult', 'Register-PSRemoteOperationWatcher' It "Should export $($names.count) functions" { $names.Count -eq $exported.count | Should be $True } foreach ($name in $names) { It "Should have an exported command of $name" { $exported.name | Should Contain $name } } $aliasHash = @{ nro = "New-PSRemoteOperation" iro = "Invoke-PSRemoteOperation" row = "Register-PSRemoteOperationWatcher" gro = "Get-PSRemoteOperationResult" } $aliasHash.GetEnumerator() | foreach-object { It "Should have an alias of $($_.key)" { (Get-Alias -Name $_.key).ResolvedCommandName | Should be $_.value } } It "Should create a RemoteOpResults type extension" { Get-TypeData RemoteOpResult | Should be $True } } Context Structure { It "Should have a Docs folder" { Get-Item $PSScriptRoot\..\docs | Should Be $True } foreach ($cmd in $myModule.ExportedFunctions.keys) { It "Should have a markdown help file for $cmd" { "$PSScriptRoot\..\docs\$cmd.md" | Should Exist } } It "Should have an external help file" { "$PSScriptRoot\..\en-us\*.xml" | Should Exist "$PSScriptRoot\..\en-us\*.txt" | Should Exist } It "Should have an about file" { "$PSScriptRoot\..\docs\about_$ModuleName.md"| Should Exist } It "Should have a license file" { "$PSScriptRoot\..\license.*" | Should Exist } It "Should have a changelog file" { "$PSScriptRoot\..\changelog*" | Should Exist } It "Should have a README.md file" { "$PSScriptRoot\..\README.md" | Should Exist } } } -Tag module InModuleScope PSRemoteOperations { Describe New-PSRemoteOperation { $params = (Get-Command New-PSRemoteOperation).parameters It "Should have a mandatory Computername parameter" { ($params["computername"].attributes).where( {$_.TypeId -match 'parameter'}).Mandatory | Should Be $True } It "Should have a mandatory ScriptBlock or ScriptPath parameter" { ($params["scriptblock"].attributes).where( {$_.TypeId -match 'parameter'}).Mandatory | Should Be $True ($params["scriptpath"].attributes).where( {$_.TypeId -match 'parameter'}).Mandatory | Should Be $True } It "Should create a psd1 file" { {New-PSRemoteOperation -Computername Foo -Path TestDrive:\ -Scriptblock {1}} | Should Not Throw Test-Path TestDrive:\foo*.psd1 | Should be $True #Should have a filename using the pattern computername_guid.psd1" $guidrx = "[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}" $template = "foo_$guidrx.psd1" (Get-Item Testdrive:\*.psd1).name -match $Template | Should be $True #get the file contents to use in the next set of tests $script:in = Import-PowerShellDataFile Testdrive:\foo_*.psd1 } It "Should create a file with a Computername value of Foo" { $script:in.Computername | Should Be "Foo" } It "Should have a Scriptblock value of 1" { $script:in.Scriptblock | Should be 1 } It "Should have a UTC CreatedAt value" { $script:in.CreatedAt -match "UTC" | Should be $true $script:in.CreatedAt -match $(get-date -format MM/dd/yyyy) | Should be $true } It "Should accept multiple computernames" { $files = New-PSRemoteOperation -Computername Foo1,Foo2,Foo3 -Path TestDrive:\ -Scriptblock {Get-Volume C:} -Passthru $files.count | Should Be 3 } } -tag command Describe Invoke-PSRemoteOperation { New-PSRemoteOperation -Computername $env:computername -Path TestDrive: -Scriptblock {Get-Service bits} New-Item -path TestDrive:\ -Name Archive -ItemType directory Context Input { $params = (Get-Command Invoke-PSRemoteOperation).parameters It "Should have a mandatory Path parameter ending in .psd1" { ($params["Path"].attributes).where( {$_.TypeId -match 'parameter'}).Mandatory | Should Be $True ($params["Path"].attributes).where( {$_.TypeId -match 'pattern'}).regexPattern | Should Be '\.psd1$' } } Context Process { $file = (Get-childitem testdrive:\*.psd1).fullname Mock 'Get-Date' {[datetime]::new(2019, 1, 1)} #I'd like to mock this but there doesn't appear to be a way #Mock New-PSSession {} Mock Convert-Path { $file } Invoke-PSRemoteOperation -Path $file -ArchivePath testdrive:\archive #-Verbose It "Should call Convert-Path" { Assert-MockCalled Convert-Path } It "Should call Get-Date" { Assert-MockCalled Get-Date } #save result for the next set of tests $script:result = Get-ChildItem TestDrive:\archive\*.psd1 $script:rcontent = get-item $script:result | get-content $script:rdata = Import-powershelldatafile $script:result } Context Output { It "Should create an archive file" { $script:result | Should Not BeNullOrEmpty } It "Should show Completed as True" { $script:rdata.Completed | Should be 'True' } It "Should show the local computername" { $script:rdata.Computername | Should be $env:computername } It "Should show the scriptblock" { $script:rdata.Scriptblock.trim() | Should be "Get-Service bits" } It "Should show a date of 01/01/2019" { $script:rdata.Date -match "01\/01\/2019\s(\d{2}:){2}00\sUTC" | Should be $True } } } -tag command Describe Get-PSRemoteOperationResult { #copy the results from an earlier test to avoid duplication New-Item -path TestDrive: -Name Archive -ItemType directory $fake = Join-Path -Path TestDrive:\Archive -ChildPath "$($env:computername)_$(New-guid).psd1" $script:rcontent | Out-File -FilePath $fake $r = Get-PSRemoteOperationResult -ArchivePath $fake It "Should get a result" { $fake | Should Exist $r | Should Not BeNullOrEmpty } It "Should write a RemoteOpResult object" { $r.psobject.typenames[0] | Should Be "RemoteOpResult" } } -tag command Describe Register-PSRemoteOperationWatcher { New-Item -path TestDrive: -Name Archive -ItemType directory Mock New-JobTrigger { [Microsoft.PowerShell.ScheduledJob.ScheduledJobTrigger]::new()} Mock Register-ScheduledJob {} #create a fake credential for the pester test $cred = New-Object PSCredential foo,(ConvertTo-SecureString "password" -AsPlainText -Force) $testparams = @{ Credential = $cred Name = 'TestWatch' Path = 'Testdrive:\' ArchivePath = 'Testdrive:\Archive' } Register-PSRemoteOperationWatcher @testparams It "Should call New-Jobtrigger" { Assert-MockCalled New-JobTrigger } it "Should call Register-ScheduledJob" { Assert-MockCalled Register-ScheduledJob } } -tag command } |