Tests/Public/Move-FileShare.Tests.ps1
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '', Justification = 'Tests intentionally swallow errors to verify side-effects')] param() BeforeAll { $modulePath = "$PSScriptRoot/../.." Get-ChildItem -Path "$modulePath/Private/*.ps1" | ForEach-Object { . $_.FullName } Get-ChildItem -Path "$modulePath/Public/*.ps1" | ForEach-Object { . $_.FullName } } Describe 'Move-FileShare' { BeforeEach { Mock Write-Host {} Mock Write-Warning {} Mock Assert-AzCopyInstalled {} Mock Assert-AzCliLogin { [PSCustomObject]@{ user = @{ name = 'test@contoso.com' } } } Mock Test-StorageAccountAccess {} Mock New-SasToken { 'fakesas=token' } Mock New-Item { [PSCustomObject]@{ FullName = 'C:\logs' } } } Context 'Pre-flight checks' { It 'Calls Assert-AzCopyInstalled' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' } Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' } try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -Confirm:$false } catch {} Should -Invoke Assert-AzCopyInstalled -Times 1 } It 'Calls Assert-AzCliLogin' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' } Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' } try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -Confirm:$false } catch {} Should -Invoke Assert-AzCliLogin -Times 1 } It 'Validates both storage accounts are accessible' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' } Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' } try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -Confirm:$false } catch {} Should -Invoke Test-StorageAccountAccess -Times 2 } It 'Generates SAS tokens for source (rl) and destination (rwdlc)' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' } Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' } try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -Confirm:$false } catch {} Should -Invoke New-SasToken -ParameterFilter { $Permissions -eq 'rl' } -Times 1 Should -Invoke New-SasToken -ParameterFilter { $Permissions -eq 'rwdlc' } -Times 1 } } Context 'Share enumeration' { It 'Returns early when no shares found on source' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '[]' } Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' Should -Invoke Write-Warning -ParameterFilter { $Message -like '*No file shares*' } } It 'Throws when requested share does not exist' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1","share2"]' } { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'nonexistent' } | Should -Throw '*nonexistent*' } It 'Throws when az storage share list fails' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 1; 'AuthorizationFailure' } { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' } | Should -Throw '*Failed to list*' } It 'Filters to specified shares when ShareNames provided' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1","share2","share3"]' } Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' } try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1','share2' -Confirm:$false } catch {} Should -Invoke Write-Host -ParameterFilter { $Object -like '*Targeting 2 share*' } } It 'Targets all shares when ShareNames not provided' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1","share2"]' } Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'done' } try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -Confirm:$false } catch {} Should -Invoke Write-Host -ParameterFilter { $Object -like '*Targeting all 2*' } } } Context 'WhatIf support' { It 'Proceeds through share enumeration when WhatIf is specified' { Mock -CommandName 'az' -MockWith { $global:LASTEXITCODE = 0; '["share1"]' } Mock -CommandName 'azcopy' -MockWith { $global:LASTEXITCODE = 0; 'dry run complete' } try { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ShareNames 'share1' -WhatIf } catch {} # Verify WhatIf does not skip function body — enumeration and targeting still occur Should -Invoke Write-Host -ParameterFilter { $Object -like '*Targeting 1 share*' } } } Context 'Parameter validation' { It 'ThrottleLimit must be between 1 and 64' { { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ThrottleLimit 0 } | Should -Throw { Move-FileShare -SourceAccountName 'src' -DestinationAccountName 'dst' -ThrottleLimit 65 } | Should -Throw } It 'SourceAccountName is mandatory' { $param = (Get-Command Move-FileShare).Parameters['SourceAccountName'] $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] } | ForEach-Object { $_.Mandatory | Should -BeTrue } } It 'DestinationAccountName is mandatory' { $param = (Get-Command Move-FileShare).Parameters['DestinationAccountName'] $param.Attributes | Where-Object { $_ -is [System.Management.Automation.ParameterAttribute] } | ForEach-Object { $_.Mandatory | Should -BeTrue } } } } |