Tests/Unit/Get-SPCGraphSiteUsageInternal.Tests.ps1

#Requires -Modules @{ ModuleName = 'Pester'; ModuleVersion = '5.0.0' }

BeforeAll {
    . (Join-Path $PSScriptRoot '../../Private/PnPWrappers.ps1')
    . (Join-Path $PSScriptRoot '../../Private/Get-SPCGraphSiteUsageInternal.ps1')
}

Describe 'Get-SPCGraphSiteUsageInternal Unit Tests' -Tag 'Graph', 'Internal', 'Throttling' {
    BeforeEach {
        $script:SPCContext = [PSCustomObject]@{
            TenantName       = 'contoso'
            GraphAccessToken = 'mock_graph_token'
            PnPContext       = [PSCustomObject]@{ Url = 'https://contoso-admin.sharepoint.com' }
        }
    }

    Context 'TC-USAGE-001: CSV Parsing & OwnerUPN Mapping (RF-08)' {
        It 'TC-USAGE-001.1: Should map Site Owner Principal Name to OwnerUPN accurately' {
            $csvContent = @"
Report Refresh Date,Site URL,Site Title,Root Web Template,Site Owner Principal Name,Owner Display Name,Storage Used (Byte),Storage Allocated (Byte),File Count,Active File Count,Last Activity Date,Lock State,Group ID
2026-08-15,https://contoso.sharepoint.com/sites/ProjectA,Project A,STS#3,megan.bowen@contoso.com,Megan Bowen,104857600,1073741824,500,450,2026-08-10,Unlock,11111111-2222-3333-4444-555555555555
"@

            Mock Invoke-RestMethod { $csvContent }

            $result = Get-SPCGraphSiteUsageInternal

            $result | Should -Not -BeNullOrEmpty
            $result.Count | Should -Be 1
            $result[0].SiteUrl | Should -Be 'https://contoso.sharepoint.com/sites/ProjectA'
            $result[0].OwnerUPN | Should -Be 'megan.bowen@contoso.com'
            $result[0].StorageUsedMB | Should -Be 100.0
            $result[0].IsTeamSite | Should -BeTrue
        }
    }

    Context 'TC-USAGE-002: Throttling Resilience (HTTP 429 Backoff)' {
        It 'TC-USAGE-002.1: Should retry upon encountering HTTP 429 Throttling response' {
            $script:attemptCount = 0
            $csvContent = @"
Report Refresh Date,Site URL,Site Title,Root Web Template,Site Owner Principal Name,Owner Display Name,Storage Used (Byte),Storage Allocated (Byte),File Count,Active File Count,Last Activity Date,Lock State,Group ID
2026-08-15,https://contoso.sharepoint.com/sites/A,Site A,STS#3,admin@contoso.com,Admin,1024,2048,1,1,2026-08-10,Unlock,
"@

            Mock Invoke-RestMethod {
                $script:attemptCount++
                if ($script:attemptCount -lt 2) {
                    $mockResponse = [PSCustomObject]@{
                        StatusCode = [PSCustomObject]@{ value__ = 429 }
                        Headers = @{ 'Retry-After' = 1 }
                    }
                    $ex = [System.Exception]::new('Too Many Requests')
                    $ex | Add-Member -NotePropertyName Response -NotePropertyValue $mockResponse -Force
                    throw $ex
                }
                return $csvContent
            }
            Mock Start-Sleep { }

            $result = Get-SPCGraphSiteUsageInternal

            $result | Should -Not -BeNullOrEmpty
            $script:attemptCount | Should -Be 2
        }
    }

    Context 'TC-USAGE-003: Fallback Mechanism on Non-Throttling Failure' {
        It 'TC-USAGE-003.1: Should fallback to Get-PnPTenantSite when Graph endpoint fails' {
            Mock Invoke-RestMethod { throw [System.Exception]::new('Graph Endpoint 500 Internal Error') }
            Mock Get-PnPTenantSite {
                @(
                    [PSCustomObject]@{
                        Url                      = 'https://contoso.sharepoint.com/sites/FallbackSite'
                        Title                    = 'Fallback Site'
                        StorageUsageCurrent      = 512.0
                        Template                 = 'GROUP#0'
                        GroupId                  = 'mock-guid'
                        Owner                    = 'fallback.owner@contoso.com'
                        LockState                = 'Unlock'
                        LastContentModifiedDate = (Get-Date)
                    }
                )
            }

            $result = Get-SPCGraphSiteUsageInternal

            $result | Should -Not -BeNullOrEmpty
            $result[0].SiteUrl | Should -Be 'https://contoso.sharepoint.com/sites/FallbackSite'
            $result[0].OwnerUPN | Should -Be 'fallback.owner@contoso.com'
        }
    }
}