Tests/Restart-ECMA2ConnectorSyncJob.Tests.ps1

# Import the module
$ModulePath = Split-Path -Parent $PSScriptRoot
Import-Module "$ModulePath\ECMA2HostTools.psd1" -Force

# Note: Mock -MockWith scriptblocks for -ModuleName ECMA2HostTools run inside the
# module's own scope, so they cannot see helper functions defined in this test script.
# The test sync job object is therefore built inline in each Mock block.

Describe 'Restart-ECMA2ConnectorSyncJob' {
    Context 'Parameter Validation' {
        It 'Should have mandatory ServicePrincipalId and JobId parameters' {
            $command = Get-Command Restart-ECMA2ConnectorSyncJob
            ($command.Parameters['ServicePrincipalId'].Attributes.Mandatory -contains $true) | Should Be $true
            ($command.Parameters['JobId'].Attributes.Mandatory -contains $true) | Should Be $true
        }

        It 'Should support ShouldProcess (WhatIf/Confirm)' {
            $command = Get-Command Restart-ECMA2ConnectorSyncJob
            $command.Parameters.ContainsKey('WhatIf') | Should Be $true
            $command.Parameters.ContainsKey('Confirm') | Should Be $true
        }

        It 'Should restrict ResetScope to the documented values' {
            $command = Get-Command Restart-ECMA2ConnectorSyncJob
            $validation = $command.Parameters['ResetScope'].Attributes | Where-Object { $_.TypeId.Name -eq 'ValidateSetAttribute' }
            $validation.ValidValues | Should Be @('Escrows', 'Watermark', 'QuarantineState', 'ForceDeletes', 'Full', 'None', 'ConnectorDataStore')
        }
    }

    Context 'Dangerous Scope Guard' {
        BeforeEach {
            Mock Get-ECMA2ConnectorSyncJob -ModuleName ECMA2HostTools -MockWith {
                [PSCustomObject]@{ Id = 'job1'; ServicePrincipalId = 'sp1'; StatusCode = 'Active'; IsRunning = $false; LastExecutionState = 'Succeeded' }
            }
            Mock Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -MockWith { $null }
        }

        It 'Should block ConnectorDataStore without -Force' {
            $errors = @()
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -ResetScope ConnectorDataStore -ErrorVariable errors -ErrorAction SilentlyContinue -Confirm:$false
            $errors.Count -gt 0 | Should Be $true
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -Times 0
        }

        It 'Should block None without -Force' {
            $errors = @()
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -ResetScope None -ErrorVariable errors -ErrorAction SilentlyContinue -Confirm:$false
            $errors.Count -gt 0 | Should Be $true
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -Times 0
        }

        It 'Should allow ConnectorDataStore with -Force' {
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -ResetScope ConnectorDataStore -Force -Confirm:$false
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -Times 1
        }
    }

    Context 'Running Job Guard' {
        BeforeEach {
            Mock Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -MockWith { $null }
        }

        It 'Should block a narrow reset (Escrows) while the job is running' {
            Mock Get-ECMA2ConnectorSyncJob -ModuleName ECMA2HostTools -MockWith {
                [PSCustomObject]@{ Id = 'job1'; ServicePrincipalId = 'sp1'; StatusCode = 'Active'; IsRunning = $true; LastExecutionState = 'InProgress' }
            }
            $errors = @()
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -ErrorVariable errors -ErrorAction SilentlyContinue -Confirm:$false
            $errors.Count -gt 0 | Should Be $true
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -Times 0
        }

        It 'Should allow a Full reset while the job is running' {
            Mock Get-ECMA2ConnectorSyncJob -ModuleName ECMA2HostTools -MockWith {
                [PSCustomObject]@{ Id = 'job1'; ServicePrincipalId = 'sp1'; StatusCode = 'Active'; IsRunning = $true; LastExecutionState = 'InProgress' }
            }
            $warnings = @()
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -ResetScope Full -WarningVariable warnings -WarningAction SilentlyContinue -Confirm:$false
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -Times 1
            $warnings.Count -gt 0 | Should Be $true
        }

        It 'Should allow a narrow reset while running when -Force is specified' {
            Mock Get-ECMA2ConnectorSyncJob -ModuleName ECMA2HostTools -MockWith {
                [PSCustomObject]@{ Id = 'job1'; ServicePrincipalId = 'sp1'; StatusCode = 'Active'; IsRunning = $true; LastExecutionState = 'InProgress' }
            }
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -Force -Confirm:$false
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -Times 1
        }

        It 'Should proceed normally when the job is not running' {
            Mock Get-ECMA2ConnectorSyncJob -ModuleName ECMA2HostTools -MockWith {
                [PSCustomObject]@{ Id = 'job1'; ServicePrincipalId = 'sp1'; StatusCode = 'Active'; IsRunning = $false; LastExecutionState = 'Succeeded' }
            }
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -Confirm:$false
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -Times 1
        }
    }

    Context 'Job Not Found' {
        It 'Should error when the job cannot be found' {
            Mock Get-ECMA2ConnectorSyncJob -ModuleName ECMA2HostTools -MockWith { $null }
            Mock Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -MockWith { $null }
            $errors = @()
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'missing' -ErrorVariable errors -ErrorAction SilentlyContinue -Confirm:$false
            $errors.Count -gt 0 | Should Be $true
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -Times 0
        }
    }

    Context 'ApiVersion / URI construction' {
        BeforeEach {
            Mock Get-ECMA2ConnectorSyncJob -ModuleName ECMA2HostTools -MockWith {
                [PSCustomObject]@{ Id = 'job1'; ServicePrincipalId = 'sp1'; StatusCode = 'Active'; IsRunning = $false; LastExecutionState = 'Succeeded' }
            }
        }

        It 'Should POST to the v1.0 restart endpoint by default' {
            Mock Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -MockWith { $null }
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -Confirm:$false
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -ParameterFilter {
                $Uri -eq 'https://graph.microsoft.com/v1.0/servicePrincipals/sp1/synchronization/jobs/job1/restart' -and $Method -eq 'POST'
            }
        }

        It 'Should POST to the beta microsoft.graph.restart endpoint when -ApiVersion beta is specified' {
            Mock Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -MockWith { $null }
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -ApiVersion beta -Confirm:$false
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -ParameterFilter {
                $Uri -eq 'https://graph.microsoft.com/beta/servicePrincipals/sp1/synchronization/jobs/job1/microsoft.graph.restart'
            }
        }
    }

    Context 'WhatIf Support' {
        BeforeEach {
            Mock Get-ECMA2ConnectorSyncJob -ModuleName ECMA2HostTools -MockWith {
                [PSCustomObject]@{ Id = 'job1'; ServicePrincipalId = 'sp1'; StatusCode = 'Active'; IsRunning = $false; LastExecutionState = 'Succeeded' }
            }
            Mock Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -MockWith { $null }
        }

        It 'Should not call Graph when -WhatIf is specified' {
            Restart-ECMA2ConnectorSyncJob -ServicePrincipalId 'sp1' -JobId 'job1' -WhatIf
            Assert-MockCalled Invoke-ECMA2GraphRequest -ModuleName ECMA2HostTools -Times 0
        }
    }
}