diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..02c481b --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,12 @@ +version: 1.0.{build} + +image: WMF 5 + +install: + - cinst pester + +build: false + +test_script: +# Test with native PS version + - ps: . .\src\Tests\appveyorCITests.ps1 diff --git a/src/Tests/CI/Integration/PoShMon.Notifications.Email/New-EmailBody.Tests.ps1 b/src/Tests/CI/Integration/PoShMon.Notifications.Email/New-EmailBody.Tests.ps1 index 6666004..4e0d73a 100644 --- a/src/Tests/CI/Integration/PoShMon.Notifications.Email/New-EmailBody.Tests.ps1 +++ b/src/Tests/CI/Integration/PoShMon.Notifications.Email/New-EmailBody.Tests.ps1 @@ -5,13 +5,13 @@ Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") Describe "New-EmailBody" { InModuleScope PoShMon { - Mock -CommandName Get-Module -Verifiable -MockWith { - return @( - [pscustomobject]@{ - Version = "1.2.3" - } - ) - } + Mock -CommandName Get-Module -Verifiable -MockWith { + return @( + [pscustomobject]@{ + Version = "1.2.3" + } + ) + } It "Should return a the correct html for given test output" -skip { @@ -77,8 +77,8 @@ Describe "New-EmailBody" { $totalElapsedTime = (Get-Date).Subtract((Get-Date).AddMinutes(-3)) - #$currentVersion = (Get-Module PoShmon).Version.ToString() - $expected = '
 
 

PoShMon Monitoring Report

 
 SharePoint Environment 
 

Test1 (60.00 Seconds)

StateComponent
State 1123
State 2456

Test2 - Failed

An Exception Occurred: System.Exception: Something went wrong

 
 Skipped Tests: SPServerStatus, WindowsServiceState, SPFailingTimerJobs, SPDatabaseHealth, SPSearchHealth, SPDistributedCacheHealth, WebTests
Total Elapsed Time (Seconds): 180.00 (3.00 Minutes)
 
 PoShMon Version 1.2.3 (Version check skipped) 
 

' + $currentVersion = (Get-Module PoShmon).Version.ToString() + $expected = '
 
 

PoShMon Monitoring Report

 
 SharePoint Environment 
 

Grouped Test (60.00 Seconds)

Server 1
 
MessageEvent ID
Message 1123
Message 2456
Server 2
 
MessageEvent ID
Message 3789

Ungrouped Test (60.00 Seconds)

StateComponent
State 1123
State 2456

 
 Skipped Tests: SPServerStatus, WindowsServiceState, SPFailingTimerJobs, SPDatabaseHealth, SPSearchHealth, SPDistributedCacheHealth, WebTests
Total Elapsed Time (Seconds): 180.00 (3.00 Minutes)
 
 PoShMon Version ' + $currentVersion + ' (Version check skipped) 
 

' $actual = New-EmailBody $poShMonConfiguration "All" $testMonitoringOutput $totalElapsedTime @@ -143,7 +143,7 @@ Describe "New-EmailBody" { $totalElapsedTime = (Get-Date).Subtract((Get-Date).AddMinutes(-3)) - $expected = '
 
 

PoShMon Monitoring Report

 
 SharePoint Environment 
 

Grouped Test (60.00 Seconds)

Server 1
 
MessageEvent ID
Message 1123
Message 2456
Server 2
 
MessageEvent ID
Message 3789

Ungrouped Test (60.00 Seconds)

StateComponent
State 1123
State 2456

 
 Skipped Tests: SPServerStatus, WindowsServiceState, SPFailingTimerJobs, SPDatabaseHealth, SPSearchHealth, SPDistributedCacheHealth, WebTests
Total Elapsed Time (Seconds): 180.00 (3.00 Minutes)
 
 PoShMon Version 1.2.3 (Version check skipped) 
 

' + $expected = '
 
 

PoShMon Monitoring Report

 
 SharePoint Environment 
 

Grouped Test (60.00 Seconds)

Server 1
 
MessageEvent ID
Message 1123
Message 2456
Server 2
 
MessageEvent ID
Message 3789

Ungrouped Test (60.00 Seconds)

StateComponent
State 1123
State 2456

 
 Skipped Tests: SPServerStatus, WindowsServiceState, SPFailingTimerJobs, SPDatabaseHealth, SPSearchHealth, SPDistributedCacheHealth, WebTests
Total Elapsed Time (Seconds): 180.00 (3.00 Minutes)
 
 PoShMon Version 1.2.3 (Version check skipped) 
 

' $actual = New-EmailBody $poShMonConfiguration "All" $testMonitoringOutput $totalElapsedTime @@ -189,7 +189,7 @@ Describe "New-EmailBody" { $totalElapsedTime = (Get-Date).Subtract((Get-Date).AddMinutes(-3)) - $expected = '
 
 

