# Windows Server Backup collector, against collectors/wsb/tests/MockWsb.ps1 (shapes from a Server # 2019 Hyper-V host: job times are culture-formatted local-time strings, HRESULTs are strings, # VMs are nested under a VirtualMachineList item). BeforeAll { Import-Module (Join-Path $PSScriptRoot 'TestHelpers.psm1') -Force $now = Set-MockNow $config = @{ ApiUrl = 'http://localhost:1'; ApiKey = 'bdk_x'; Tenant = 'Acme' } $vms = @('AAOG-EDM-AD1', 'Host Component') $hostComponentBytes = 447729 } Describe 'Windows Server Backup collector' { Context 'what it reports (dry run)' { BeforeAll { $r = Invoke-Collector wsb -Config $config -DryRun $runs = @($r.Reports | Where-Object run | ForEach-Object run) $byStart = @{} foreach ($run in $runs) { $byStart[$run.started_at] = $run } function At([double]$HoursAgo) { $byStart[(ConvertTo-ApiTime $now.AddHours(-$HoursAgo))] } } It 'runs cleanly' { $r.ExitCode | Should -Be 0 $r.Log[-1] | Should -Be '[INFO] Reported 4 runs, 0 failures' } It 'reports the server as one job, with the next backup from Get-WBSummary' { $r.Reports.job.external_id | Select-Object -Unique | Should -Be 'wsb:srv01' $r.Reports.job.name | Select-Object -Unique | Should -Be 'SRV01 - Windows Server Backup' $r.Reports.source_system | Select-Object -Unique | Should -Be 'Windows Server Backup' $next = $now.Date.AddHours(21).AddDays($(if ($now.Hour -ge 21) { 1 } else { 0 })) $r.Reports[0].job.next_run_at | Should -Be (ConvertTo-ApiTime $next) } It 'reads job times as local time, and sends no run ID (WSB jobs have none; the API keys on start time)' { (At 12).finished_at | Should -Be (ConvertTo-ApiTime $now.AddHours(-11.6)) $runs | ForEach-Object { $_.PSObject.Properties.Name | Should -Not -Contain 'external_id' } } It 'reports a Hyper-V backup with its VMs (nested in VirtualMachineList) and size' { $run = At 12 $run.status | Should -Be 'success' $run.message | Should -Be 'Backup completed successfully.' $run.details.items | Should -Be $vms $run.size_bytes | Should -Be (124756706036 + $hostComponentBytes) } It "doesn't cite the failure log for a success (WSB fills it in regardless)" { (At 12).message | Should -Not -BeLike '*Failure log*' } It 'reports a backup where one VM failed as a warning, naming the VM' { $run = At 36 $run.status | Should -Be 'warning' $run.message | Should -BeLike '*AAOG-EDM-AD1 - Access is denied.*' $run.message | Should -BeLike '*Failure log: C:\Windows\Logs\WindowsServerBackup\Backup_Error.log*' } It 'reports a backup with an error HRESULT as failed, with the code in 0x8 form' { $run = At 30 $run.status | Should -Be 'failed' $run.message | Should -BeLike '*The backup storage location could not be found.*' $run.message | Should -BeLike '*error 0x80042302*' } It 'reports a volume backup with its volumes and size' { $run = At 20 $run.status | Should -Be 'success' $run.details.items | Should -Be @('C:', 'D:') $run.size_bytes | Should -Be (240GB) } It "ignores restores, old backups, and Get-WBJob's empty job when nothing is running" { $runs.Count | Should -Be 4 } It 'reads dd/MM dates correctly on servers with other regional settings' { $gb = Invoke-Collector wsb -Config $config -DryRun -Culture 'en-GB' ($gb.Reports | ConvertTo-Json -Depth 6) | Should -Be ($r.Reports | ConvertTo-Json -Depth 6) } It 'reports a backup in progress as running, with no message' { $running = Invoke-Collector wsb -Config $config -DryRun -MockArgs '-WithRunningJob' $run = $running.Reports | Where-Object { $_.run.status -eq 'running' } | ForEach-Object run $run.started_at | Should -Be (ConvertTo-ApiTime $now.AddMinutes(-10)) $run.message | Should -Be '' $run.PSObject.Properties.Name | Should -Not -Contain 'finished_at' $run.details.items | Should -Be $vms } } Context 'sending to the API' { BeforeAll { $stub = Start-ApiStub $live = $config.Clone(); $live.ApiUrl = $stub.Url $first = Invoke-Collector wsb -Config $live -MockArgs '-WithRunningJob' $firstRequests = Get-StubRequests $stub $second = Invoke-Collector wsb -Config $live -WorkDir $first.WorkDir -MockArgs '-RunningJobFinished' $secondRequests = Get-StubRequests $stub } AfterAll { Stop-ApiStub $stub } It 'sends every run, remembering the finished ones' { $first.ExitCode | Should -Be 0 $firstRequests.Count | Should -Be 5 $first.State.Count | Should -Be 4 } It 'sends the finished backup once it ends, with the same start time, so the API merges it into the running one' { $running = $firstRequests.Payload.run | Where-Object status -EQ 'running' $secondRequests.Count | Should -Be 1 $finished = $secondRequests[0].Payload.run $finished.status | Should -Be 'success' $finished.started_at | Should -Be $running.started_at $second.State.Count | Should -Be 5 } } }