Tests/Unit/MSFT_xServiceResource.Tests.ps1
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] param () Import-Module "$PSScriptRoot\..\..\DSCResource.Tests\TestHelper.psm1" -Force $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName 'xPSDesiredStateConfiguration' ` -DSCResourceName 'MSFT_xServiceResource' ` -TestType Unit InModuleScope 'MSFT_xServiceResource' { Describe 'xService Unit Tests' { BeforeAll { Import-Module "$PSScriptRoot\..\CommonTestHelper.psm1" -Force Import-Module "$PSScriptRoot\..\MSFT_xServiceResource.TestHelper.psm1" -Force $script:getTargetResourceResultProperties = @('Name', 'StartupType', 'DisplayName', 'Description', 'State', 'Path', 'Dependencies') $script:testServiceName = "DscTestService" $script:testServiceCodePath = "$PSScriptRoot\..\DscTestService.cs" $script:testServiceDisplayName = "DSC test service display name" $script:testServiceDescription = "This is DSC test service used for testing ServiceSet composite resource" $script:testServiceDependsOn = "winrm" $script:testServiceExecutablePath = Join-Path -Path (Get-Location) -ChildPath "DscTestService.exe" Stop-Service $script:testServiceName -ErrorAction SilentlyContinue New-TestService ` -ServiceName $script:testServiceName ` -ServiceCodePath $script:testServiceCodePath ` -ServiceDisplayName $script:testServiceDisplayName ` -ServiceDescription $script:testServiceDescription ` -ServiceDependsOn $script:testServiceDependsOn ` -ServiceExecutablePath $script:testServiceExecutablePath } AfterAll { Remove-TestService -ServiceName $script:testServiceName -ServiceExecutablePath $script:testServiceExecutablePath } BeforeEach { Set-TargetResource ` -Name $script:testServiceName ` -DisplayName $script:testServiceDisplayName ` -Description $script:testServiceDescription ` -Path $script:testServiceExecutablePath ` -Dependencies $script:testServiceDependsOn ` -BuiltInAccount 'LocalSystem' ` -State 'Stopped' ` -StartupType 'Manual' } AfterEach { Set-TargetResource -Name $script:testServiceName -Ensure 'Absent' } Context 'Get-TargetResource' { It 'Should return the correct hashtable properties' { $getTargetResourceResult = Get-TargetResource -Name $script:testServiceName Test-GetTargetResourceResult -GetTargetResourceResult $getTargetResourceResult -GetTargetResourceResultProperties $script:getTargetResourceResultProperties $getTargetResourceResult.Name | Should Be $script:testServiceName $getTargetResourceResult.StartupType | Should Be 'Manual' $getTargetResourceResult.DisplayName | Should Be $script:testServiceDisplayName $getTargetResourceResult.Description | Should Be $script:testServiceDescription $getTargetResourceResult.State | Should Be 'Stopped' $getTargetResourceResult.Path.IndexOf($script:testServiceName, [System.StringComparison]::OrdinalIgnoreCase) | Should Not Be -1 $getTargetResourceResult.Dependencies | Should Be $script:testServiceDependsOn } It 'Should throw with an invalid service name'{ { Get-TargetResource -Name "NotAService" } | Should Throw } } Context 'Set-TargetResource' { It 'Should set the correct state' { Set-TargetResource -Name $script:testServiceName $getTargetResourceResult = Get-TargetResource $script:testServiceName $getTargetResourceResult.State | Should Be 'Running' Set-TargetResource -Name $script:testServiceName -State 'Stopped' $getTargetResourceResult = Get-TargetResource $script:testServiceName $getTargetResourceResult.State | Should Be 'Stopped' } It 'Should provide correct verbose output when setting State to Running with the service already started' { Set-TargetResource -Name $script:testServiceName $verboseFilePath = Join-Path -Path (Get-Location) -ChildPath 'SetTargetResourceRunningTestVerboseOutput.txt' if (Test-Path $verboseFilePath) { Remove-Item $verboseFilePath -ErrorAction SilentlyContinue } try { Set-TargetResource -Name $script:testServiceName -Verbose 4> $verboseFilePath $actualVerboseOutput = (Get-Content -Path $verboseFilePath -Raw).Trim().Replace("`r`n", "").Replace("`n", "") $expectedVerboseOutputWritePropertiesIgnored = $serviceLocalizedData.WritePropertiesIgnored -f $script:testServiceName $expectedVerboseOutputServiceAlreadyStarted = $serviceLocalizedData.ServiceAlreadyStarted -f $script:testServiceName $actualVerboseOutput.Contains($expectedVerboseOutputWritePropertiesIgnored) | Should Be $true $actualVerboseOutput.Contains($expectedVerboseOutputServiceAlreadyStarted) | Should Be $true } finally { if (Test-Path $verboseFilePath) { Remove-Item $verboseFilePath -ErrorAction SilentlyContinue } } } It 'Should provide correct verbose output when setting State to Stopped with the service already stopped' { Set-TargetResource -Name $script:testServiceName -State 'Stopped' $verboseFilePath = Join-Path -Path (Get-Location) -ChildPath 'SetTargetResourceStoppedTestVerboseOutput.txt' if (Test-Path $verboseFilePath) { Remove-Item $verboseFilePath -ErrorAction SilentlyContinue } try { Set-TargetResource -Name $script:testServiceName -State 'Stopped' -Verbose 4> $verboseFilePath $actualVerboseOutput = (Get-Content -Path $verboseFilePath -Raw).Trim().Replace("`r`n", "").Replace("`n", "") $expectedVerboseOutputWritePropertiesIgnored = $serviceLocalizedData.WritePropertiesIgnored -f $script:testServiceName $expectedVerboseOutputServiceAlreadyStopped = $serviceLocalizedData.ServiceAlreadyStopped -f $script:testServiceName $actualVerboseOutput.Contains($expectedVerboseOutputWritePropertiesIgnored) | Should Be $true $actualVerboseOutput.Contains($expectedVerboseOutputServiceAlreadyStopped) | Should Be $true } finally { if (Test-Path $verboseFilePath) { Remove-Item $verboseFilePath -ErrorAction SilentlyContinue } } } It 'Should throw when setting State to Stopped and StartupType to Automatic' { Set-TargetResource -Name $script:testServiceName { Set-TargetResource -Name $script:testServiceName -State 'Stopped' -StartupType 'Automatic' } | Should Throw } It 'Should throw when setting State to Running and StartupType to Disabled' { Set-TargetResource -Name $script:testServiceName -State 'Stopped' { Set-TargetResource -Name $script:testServiceName -StartupType 'Disabled' } | Should Throw } It 'Should throw when both BuiltInAccount and Credential specified' { $testUsername = 'username' $testPassword = 'password' $secureTestPassword = ConvertTo-SecureString $testPassword -AsPlainText -Force $testCredential = New-Object System.Management.Automation.PSCredential ($testUsername, $secureTestPassword) { Set-TargetResource -Name $script:testServiceName -BuiltInAccount 'LocalService' -Credential $testCredential } | Should Throw } It 'Should correctly change StartupType' { Set-TargetResource -Name $script:testServiceName -State 'Stopped' -StartupType 'Disabled' $getTargetResourceResult = Get-TargetResource -Name $script:testServiceName $getTargetResourceResult.StartupType | Should Be "Disabled" Set-TargetResource -Name $script:testServiceName -State 'Stopped' -StartupType 'Manual' $getTargetResourceResult = Get-TargetResource -Name $script:testServiceName $getTargetResourceResult.StartupType | Should Be "Manual" } It 'Should correctly change BuiltInAccount' { Set-TargetResource -Name $script:testServiceName -State 'Stopped' -BuiltInAccount 'NetworkService' $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -State 'Stopped' -BuiltInAccount 'NetworkService' $testTargetResourceResult | Should Be $true Set-TargetResource -Name $script:testServiceName -State 'Stopped' -BuiltInAccount 'LocalService' $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -State 'Stopped' -BuiltInAccount 'LocalService' $testTargetResourceResult | Should Be $true Set-TargetResource -Name $script:testServiceName -State 'Stopped' -BuiltInAccount 'LocalSystem' $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -State 'Stopped' -BuiltInAccount 'LocalSystem' $testTargetResourceResult | Should Be $true } It 'Should throw when trying to set an invalid credential' { $testUsername = 'username' $testPassword = 'password' $secureTestPassword = ConvertTo-SecureString $testPassword -AsPlainText -Force $testCredential = New-Object System.Management.Automation.PSCredential ($testUsername, $secureTestPassword) { Set-TargetResource -Name $script:testServiceName -State 'Stopped' -Credential $testCredential } | Should Throw } It 'Should output correct description and not start a stopped service when WhatIf is specified' { Set-TargetResource -Name $script:testServiceName -State 'Stopped' $transcriptPath = Join-Path -Path (Get-Location) -ChildPath 'WhatIfTestTranscript.txt' if (Test-Path $transcriptPath) { Wait-ScriptBlockReturnTrue -ScriptBlock {-not (Test-IsFileLocked -Path $transcriptPath)} Remove-Item $transcriptPath } try { Wait-ScriptBlockReturnTrue -ScriptBlock {-not (Test-IsFileLocked -Path $transcriptPath)} Start-Transcript -Path $transcriptPath Set-TargetResource -Name $script:testServiceName -WhatIf Stop-Transcript Wait-ScriptBlockReturnTrue -ScriptBlock {-not (Test-IsFileLocked -Path $transcriptPath)} $transcriptContent = Get-Content -Path $transcriptPath -Raw $transcriptContent | Should Not Be $null $expectedTranscriptMessage = $LocalizedData.StartServiceWhatIf -f $script:testServiceName $transcriptContent = $transcriptContent.Replace("`r`n", "").Replace("`n", "") $transcriptContent.Contains($expectedTranscriptMessage) | Should Be $true $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -State 'Stopped' $testTargetResourceResult | Should Be $true } finally { if (Test-Path $transcriptPath) { Wait-ScriptBlockReturnTrue -ScriptBlock {-not (Test-IsFileLocked -Path $transcriptPath)} Remove-Item $transcriptPath } } } It 'Should output correct description and not stop a started service when WhatIf is specified' { Set-TargetResource -Name $script:testServiceName $transcriptPath = Join-Path -Path (Get-Location) -ChildPath 'WhatIfTestTranscript.txt' if (Test-Path $transcriptPath) { Wait-ScriptBlockReturnTrue -ScriptBlock {-not (Test-IsFileLocked -Path $transcriptPath)} Remove-Item $transcriptPath } try { Wait-ScriptBlockReturnTrue -ScriptBlock {-not (Test-IsFileLocked -Path $transcriptPath)} Start-Transcript -Path $transcriptPath Set-TargetResource -Name $script:testServiceName -State 'Stopped' -WhatIf Stop-Transcript Wait-ScriptBlockReturnTrue -ScriptBlock {-not (Test-IsFileLocked -Path $transcriptPath)} $transcriptContent = Get-Content -Path $transcriptPath -Raw $transcriptContent | Should Not Be $null $expectedTranscriptMessage = $LocalizedData.StopServiceWhatIf -f $script:testServiceName $transcriptContent = $transcriptContent.Replace("`r`n", "").Replace("`n", "") $transcriptContent.Contains($expectedTranscriptMessage) | Should Be $true $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName $testTargetResourceResult | Should Be $true } finally { if (Test-Path $transcriptPath) { Wait-ScriptBlockReturnTrue -ScriptBlock {-not (Test-IsFileLocked -Path $transcriptPath)} Remove-Item $transcriptPath } } } It 'Should throw with invalid service name' { { Set-TargetResource -Name "NotAService" } | Should Throw } It 'Should throw when trying to start a disabled service' { Set-TargetResource -Name $script:testServiceName -State 'Stopped' -StartupType 'Disabled' { Set-TargetResource -Name $script:testServiceName } | Should Throw } } Context 'Test-TargetResource' { It 'Should return correct value based on State' { Set-TargetResource -Name $script:testServiceName $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName $testTargetResourceResult | Should Be $true $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -State 'Stopped' $testTargetResourceResult | Should Be $false Set-TargetResource -Name $script:testServiceName -State 'Stopped' $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName $testTargetResourceResult | Should Be $false $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -State 'Stopped' $testTargetResourceResult | Should Be $true } It 'Should return true with the Automatic StartupType' { Set-TargetResource -Name $script:testServiceName -StartupType 'Automatic' $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -StartupType 'Automatic' $testTargetResourceResult | Should Be $true } It 'Should return true with the Manual StartupType' { Set-TargetResource -Name $script:testServiceName -StartupType 'Manual' $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -StartupType 'Manual' $testTargetResourceResult | Should Be $true } It 'Should return true with the Disabled StartupType' { Set-TargetResource -Name $script:testServiceName -State 'Stopped' -StartupType 'Disabled' $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -State 'Stopped' -StartupType 'Disabled' $testTargetResourceResult | Should Be $true } It 'Should return false with different StartType' { Set-TargetResource -Name $script:testServiceName $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -StartupType 'Automatic' $testTargetResourceResult | Should Be $false } It 'Should return false with different BuiltInAccount' { Set-TargetResource -Name $script:testServiceName $testTargetResourceResult = Test-TargetResource -Name $script:testServiceName -BuiltInAccount NetworkService $testTargetResourceResult | Should Be $false } It 'Should return false with invalid service name' { Test-TargetResource -Name "NotAService" | Should Be $false } } Context 'Set-ServiceStartupType' { It 'Should throw with invalid StartupType' { $win32ServiceObject = Get-Win32ServiceObject -Name $script:testServiceName { Set-ServiceStartupType -Win32ServiceObject $win32ServiceObject -StartupType "NotAStartupValue" } | Should Throw } } } } |