PoShMon Monitoring Report

 
 SharePoint Environment 
 

Test1 (60.00 Seconds)

StateComponent
State 1123
State 2456

Test2 - Failed

An Exception Occurred: System.Exception: Something went wrong

 
 Skipped Tests: SPServerStatus, WindowsServiceState, SPFailingTimerJobs, SPDatabaseHealth, SPSearchHealth, SPDistributedCacheHealth, WebTests
Total Elapsed Time (Seconds): 180.00 (3.00 Minutes)
 
 PoShMon Version 1.2.3 (Version check skipped) 
 

' + $expected = '
 
 

PoShMon Monitoring Report

 
 SharePoint Environment 
 

Test1 (60.00 Seconds)

StateComponent
State 1123
State 2456

Test2 - Failed

An Exception Occurred: System.Exception: Something went wrong

 
 Skipped Tests: SPServerStatus, WindowsServiceState, SPFailingTimerJobs, SPDatabaseHealth, SPSearchHealth, SPDistributedCacheHealth, WebTests
Total Elapsed Time (Seconds): 180.00 (3.00 Minutes)
 
 PoShMon Version 1.2.3 (Version check skipped) 
 

' $actual = New-EmailBody $poShMonConfiguration "All" $testMonitoringOutput $totalElapsedTime diff --git a/src/Tests/CI/Unit/PoShMon.Monitoring.OS/Test-ComputerTime.Tests.ps1 b/src/Tests/CI/Unit/PoShMon.Monitoring.OS/Test-ComputerTime.Tests.ps1 index 75db583..22a6093 100644 --- a/src/Tests/CI/Unit/PoShMon.Monitoring.OS/Test-ComputerTime.Tests.ps1 +++ b/src/Tests/CI/Unit/PoShMon.Monitoring.OS/Test-ComputerTime.Tests.ps1 @@ -1,344 +1,290 @@ -$rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve -Remove-Module PoShMon -ErrorAction SilentlyContinue -Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") - -Describe "Test-ComputerTime" { - InModuleScope PoShMon { - - class ServerTimeMock { - [string]$PSComputerName - [datetime]$DateTime - [datetime]$LocalDateTime - [datetime]$LastBootUptime - [int]$Year - [int]$Month - [int]$Day - [int]$Hour - [int]$Minute - [int]$Second - - ServerTimeMock ([string]$NewPSComputerName, [datetime]$NewDateTime, [datetime]$NewLastBootUptime) { - $this.PSComputerName = $NewPSComputerName; - $this.DateTime = $NewDateTime - $this.LocalDateTime = $NewDateTime - $this.LastBootUptime = $NewLastBootUptime - } - - [datetime] ConvertToDateTime([datetime]$something) { - return $something - } -} - - #It "Should throw an exception if no OperatingSystem configuration is set" { - # - # $poShMonConfiguration = New-PoShMonConfiguration { } - # - # { Test-ComputerTime $poShMonConfiguration } | Should throw - #} - - It "Should return a matching output structure" { - - Mock -ModuleName PoShMon Get-WmiObject { - return [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2017, 1, 1, 10, 15, 0)) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem - } - - $actual = Test-ComputerTime $poShMonConfiguration - - $actual.Keys.Count | Should Be 5 - $actual.ContainsKey("NoIssuesFound") | Should Be $true - $actual.ContainsKey("OutputHeaders") | Should Be $true - $actual.ContainsKey("OutputValues") | Should Be $true - $actual.ContainsKey("SectionHeader") | Should Be $true - $actual.ContainsKey("ElapsedTime") | Should Be $true - $headers = $actual.OutputHeaders - $headers.Keys.Count | Should Be 3 - #$values1 = $actual.OutputValues[0] - #$values1.Keys.Count | Should Be 3 - $actual.OutputValues[0].ServerName | Should Be 'Server1' - $actual.OutputValues[0].CurrentTime | Should Be ([datetime]::new(2017, 1, 1, 10, 15, 0)).ToString() - $actual.OutputValues[0].LastBootUptime | Should Be ([datetime]::new(2017, 1, 1, 10, 15, 0)).ToString() - $actual.OutputValues[0].Highlight[0] | Should Be 'CurrentTime' - } - - It "Should write the expected Verbose output" { - - Mock -CommandName Get-WmiObject -MockWith { - return [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - } - - Mock -CommandName Get-Date -MockWith { - Return [datetime]::new(2017, 1, 1, 10, 15, 0) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem - } - - $actual = Test-ComputerTime $poShMonConfiguration -Verbose - $output = $($actual = Test-ComputerTime $poShMonConfiguration -Verbose) 4>&1 - - $output.Count | Should Be 3 - $output[0].ToString() | Should Be "Initiating 'Server Clock Review' Test..." - $output[1].ToString() | Should Be "`tServer1: 10:15 AM" - $output[2].ToString() | Should Be "Complete 'Server Clock Review' Test, Issues Found: No" - - } - - It "Should write the expected Warning output for time difference" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 09, 0), [datetime]::new(2016, 1, 1, 10, 09, 0)) - ) - } - - Mock -CommandName Get-Date -MockWith { - Return [datetime]::new(2017, 1, 1, 10, 15, 0) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem - } - - $actual = Test-ComputerTime $poShMonConfiguration - $output = $($actual = Test-ComputerTime $poShMonConfiguration) 3>&1 - - $output.Count | Should Be 1 - $output[0].ToString() | Should Be "`tDifference (6) is above variance threshold minutes (1)" - } - - It "Should write the expected Warning output for recent reboot" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 09, 0), [datetime]::new(2017, 1, 1, 10, 08, 0)) - ) - } - - Mock -CommandName Get-Date -MockWith { - Return [datetime]::new(2017, 1, 1, 10, 09, 0) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem - } - - $actual = Test-ComputerTime $poShMonConfiguration - $output = $($actual = Test-ComputerTime $poShMonConfiguration) 3>&1 - - $output.Count | Should Be 1 - $output[0].ToString() | Should Be "`tLastBootUptime (01/01/2017 10:08:00) is within the last 15 minutes" - } - - It "Should warn on different server time (to local PoShMon machine)" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', (Get-Date -Year 2017 -Month 1 -Day 1 -Hour 10 -Minute 15).AddMinutes(-6), [datetime]::new(2016, 1, 1, 10, 15, 0)) - ) - } - - Mock -CommandName Get-Date -MockWith { - Return [datetime]::new(2017, 1, 1, 10, 15, 0) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem - } - - $actual = Test-ComputerTime $poShMonConfiguration -WarningAction SilentlyContinue - - $actual.NoIssuesFound | Should Be $false - - $actual.OutputValues.Highlight.Count | Should Be 1 - $actual.OutputValues.Highlight | Should Be "CurrentTime" - } - - It "Should not warn on matching server times" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - ) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem - } - - $actual = Test-ComputerTime $poShMonConfiguration - - $actual.NoIssuesFound | Should Be $true - - $actual.OutputValues.Highlight.Count | Should Be 0 - } - - It "Should not warn on server time differences within default threshold" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 14, 30), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - ) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem - } - - $actual = Test-ComputerTime $poShMonConfiguration - - $actual.NoIssuesFound | Should Be $true - - $actual.OutputValues.Highlight.Count | Should Be 0 - } - - It "Should warn on server times with differences above default threshold" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 12, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - ) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem - } - - $actual = Test-ComputerTime $poShMonConfiguration -WarningAction SilentlyContinue - - $actual.NoIssuesFound | Should Be $false - - $actual.OutputValues.Highlight.Count | Should Be 3 - $actual.OutputValues.Highlight[0] | Should Be "CurrentTime" - } - - It "Should not warn on server time differences within configured threshold" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 09, 48, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server4', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - ) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem -AllowedMinutesVarianceBetweenServerTimes 31 - } - - $actual = Test-ComputerTime $poShMonConfiguration - - $actual.NoIssuesFound | Should Be $true - - $actual.OutputValues.Highlight.Count | Should Be 0 - } - - It "Should warn on server times with differences above configured threshold" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 12, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 10, 15, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - ) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem -AllowedMinutesVarianceBetweenServerTimes 2 - } - - $actual = Test-ComputerTime $poShMonConfiguration -WarningAction SilentlyContinue - - $actual.NoIssuesFound | Should Be $false - - $actual.OutputValues.Highlight.Count | Should Be 3 - $actual.OutputValues.Highlight[0] | Should Be "CurrentTime" - } - - It "Should not warn on server times with differences within default threshold across hour boundaries" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 11, 01, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 59, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 11, 01, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - ) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem -AllowedMinutesVarianceBetweenServerTimes 3 - } - - $actual = Test-ComputerTime $poShMonConfiguration - - $actual.NoIssuesFound | Should Be $true - } - - It "Should not warn on server times with differences within default threshold across day boundaries" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 2, 00, 01, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 23, 59, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 2, 00, 01, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - ) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem -AllowedMinutesVarianceBetweenServerTimes 3 - } - - $actual = Test-ComputerTime $poShMonConfiguration - - $actual.NoIssuesFound | Should Be $true - } - - It "Should only warn servers recently rebooted" { - - Mock -CommandName Get-WmiObject -MockWith { - return @( - [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 2, 00, 01, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 23, 59, 0), [datetime]::new(2017, 1, 1, 10, 5, 0)) - [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 2, 00, 01, 0), [datetime]::new(2016, 1, 1, 10, 15, 0)) - ) - } - - Mock -CommandName Get-Date -MockWith { - Return [datetime]::new(2017, 1, 1, 10, 15, 0) - } - - $poShMonConfiguration = New-PoShMonConfiguration { - General -ServerNames 'Server1' - OperatingSystem -AllowedMinutesVarianceBetweenServerTimes 3 - } - - $actual = Test-ComputerTime $poShMonConfiguration -WarningAction SilentlyContinue - - $actual.NoIssuesFound | Should Be $false - $actual.OutputValues[2].Highlight | Should Be "LastBootUptime" - } - } -} \ No newline at end of file +$rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve +Remove-Module PoShMon -ErrorAction SilentlyContinue +Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") + +Describe "Test-ComputerTime" { + InModuleScope PoShMon { + + class ServerTimeMock { + [string]$PSComputerName + [datetime]$DateTime + [int]$Year + [int]$Month + [int]$Day + [int]$Hour + [int]$Minute + [int]$Second + + ServerTimeMock ([string]$NewPSComputerName, [datetime]$NewDateTime) { + $this.PSComputerName = $NewPSComputerName; + $this.DateTime = $NewDateTime + } + + [datetime] ConvertToDateTime([string]$something) { + return $this.DateTime + } +} + + #It "Should throw an exception if no OperatingSystem configuration is set" { + # + # $poShMonConfiguration = New-PoShMonConfiguration { } + # + # { Test-ComputerTime $poShMonConfiguration } | Should throw + #} + + It "Should return a matching output structure" { + + Mock -ModuleName PoShMon Get-WmiObject { + return [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0)) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem + } + + $actual = Test-ComputerTime $poShMonConfiguration + + $actual.Keys.Count | Should Be 5 + $actual.ContainsKey("NoIssuesFound") | Should Be $true + $actual.ContainsKey("OutputHeaders") | Should Be $true + $actual.ContainsKey("OutputValues") | Should Be $true + $actual.ContainsKey("SectionHeader") | Should Be $true + $actual.ContainsKey("ElapsedTime") | Should Be $true + $headers = $actual.OutputHeaders + $headers.Keys.Count | Should Be 2 + #$values1 = $actual.OutputValues[0] + #$values1.Keys.Count | Should Be 3 + $actual.OutputValues[0].ServerName | Should Be 'Server1' + $actual.OutputValues[0].CurrentTime | Should Be ([datetime]::new(2017, 1, 1, 10, 15, 0)).ToString() + $actual.OutputValues[0].Highlight[0] | Should Be 'CurrentTime' + } + + It "Should write the expected Verbose output" { + + Mock -CommandName Get-WmiObject -MockWith { + return [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0)) + } + + Mock -CommandName Get-Date -MockWith { + Return [datetime]::new(2017, 1, 1, 10, 15, 0) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem + } + + $actual = Test-ComputerTime $poShMonConfiguration -Verbose + $output = $($actual = Test-ComputerTime $poShMonConfiguration -Verbose) 4>&1 + + $output.Count | Should Be 3 + $output[0].ToString() | Should Be "Initiating 'Server Clock Review' Test..." + $output[1].ToString() | Should Be "`tServer1: 10:15 AM" + $output[2].ToString() | Should Be "Complete 'Server Clock Review' Test, Issues Found: No" + + } + + It "Should write the expected Warning output" { + + Mock -CommandName Get-WmiObject -MockWith { + return @( + [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 09, 0)) + ) + } + + Mock -CommandName Get-Date -MockWith { + Return [datetime]::new(2017, 1, 1, 10, 15, 0) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem + } + + $actual = Test-ComputerTime $poShMonConfiguration + $output = $($actual = Test-ComputerTime $poShMonConfiguration) 3>&1 + + $output.Count | Should Be 1 + $output[0].ToString() | Should Be "`tDifference (6) is above variance threshold minutes (1)" + } + + It "Should warn on different server time (to local PoShMon machine)" { + + Mock -CommandName Get-WmiObject -MockWith { + return @( + [ServerTimeMock]::new('Server1', (Get-Date -Year 2017 -Month 1 -Day 1 -Hour 10 -Minute 15).AddMinutes(-6)) + ) + } + + Mock -CommandName Get-Date -MockWith { + Return [datetime]::new(2017, 1, 1, 10, 15, 0) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem + } + + $actual = Test-ComputerTime $poShMonConfiguration -WarningAction SilentlyContinue + + $actual.NoIssuesFound | Should Be $false + + $actual.OutputValues.Highlight.Count | Should Be 1 + $actual.OutputValues.Highlight | Should Be "CurrentTime" + } + + It "Should not warn on matching server times" { + + Mock -CommandName Get-WmiObject -MockWith { + return @( + [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0)) + [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 15, 0)) + [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 10, 15, 0)) + ) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem + } + + $actual = Test-ComputerTime $poShMonConfiguration + + $actual.NoIssuesFound | Should Be $true + + $actual.OutputValues.Highlight.Count | Should Be 0 + } + + It "Should not warn on server time differences within default threshold" { + + Mock -CommandName Get-WmiObject -MockWith { + return @( + [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0)) + [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 14, 30)) + [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 10, 15, 0)) + ) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem + } + + $actual = Test-ComputerTime $poShMonConfiguration + + $actual.NoIssuesFound | Should Be $true + + $actual.OutputValues.Highlight.Count | Should Be 0 + } + + It "Should warn on server times with differences above default threshold" { + + Mock -CommandName Get-WmiObject -MockWith { + return @( + [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0)) + [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 12, 0)) + [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 10, 15, 0)) + ) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem + } + + $actual = Test-ComputerTime $poShMonConfiguration -WarningAction SilentlyContinue + + $actual.NoIssuesFound | Should Be $false + + $actual.OutputValues.Highlight.Count | Should Be 3 + $actual.OutputValues.Highlight[0] | Should Be "CurrentTime" + } + + It "Should not warn on server time differences within configured threshold" { + + Mock -CommandName Get-WmiObject -MockWith { + return @( + [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0)) + [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 15, 0)) + [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 09, 48, 0)) + [ServerTimeMock]::new('Server4', [datetime]::new(2017, 1, 1, 10, 15, 0)) + ) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem -AllowedMinutesVarianceBetweenServerTimes 31 + } + + $actual = Test-ComputerTime $poShMonConfiguration + + $actual.NoIssuesFound | Should Be $true + + $actual.OutputValues.Highlight.Count | Should Be 0 + } + + It "Should warn on server times with differences above configured threshold" { + + Mock -CommandName Get-WmiObject -MockWith { + return @( + [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 10, 15, 0)) + [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 12, 0)) + [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 10, 15, 0)) + ) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem -AllowedMinutesVarianceBetweenServerTimes 2 + } + + $actual = Test-ComputerTime $poShMonConfiguration -WarningAction SilentlyContinue + + $actual.NoIssuesFound | Should Be $false + + $actual.OutputValues.Highlight.Count | Should Be 3 + $actual.OutputValues.Highlight[0] | Should Be "CurrentTime" + } + + It "Should not warn on server times with differences within default threshold across hour boundaries" { + + Mock -CommandName Get-WmiObject -MockWith { + return @( + [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 1, 11, 01, 0)) + [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 10, 59, 0)) + [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 1, 11, 01, 0)) + ) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem -AllowedMinutesVarianceBetweenServerTimes 3 + } + + $actual = Test-ComputerTime $poShMonConfiguration + + $actual.NoIssuesFound | Should Be $true + } + + It "Should not warn on server times with differences within default threshold across day boundaries" { + + Mock -CommandName Get-WmiObject -MockWith { + return @( + [ServerTimeMock]::new('Server1', [datetime]::new(2017, 1, 2, 00, 01, 0)) + [ServerTimeMock]::new('Server2', [datetime]::new(2017, 1, 1, 23, 59, 0)) + [ServerTimeMock]::new('Server3', [datetime]::new(2017, 1, 2, 00, 01, 0)) + ) + } + + $poShMonConfiguration = New-PoShMonConfiguration { + General -ServerNames 'Server1' + OperatingSystem -AllowedMinutesVarianceBetweenServerTimes 3 + } + + $actual = Test-ComputerTime $poShMonConfiguration + + $actual.NoIssuesFound | Should Be $true + } + } +} diff --git a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPDatabaseHealth.Tests.ps1 b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPDatabaseHealth.Tests.ps1 index 507ef86..9ec7af4 100644 --- a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPDatabaseHealth.Tests.ps1 +++ b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPDatabaseHealth.Tests.ps1 @@ -34,14 +34,12 @@ Describe "Test-SPDatabaseHealth" { $headerKeyCount = 3 - $actual.Keys.Count | Should Be 7 + $actual.Keys.Count | Should Be 5 $actual.ContainsKey("NoIssuesFound") | Should Be $true $actual.ContainsKey("OutputHeaders") | Should Be $true $actual.ContainsKey("OutputValues") | Should Be $true $actual.ContainsKey("SectionHeader") | Should Be $true $actual.ContainsKey("ElapsedTime") | Should Be $true - $actual.ContainsKey("HeaderUrl") | Should Be $true - $actual.ContainsKey("LinkColumn") | Should Be $true $headers = $actual.OutputHeaders $headers.Keys.Count | Should Be $headerKeyCount $values1 = $actual.OutputValues[0] diff --git a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPJobHealth.Tests.ps1 b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPJobHealth.Tests.ps1 index 3a6e646..a37e484 100644 --- a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPJobHealth.Tests.ps1 +++ b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPJobHealth.Tests.ps1 @@ -36,13 +36,12 @@ Describe "Test-SPJobHealth" { $headerKeyCount = 4 - $actual.Keys.Count | Should Be 6 + $actual.Keys.Count | Should Be 5 $actual.ContainsKey("NoIssuesFound") | Should Be $true $actual.ContainsKey("OutputHeaders") | Should Be $true $actual.ContainsKey("OutputValues") | Should Be $true $actual.ContainsKey("SectionHeader") | Should Be $true $actual.ContainsKey("ElapsedTime") | Should Be $true - $actual.ContainsKey("HeaderUrl") | Should Be $true $headers = $actual.OutputHeaders $headers.Keys.Count | Should Be $headerKeyCount $actual.OutputValues[0].JobDefinitionTitle | Should Be 'Job 123' diff --git a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPSearchHealth.Tests.ps1 b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPSearchHealth.Tests.ps1 index 6e6283a..7ae7ac9 100644 --- a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPSearchHealth.Tests.ps1 +++ b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPSearchHealth.Tests.ps1 @@ -36,13 +36,12 @@ Describe "Test-SPSearchHealth" { $headerKeyCount = 3 - $actual.Keys.Count | Should Be 6 + $actual.Keys.Count | Should Be 5 $actual.ContainsKey("NoIssuesFound") | Should Be $true $actual.ContainsKey("OutputHeaders") | Should Be $true $actual.ContainsKey("OutputValues") | Should Be $true $actual.ContainsKey("SectionHeader") | Should Be $true $actual.ContainsKey("ElapsedTime") | Should Be $true - $actual.ContainsKey("HeaderUrl") | Should Be $true $headers = $actual.OutputHeaders $headers.Keys.Count | Should Be $headerKeyCount $actual.OutputValues[1].ServerName | Should Be 'Server1' @@ -73,12 +72,11 @@ Describe "Test-SPSearchHealth" { $actual = Test-SPSearchHealth $poShMonConfiguration -Verbose $output = $($actual = Test-SPSearchHealth $poShMonConfiguration -Verbose) 4>&1 - $output.Count | Should Be 5 - $output[0].ToString() | Should Be "Getting Search Service App..." - $output[1].ToString() | Should Be "Initiating 'Search Status' Test..." - $output[2].ToString() | Should Be "`tComponent1 is in the following state: Active" - $output[3].ToString() | Should Be "`tComponent2 is in the following state: Active" - $output[4].ToString() | Should Be "Complete 'Search Status' Test, Issues Found: No" + $output.Count | Should Be 4 + $output[0].ToString() | Should Be "Initiating 'Search Status' Test..." + $output[1].ToString() | Should Be "`tComponent1 is in the following state: Active" + $output[2].ToString() | Should Be "`tComponent2 is in the following state: Active" + $output[3].ToString() | Should Be "Complete 'Search Status' Test, Issues Found: No" } It "Should write the expected Warning output" { diff --git a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPServerStatus.Tests.ps1 b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPServerStatus.Tests.ps1 index d06a7f0..ca2aa91 100644 --- a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPServerStatus.Tests.ps1 +++ b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPServerStatus.Tests.ps1 @@ -33,13 +33,12 @@ Describe "Test-SPServerStatus" { $headerKeyCount = 4 - $actual.Keys.Count | Should Be 6 + $actual.Keys.Count | Should Be 5 $actual.ContainsKey("NoIssuesFound") | Should Be $true $actual.ContainsKey("OutputHeaders") | Should Be $true $actual.ContainsKey("OutputValues") | Should Be $true $actual.ContainsKey("SectionHeader") | Should Be $true $actual.ContainsKey("ElapsedTime") | Should Be $true - $actual.ContainsKey("HeaderUrl") | Should Be $true $headers = $actual.OutputHeaders $headers.Keys.Count | Should Be $headerKeyCount $actual.OutputValues[1].ServerName | Should Be 'Server2' diff --git a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPUPSSyncHealth.Tests.ps1 b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPUPSSyncHealth.Tests.ps1 index 0c16022..4655502 100644 --- a/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPUPSSyncHealth.Tests.ps1 +++ b/src/Tests/CI/Unit/PoShMon.Monitoring.SharePoint/Test-SPUPSSyncHealth.Tests.ps1 @@ -184,13 +184,12 @@ Describe "Test-SPUPSSyncHealth" { $headerKeyCount = 4 - $actual.Keys.Count | Should Be 6 + $actual.Keys.Count | Should Be 5 $actual.ContainsKey("NoIssuesFound") | Should Be $true $actual.ContainsKey("OutputHeaders") | Should Be $true $actual.ContainsKey("OutputValues") | Should Be $true $actual.ContainsKey("SectionHeader") | Should Be $true $actual.ContainsKey("ElapsedTime") | Should Be $true - $actual.ContainsKey("HeaderUrl") | Should Be $true $headers = $actual.OutputHeaders $headers.Keys.Count | Should Be $headerKeyCount $actual.OutputValues[1].ManagementAgent.Count | Should Be 0 @@ -357,11 +356,10 @@ Describe "Test-SPUPSSyncHealth" { $actual = Test-SPUPSSyncHealth $poShMonConfiguration -Verbose $output = $($actual = Test-SPUPSSyncHealth $poShMonConfiguration -Verbose) 4>&1 - $output.Count | Should Be 4 - $output[0].ToString() | Should Be "Getting UPS Service App..." - $output[1].ToString() | Should Be "Initiating 'User Profile Sync State' Test..." - $output[2].ToString() | Should Be "`tGetting SharePoint service list to locate UPS Sync server..." - $output[3].ToString() | Should Be "Complete 'User Profile Sync State' Test, Issues Found: No" + $output.Count | Should Be 3 + $output[0].ToString() | Should Be "Initiating 'User Profile Sync State' Test..." + $output[1].ToString() | Should Be "`tGetting SharePoint service list to locate UPS Sync server..." + $output[2].ToString() | Should Be "Complete 'User Profile Sync State' Test, Issues Found: No" } It "Should write the expected Warning output" { diff --git a/src/Tests/ExternalDependencies/PoShMon.Notifications.Email.Monitoring/New-EmailBody.Tests.ps1 b/src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.Email.Monitoring/New-EmailBody.Tests.ps1 similarity index 99% rename from src/Tests/ExternalDependencies/PoShMon.Notifications.Email.Monitoring/New-EmailBody.Tests.ps1 rename to src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.Email.Monitoring/New-EmailBody.Tests.ps1 index b255224..60bb79d 100644 --- a/src/Tests/ExternalDependencies/PoShMon.Notifications.Email.Monitoring/New-EmailBody.Tests.ps1 +++ b/src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.Email.Monitoring/New-EmailBody.Tests.ps1 @@ -1,4 +1,4 @@ -$rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\') -Resolve +$rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve Remove-Module PoShMon -ErrorAction SilentlyContinue Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") diff --git a/src/Tests/ExternalDependencies/PoShMon.Notifications.O365Teams/Send-O365TeamsMessage.Tests.ps1 b/src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.O365Teams/Send-O365TeamsMessage.Tests.ps1 similarity index 98% rename from src/Tests/ExternalDependencies/PoShMon.Notifications.O365Teams/Send-O365TeamsMessage.Tests.ps1 rename to src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.O365Teams/Send-O365TeamsMessage.Tests.ps1 index 9ecf702..c040854 100644 --- a/src/Tests/ExternalDependencies/PoShMon.Notifications.O365Teams/Send-O365TeamsMessage.Tests.ps1 +++ b/src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.O365Teams/Send-O365TeamsMessage.Tests.ps1 @@ -1,4 +1,4 @@ -$rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\') -Resolve +$rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve Remove-Module PoShMon -ErrorAction SilentlyContinue Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") diff --git a/src/Tests/ExternalDependencies/PoShMon.Notifications.Pushbullet/Send-PushbulletMessage.Tests.ps1 b/src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.Pushbullet/Send-PushbulletMessage.Tests.ps1 similarity index 98% rename from src/Tests/ExternalDependencies/PoShMon.Notifications.Pushbullet/Send-PushbulletMessage.Tests.ps1 rename to src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.Pushbullet/Send-PushbulletMessage.Tests.ps1 index 7b0964b..b3231da 100644 --- a/src/Tests/ExternalDependencies/PoShMon.Notifications.Pushbullet/Send-PushbulletMessage.Tests.ps1 +++ b/src/Tests/Non-CI/ExternalDependencies/PoShMon.Notifications.Pushbullet/Send-PushbulletMessage.Tests.ps1 @@ -1,4 +1,4 @@ -$rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\') -Resolve +$rootPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) -ChildPath ('..\..\..\..\') -Resolve Remove-Module PoShMon -ErrorAction SilentlyContinue Import-Module (Join-Path $rootPath -ChildPath "PoShMon.psd1") diff --git a/src/Tests/PoShMon.Tests.ps1 b/src/Tests/PoShMon.Tests.ps1 index fb55b20..679fda8 100644 --- a/src/Tests/PoShMon.Tests.ps1 +++ b/src/Tests/PoShMon.Tests.ps1 @@ -1,18 +1,38 @@ +Import-Module Pester + $path = (Split-Path -Parent $MyInvocation.MyCommand.Path) -#$scriptFiles = @( Get-ChildItem -Path "$path\Integration\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) -#$scriptFiles = @( Get-ChildItem -Path "$path\Unit\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) +$testsPath = "$path\CI\Unit" + +Invoke-Pester -Path $testsPath -CodeCoverage "$sutPath\*\*.ps1" + #$scriptFiles = @( Get-ChildItem -Path "$path\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) -$scriptFiles = @( Get-ChildItem -Path "$path\Integration\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) + ` - @( Get-ChildItem -Path "$path\Unit\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) +#$scriptFiles = @( Get-ChildItem -Path "$path\CI\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) +#$scriptFiles = @( Get-ChildItem -Path "$path\CI\Integration\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) +#$scriptFiles = @( Get-ChildItem -Path "$path\CI\Unit\*\*.ps1" -Recurse -ErrorAction SilentlyContinue ) + +#$testResultSettings = @{ } -$testResultSettings = @{ } +#$testsPath = "$path\CI" +#$testsPath = "$path\CI\Integration" + +<# +$filesToTest = @() +$sutPath = Join-Path (Split-Path -Parent $path) -ChildPath ('\Functions') -Resolve Foreach($import in $scriptFiles) { + $sutFileName = (Split-Path -Leaf $import).Replace(".Tests", "") + if (!$filesToTest.Contains($sutFileName)) + { + $fileToTest = Get-ChildItem -Path "$sutPath\*\$sutFileName" -Recurse + + $filesToTest += $fileToTest.FullName + } + #Invoke-Pester -Script $import # -PassThru $testResultSettings - #$import - . $import + #. $import } +#> # $testResultSettings \ No newline at end of file diff --git a/src/Tests/appveyorCITests.ps1 b/src/Tests/appveyorCITests.ps1 new file mode 100644 index 0000000..d6a040b --- /dev/null +++ b/src/Tests/appveyorCITests.ps1 @@ -0,0 +1,58 @@ +#based on code from https://github.com/RamblingCookieMonster/PSDiskPart/ +$ProjectRoot = $ENV:APPVEYOR_BUILD_FOLDER +Set-Location $ProjectRoot + +#$path = (Split-Path -Parent $MyInvocation.MyCommand.Path) + +Import-Module Pester + +Invoke-Pester -Path "$ProjectRoot\src\Tests\CI" -CodeCoverage "$ProjectRoot\src\Functions\*\*.ps1" -OutputFormat NUnitXml -OutputFile "$ProjectRoot\RawTestResults.xml" -PassThru | ` + Export-Clixml -Path "$ProjectRoot\PesterTestResults.xml" + +#Invoke-Pester -Path "$ProjectRoot\src\Tests\Integration" -OutputFormat NUnitXml -OutputFile "$ProjectRoot\RawIntegrationTestResults.xml" -PassThru | ` +# Export-Clixml -Path "$ProjectRoot\PesterIntegrationTestResults.xml" + +#Show status... +$AllFiles = Get-ChildItem -Path $ProjectRoot\*Results.xml | Select -ExpandProperty FullName +"`n`tSTATUS: Finalizing results`n" +"COLLATING FILES:`n$($AllFiles | Out-String)" + +#Upload results for test page +Get-ChildItem -Path $ProjectRoot\Raw*TestResults.xml | Foreach-Object { + $Address = "https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)" + $Source = $_.FullName + + "UPLOADING FILES: $Address $Source" + + (New-Object 'System.Net.WebClient').UploadFile( $Address, $Source ) +} + +#What failed? +$Results = @( Get-ChildItem -Path "$ProjectRoot\Pester*TestResults.xml" | Import-Clixml ) + +$FailedCount = $Results | + Select -ExpandProperty FailedCount | + Measure-Object -Sum | + Select -ExpandProperty Sum + +if ($FailedCount -gt 0) { + + $FailedItems = $Results | + Select -ExpandProperty TestResult | + Where {$_.Passed -notlike $True} + + "FAILED TESTS SUMMARY:`n" + $FailedItems | ForEach-Object { + $Test = $_ + [pscustomobject]@{ + Describe = $Test.Describe + Context = $Test.Context + Name = "It $($Test.Name)" + Result = $Test.Result + } + } | + Sort Describe, Context, Name, Result | + Format-List + + throw "$FailedCount tests failed." +} \ No newline at end of file