From 354c34e19f0f251da6c16c055a137d4fd4a55970 Mon Sep 17 00:00:00 2001 From: Glenn Sarti Date: Thu, 6 Sep 2018 10:10:00 +0800 Subject: [PATCH] (MODULES-7661) Add tests for PowerShell task This commit adds tests for the Invoke-ExecuteTask function. This also includes mocking functions to create objects similar to that returned from the Windows Update Agent API. --- spec/spec_helper.ps1 | 46 +++++++++++++ spec/tasks/update_history.Tests.ps1 | 102 ++++++++++++++++++++++++++++ tasks/update_history.ps1 | 10 ++- 3 files changed, 155 insertions(+), 3 deletions(-) diff --git a/spec/spec_helper.ps1 b/spec/spec_helper.ps1 index 752930e..a06677d 100644 --- a/spec/spec_helper.ps1 +++ b/spec/spec_helper.ps1 @@ -2,3 +2,49 @@ $DebugPreference = "SilentlyContinue" $here = Split-Path -Parent $MyInvocation.MyCommand.Definition $src = Resolve-Path -Path "$($here)\.." +Function New-MockUpdate($UpdateID, $Title) { + $properties = @{ + Operation = Get-Random -Minimum 1 -Maximum 3 + ResultCode = Get-Random -Minimum 0 -Maximum 6 + Date = [DateTime]::Now + UpdateIdentity = @{ + RevisionNumber = Get-Random -Minimum 1 -Maximum 11 + UpdateID = [GUID]::NewGuid().ToString() + } + Title = "Mock Update Title $(Get-Random)" + ServiceID = [GUID]::NewGuid().ToString() + Categories = @() # TODO + HResult = Get-Random -Minimum 0 -Maximum 32768 + Description = "Mock Description $(Get-Random)" + UnmappedResultCode = Get-Random -Minimum 0 -Maximum 32768 + + ClientApplicationID = "Mock ClientApplicationID $(Get-Random)" + ServerSelection = Get-Random -Minimum 0 -Maximum 4 + UninstallationSteps = @("Mock UninstallationStep $(Get-Random)") + UninstallationNotes = "Mock UninstallationNotes $(Get-Random)" + SupportUrl = "Mock SupportUrl $(Get-Random)" + } + + if (-Not [String]::IsNullOrEmpty($UpdateID)) { $properties.UpdateIdentity.UpdateID = $UpdateID} + if (-Not [String]::IsNullOrEmpty($Title)) { $properties.Title = $Title} + + New-Object -TypeName PSObject -Property $properties +} +Function New-MockUpdateSession($UpdateCount = 0, $UpdateObjects = @()) { + $mock = New-Object -TypeName PSObject + + $mock | Add-Member -MemberType NoteProperty -Name MockGetTotalHistoryCount -Value $UpdateCount | Out-Null + + # Create a random update list + $Updates = $UpdateObjects + While ($Updates.Count -lt $UpdateCount) { + $Updates += New-MockUpdate + } + $mock | Add-Member -MemberType NoteProperty -Name MockQueryHistory -Value $Updates | Out-Null + + # The following are methods not a properties and we can't do closures so just mirror the mock properties + $mock | Add-Member -MemberType ScriptMethod -Name GetTotalHistoryCount -Value { $this.MockGetTotalHistoryCount } | Out-Null + $mock | Add-Member -MemberType ScriptMethod -Name QueryHistory -Value { param($start, $count) $this.MockQueryHistory[$start..($start + $count - 1)] } | Out-Null + + Write-Output $mock +} diff --git a/spec/tasks/update_history.Tests.ps1 b/spec/tasks/update_history.Tests.ps1 index 6d720f6..99074c0 100644 --- a/spec/tasks/update_history.Tests.ps1 +++ b/spec/tasks/update_history.Tests.ps1 @@ -59,3 +59,105 @@ Describe 'Convert-ToUpdateOperationString' { Convert-ToUpdateOperationString 2 | Should Be 'Uninstallation' } } + +Describe 'Invoke-ExecuteTask' { + $DefaultExecuteParams = @{ + Detailed = $false; + Title = $null + UpdateID = $null + MaximumUpdates = 300 + } + + It 'should return empty JSON if no history' { + Mock Get-UpdateSessionObject { New-MockUpdateSession 0 } + + $Result = Invoke-ExecuteTask @DefaultExecuteParams | ConvertFrom-JSON + $Result | Should -HaveCount 0 + } + + It 'should return a JSON array for a single element' { + Mock Get-UpdateSessionObject { New-MockUpdateSession 1 } + + $ResultJSON = Invoke-ExecuteTask @DefaultExecuteParams + $ResultJSON | Should -Match "^\[" + $ResultJSON | Should -Match "\]$" + + $Result = $ResultJSON | ConvertFrom-JSON + $Result | Should -HaveCount 1 + } + + It 'should not return detailed information when Detailed specified as false' { + Mock Get-UpdateSessionObject { New-MockUpdateSession 1 } + $ExecuteParams = $DefaultExecuteParams.Clone() + $ExecuteParams.Detailed = $false + + $Result = Invoke-ExecuteTask @ExecuteParams | ConvertFrom-JSON + $Result | Should -HaveCount 1 + $Result[0].HResult | Should -BeNullOrEmpty + $Result[0].Description | Should -BeNullOrEmpty + $Result[0].UnmappedResultCode | Should -BeNullOrEmpty + $Result[0].ClientApplicationID | Should -BeNullOrEmpty + $Result[0].ServerSelection | Should -BeNullOrEmpty + $Result[0].UninstallationSteps | Should -BeNullOrEmpty + $Result[0].UninstallationNotes | Should -BeNullOrEmpty + $Result[0].SupportUrl | Should -BeNullOrEmpty + $Result[0].UnmappedResultCode | Should -BeNullOrEmpty + $Result[0].UnmappedResultCode | Should -BeNullOrEmpty + } + + It 'should return detailed information when Detailed specified as true' { + Mock Get-UpdateSessionObject { New-MockUpdateSession 1 } + $ExecuteParams = $DefaultExecuteParams.Clone() + $ExecuteParams.Detailed = $true + + $Result = Invoke-ExecuteTask @ExecuteParams | ConvertFrom-JSON + $Result | Should -HaveCount 1 + $Result[0].HResult | Should -Not -BeNullOrEmpty + $Result[0].Description | Should -Not -BeNullOrEmpty + $Result[0].UnmappedResultCode | Should -Not -BeNullOrEmpty + $Result[0].ClientApplicationID | Should -Not -BeNullOrEmpty + $Result[0].ServerSelection | Should -Not -BeNullOrEmpty + $Result[0].UninstallationSteps | Should -Not -BeNullOrEmpty + $Result[0].UninstallationNotes | Should -Not -BeNullOrEmpty + $Result[0].SupportUrl | Should -Not -BeNullOrEmpty + $Result[0].UnmappedResultCode | Should -Not -BeNullOrEmpty + $Result[0].UnmappedResultCode | Should -Not -BeNullOrEmpty + } + + It 'should return only the maximum number of updates when specified' { + Mock Get-UpdateSessionObject { New-MockUpdateSession 20 } + $ExecuteParams = $DefaultExecuteParams + $ExecuteParams.MaximumUpdates = 5 + + $Result = Invoke-ExecuteTask @ExecuteParams | ConvertFrom-JSON + $Result | Should -HaveCount 5 + } + + It 'should return a single update when UpdateID is specified' { + $UpdateGUID = [GUID]::NewGuid().ToString() + $UpdateObject = New-MockUpdate -UpdateID $UpdateGUID + Mock Get-UpdateSessionObject { New-MockUpdateSession 10 @($UpdateObject) } + $ExecuteParams = $DefaultExecuteParams.Clone() + $ExecuteParams.UpdateID = $UpdateGUID + + $Result = Invoke-ExecuteTask @ExecuteParams | ConvertFrom-JSON + $Result | Should -HaveCount 1 + } + + It 'should return a matching updates when Title is specified' { + $UpdateObjects = @( + New-MockUpdate -Title 'asserttitle' + New-MockUpdate -Title 'zzAssertTitlezz' + ) + Mock Get-UpdateSessionObject { New-MockUpdateSession 10 $UpdateObjects } + $ExecuteParams = $DefaultExecuteParams.Clone() + $ExecuteParams.Title = 'AssertTitle' + + $Result = Invoke-ExecuteTask @ExecuteParams | ConvertFrom-JSON + $Result | Should -HaveCount 2 + + $UpdateTitles = $Result | ForEach-Object { Write-Output $_.Title } + $UpdateTitles | Should -Contain 'asserttitle' + $UpdateTitles | Should -Contain 'zzAssertTitlezz' + } +} diff --git a/tasks/update_history.ps1 b/tasks/update_history.ps1 index 64f1571..7214fe7 100644 --- a/tasks/update_history.ps1 +++ b/tasks/update_history.ps1 @@ -65,9 +65,13 @@ Function Convert-ToUpdateOperationString($value) { } } -Function Invoke-ExecuteTask() { +Function Get-UpdateSessionObject() { $Session = New-Object -ComObject "Microsoft.Update.Session" - $Searcher = $Session.CreateUpdateSearcher() + Write-Output $Session.CreateUpdateSearcher() +} + +Function Invoke-ExecuteTask($Detailed, $Title, $UpdateID, $MaximumUpdates) { + $Searcher = Get-UpdateSessionObject # Returns IUpdateSearcher https://msdn.microsoft.com/en-us/library/windows/desktop/aa386515(v=vs.85).aspx $historyCount = $Searcher.GetTotalHistoryCount() @@ -109,4 +113,4 @@ Function Invoke-ExecuteTask() { } | ConvertTo-JSON } -if (-Not $NoOperation) { Invoke-ExecuteTask } +if (-Not $NoOperation) { Invoke-ExecuteTask -Detailed $Detailed -Title $Title -UpdateID $UpdateID -MaximumUpdates $MaximumUpdates }