Tests/Get-O365MailboxUsage.Tests.ps1
#Requires -Module Pester <# .SYNOPSIS Pester tests for Get-O365MailboxUsage function .DESCRIPTION Comprehensive unit tests for the Get-O365MailboxUsage function including: - Parameter validation - Helper function testing - Mock testing for Exchange Online cmdlets - Pipeline input testing - Sorting functionality - Error handling .NOTES Run with: Invoke-Pester -Path ".\Get-O365MailboxUsage.Tests.ps1" -Verbose Requires Pester module: Install-Module -Name Pester -Force -SkipPublisherCheck #> BeforeAll { # Import the functions to test $functionPath = Join-Path $PSScriptRoot "..\Public\Get-O365MailboxUsage.ps1" $connectionPath = Join-Path $PSScriptRoot "..\Public\Connect-O365Exchange.ps1" . $functionPath . $connectionPath # Mock Exchange Online cmdlets since we can't connect to real Exchange Online in tests Mock Get-ConnectionInformation { return @{ Name = "TestConnection" State = "Connected" } } # Create mock mailbox objects $MockMailbox1 = [PSCustomObject]@{ DisplayName = "John Doe" PrimarySmtpAddress = "john.doe@company.com" RecipientTypeDetails = "UserMailbox" ArchiveStatus = "Active" } $MockMailbox2 = [PSCustomObject]@{ DisplayName = "Jane Smith" PrimarySmtpAddress = "jane.smith@company.com" RecipientTypeDetails = "UserMailbox" ArchiveStatus = "None" } $MockMailbox3 = [PSCustomObject]@{ DisplayName = "Shared Resources" PrimarySmtpAddress = "shared@company.com" RecipientTypeDetails = "SharedMailbox" ArchiveStatus = "None" } # Create mock mailbox statistics $MockStats1 = [PSCustomObject]@{ TotalItemSize = "25 GB (26,843,545,600 bytes)" ProhibitSendReceiveQuota = "50 GB (53,687,091,200 bytes)" ItemCount = 15000 LastLogonTime = (Get-Date).AddDays(-1) } $MockStats2 = [PSCustomObject]@{ TotalItemSize = "45 GB (48,318,382,080 bytes)" ProhibitSendReceiveQuota = "50 GB (53,687,091,200 bytes)" ItemCount = 28000 LastLogonTime = (Get-Date).AddDays(-3) } $MockStats3 = [PSCustomObject]@{ TotalItemSize = "5 GB (5,368,709,120 bytes)" ProhibitSendReceiveQuota = "25 GB (26,843,545,600 bytes)" ItemCount = 3500 LastLogonTime = (Get-Date).AddDays(-7) } # Create mock archive statistics $MockArchiveStats1 = [PSCustomObject]@{ TotalItemSize = "10 GB (10,737,418,240 bytes)" ProhibitSendReceiveQuota = "100 GB (107,374,182,400 bytes)" ItemCount = 5000 } } Describe "Get-O365MailboxUsage" { Context "Parameter Validation" { It "Should accept valid SortBy parameters" { $validSortBy = @("PercentFull", "UsedSpaceGB", "TotalQuotaGB", "DisplayName") foreach ($sortBy in $validSortBy) { { Get-O365MailboxUsage -SortBy $sortBy -WhatIf } | Should -Not -Throw } } It "Should reject invalid SortBy parameters" { { Get-O365MailboxUsage -SortBy "InvalidSort" } | Should -Throw } It "Should accept pipeline input for UserPrincipalName" { Mock Get-Mailbox { return $MockMailbox1 } Mock Get-MailboxStatistics { return $MockStats1 } { "john.doe@company.com" | Get-O365MailboxUsage } | Should -Not -Throw } It "Should accept array input for UserPrincipalName" { Mock Get-Mailbox { return $MockMailbox1 } Mock Get-MailboxStatistics { return $MockStats1 } { Get-O365MailboxUsage -UserPrincipalName @("john.doe@company.com", "jane.smith@company.com") } | Should -Not -Throw } } Context "Connection Testing" { It "Should check Exchange Online connection" { Mock Get-ConnectionInformation { throw "Not connected" } { Get-O365MailboxUsage } | Should -Throw "*Exchange Online connection required*" } It "Should proceed when properly connected" { Mock Get-ConnectionInformation { return @{ Name = "TestConnection" } } Mock Get-Mailbox { return @() } { Get-O365MailboxUsage } | Should -Not -Throw } } Context "Single User Processing" { BeforeEach { Mock Get-Mailbox { return $MockMailbox1 } Mock Get-MailboxStatistics { return $MockStats1 } } It "Should process a single user correctly" { $result = Get-O365MailboxUsage -UserPrincipalName "john.doe@company.com" $result | Should -Not -BeNullOrEmpty $result.DisplayName | Should -Be "John Doe" $result.UserPrincipalName | Should -Be "john.doe@company.com" $result.UsedSpaceGB | Should -Be 25 $result.TotalQuotaGB | Should -Be 50 $result.PercentFull | Should -Be 50.0 } It "Should include archive statistics when requested" { Mock Get-MailboxStatistics -ParameterFilter { $Archive } { return $MockArchiveStats1 } $result = Get-O365MailboxUsage -UserPrincipalName "john.doe@company.com" -IncludeArchive $result.ArchiveUsedSpaceGB | Should -Be 10 $result.ArchiveTotalQuotaGB | Should -Be 100 $result.ArchivePercentFull | Should -Be 10.0 } } Context "Multiple User Processing" { BeforeEach { Mock Get-Mailbox -ParameterFilter { $ResultSize -eq "Unlimited" } { return @($MockMailbox1, $MockMailbox2, $MockMailbox3) } Mock Get-MailboxStatistics -ParameterFilter { $Identity -eq "john.doe@company.com" } { return $MockStats1 } Mock Get-MailboxStatistics -ParameterFilter { $Identity -eq "jane.smith@company.com" } { return $MockStats2 } Mock Get-MailboxStatistics -ParameterFilter { $Identity -eq "shared@company.com" } { return $MockStats3 } } It "Should process all mailboxes when no specific user provided" { $results = Get-O365MailboxUsage $results | Should -HaveCount 3 $results[0].DisplayName | Should -Be "Jane Smith" # Should be sorted by PercentFull descending $results[1].DisplayName | Should -Be "John Doe" $results[2].DisplayName | Should -Be "Shared Resources" } It "Should sort by PercentFull descending by default" { $results = Get-O365MailboxUsage $results[0].PercentFull | Should -BeGreaterThan $results[1].PercentFull $results[1].PercentFull | Should -BeGreaterThan $results[2].PercentFull } It "Should sort by DisplayName when requested" { $results = Get-O365MailboxUsage -SortBy DisplayName $results[0].DisplayName | Should -Be "Jane Smith" # Alphabetical order $results[1].DisplayName | Should -Be "John Doe" $results[2].DisplayName | Should -Be "Shared Resources" } It "Should sort by UsedSpaceGB when requested" { $results = Get-O365MailboxUsage -SortBy UsedSpaceGB $results[0].UsedSpaceGB | Should -BeGreaterOrEqual $results[1].UsedSpaceGB $results[1].UsedSpaceGB | Should -BeGreaterOrEqual $results[2].UsedSpaceGB } } Context "Pipeline Input Processing" { It "Should accept single user from pipeline" { Mock Get-Mailbox { return $MockMailbox1 } Mock Get-MailboxStatistics { return $MockStats1 } $result = "john.doe@company.com" | Get-O365MailboxUsage $result | Should -Not -BeNullOrEmpty $result.UserPrincipalName | Should -Be "john.doe@company.com" } It "Should accept multiple users from pipeline" { Mock Get-Mailbox -ParameterFilter { $Identity -eq "john.doe@company.com" } { return $MockMailbox1 } Mock Get-Mailbox -ParameterFilter { $Identity -eq "jane.smith@company.com" } { return $MockMailbox2 } Mock Get-MailboxStatistics -ParameterFilter { $Identity -eq "john.doe@company.com" } { return $MockStats1 } Mock Get-MailboxStatistics -ParameterFilter { $Identity -eq "jane.smith@company.com" } { return $MockStats2 } $results = @("john.doe@company.com", "jane.smith@company.com") | Get-O365MailboxUsage $results | Should -HaveCount 2 $results[0].UserPrincipalName | Should -Be "jane.smith@company.com" # Sorted by PercentFull $results[1].UserPrincipalName | Should -Be "john.doe@company.com" } } Context "Helper Function Testing - ConvertTo-GB" { It "Should convert GB sizes correctly" { # This tests the internal ConvertTo-GB function indirectly Mock Get-Mailbox { return $MockMailbox1 } Mock Get-MailboxStatistics { return [PSCustomObject]@{ TotalItemSize = "25 GB (26,843,545,600 bytes)" ProhibitSendReceiveQuota = "50 GB (53,687,091,200 bytes)" ItemCount = 15000 LastLogonTime = (Get-Date) } } $result = Get-O365MailboxUsage -UserPrincipalName "john.doe@company.com" $result.UsedSpaceGB | Should -Be 25 $result.TotalQuotaGB | Should -Be 50 } It "Should handle MB to GB conversion" { Mock Get-Mailbox { return $MockMailbox1 } Mock Get-MailboxStatistics { return [PSCustomObject]@{ TotalItemSize = "1024 MB (1,073,741,824 bytes)" ProhibitSendReceiveQuota = "2048 MB (2,147,483,648 bytes)" ItemCount = 5000 LastLogonTime = (Get-Date) } } $result = Get-O365MailboxUsage -UserPrincipalName "john.doe@company.com" $result.UsedSpaceGB | Should -Be 1 $result.TotalQuotaGB | Should -Be 2 } } Context "Error Handling" { It "Should handle mailbox not found gracefully" { Mock Get-Mailbox { throw "Mailbox not found" } { Get-O365MailboxUsage -UserPrincipalName "nonexistent@company.com" } | Should -Throw } It "Should handle statistics retrieval failure gracefully" { Mock Get-Mailbox { return $MockMailbox1 } Mock Get-MailboxStatistics { throw "Statistics not available" } { Get-O365MailboxUsage -UserPrincipalName "john.doe@company.com" } | Should -Throw } It "Should warn when no results are returned" { Mock Get-Mailbox { return @() } $result = Get-O365MailboxUsage $result | Should -BeNullOrEmpty } } Context "Archive Functionality" { It "Should skip archive when mailbox has no archive" { Mock Get-Mailbox { return $MockMailbox2 } # ArchiveStatus = "None" Mock Get-MailboxStatistics { return $MockStats2 } $result = Get-O365MailboxUsage -UserPrincipalName "jane.smith@company.com" -IncludeArchive $result.ArchiveUsedSpaceGB | Should -BeNullOrEmpty } It "Should include archive when requested and available" { Mock Get-Mailbox { return $MockMailbox1 } # ArchiveStatus = "Active" Mock Get-MailboxStatistics -ParameterFilter { -not $Archive } { return $MockStats1 } Mock Get-MailboxStatistics -ParameterFilter { $Archive } { return $MockArchiveStats1 } $result = Get-O365MailboxUsage -UserPrincipalName "john.doe@company.com" -IncludeArchive $result.ArchiveUsedSpaceGB | Should -Be 10 $result.ArchiveTotalQuotaGB | Should -Be 100 $result.ArchivePercentFull | Should -Be 10.0 $result.ArchiveItemCount | Should -Be 5000 } } Context "Output Validation" { BeforeEach { Mock Get-Mailbox { return $MockMailbox1 } Mock Get-MailboxStatistics { return $MockStats1 } } It "Should return objects with correct properties" { $result = Get-O365MailboxUsage -UserPrincipalName "john.doe@company.com" $result.PSObject.Properties.Name | Should -Contain "DisplayName" $result.PSObject.Properties.Name | Should -Contain "UserPrincipalName" $result.PSObject.Properties.Name | Should -Contain "UsedSpaceGB" $result.PSObject.Properties.Name | Should -Contain "TotalQuotaGB" $result.PSObject.Properties.Name | Should -Contain "PercentFull" $result.PSObject.Properties.Name | Should -Contain "ItemCount" $result.PSObject.Properties.Name | Should -Contain "LastLogonTime" $result.PSObject.Properties.Name | Should -Contain "MailboxType" } It "Should calculate percentage correctly" { # 25 GB used out of 50 GB total = 50% $result = Get-O365MailboxUsage -UserPrincipalName "john.doe@company.com" $result.PercentFull | Should -Be 50.0 } It "Should handle division by zero for percentage calculation" { Mock Get-MailboxStatistics { return [PSCustomObject]@{ TotalItemSize = "25 GB (26,843,545,600 bytes)" ProhibitSendReceiveQuota = "Unlimited" ItemCount = 15000 LastLogonTime = (Get-Date) } } $result = Get-O365MailboxUsage -UserPrincipalName "john.doe@company.com" $result.PercentFull | Should -Be 0 } } } Describe "Connect-O365Exchange" { Context "Parameter Validation" { It "Should accept valid email addresses for UserPrincipalName" { { Connect-O365Exchange -UserPrincipalName "user@domain.com" -WhatIf } | Should -Not -Throw } It "Should reject invalid email addresses" { { Connect-O365Exchange -UserPrincipalName "invalid-email" } | Should -Throw } It "Should accept organization parameter" { { Connect-O365Exchange -Organization "contoso" -WhatIf } | Should -Not -Throw } } Context "Module Dependency" { It "Should handle missing ExchangeOnlineManagement module gracefully" { Mock Get-Module { return $null } Mock Read-Host { return "N" } $result = Connect-O365Exchange $result | Should -Be $false } } Context "Connection Management" { It "Should detect existing connections" { Mock Get-ConnectionInformation { return @{ Name = "TestTenant"; State = "Connected" } } Mock Get-OrganizationConfig { return @{} } $result = Connect-O365Exchange $result | Should -Be $true } It "Should handle connection failures gracefully" { Mock Get-ConnectionInformation { throw "Connection failed" } Mock Connect-ExchangeOnline { throw "Authentication failed" } $result = Connect-O365Exchange $result | Should -Be $false } } } Describe "Test-O365ExchangeConnection" { Context "Connection Status Testing" { It "Should return true for active connection" { Mock Get-ConnectionInformation { return @{ Name = "TestTenant"; State = "Connected" } } Mock Get-OrganizationConfig { return @{} } $result = Test-O365ExchangeConnection -Quiet $result | Should -Be $true } It "Should return false for no connection" { Mock Get-ConnectionInformation { return $null } $result = Test-O365ExchangeConnection -Quiet $result | Should -Be $false } It "Should return false for non-functional connection" { Mock Get-ConnectionInformation { return @{ Name = "TestTenant"; State = "Connected" } } Mock Get-OrganizationConfig { throw "Connection not functional" } $result = Test-O365ExchangeConnection -Quiet $result | Should -Be $false } } Context "Output Modes" { It "Should provide detailed information when requested" { Mock Get-ConnectionInformation { return @{ Name = "TestTenant" UserPrincipalName = "test@domain.com" State = "Connected" TokenExpiryTimeUTC = (Get-Date).AddHours(1) } } Mock Get-OrganizationConfig { return @{} } { Test-O365ExchangeConnection -Detailed } | Should -Not -Throw } It "Should suppress output in quiet mode" { Mock Get-ConnectionInformation { return $null } { Test-O365ExchangeConnection -Quiet } | Should -Not -Throw } } } |