Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ jobs:
integration-tests:
name: Integration Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 90
# Only run for pushes to main or PRs from the same repo (has access to secrets)
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
needs: [unit-tests, unit-tests-ps51]
Expand Down Expand Up @@ -237,6 +238,7 @@ jobs:

- name: Run Integration Tests
if: steps.check-secrets.outputs.secrets_configured == 'true'
timeout-minutes: 75
shell: pwsh
env:
PLEX_SERVER_URI: ${{ secrets.PLEX_SERVER_URI }}
Expand Down
83 changes: 82 additions & 1 deletion tests/Integration/IntegrationTestHelpers.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,87 @@ function Remove-IntegrationTestServers {
}
}

function Start-SyncProgressMonitor {
<#
.SYNOPSIS
Starts a background timer that reports download progress to CI logs

.PARAMETER Path
The destination directory to monitor for downloaded files

.PARAMETER IntervalSeconds
How often to report progress (default: 30 seconds)

.OUTPUTS
PSCustomObject
Returns a monitor object to pass to Stop-SyncProgressMonitor
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Path,

[Parameter(Mandatory = $false)]
[int]$IntervalSeconds = 30
)

$timer = [System.Timers.Timer]::new($IntervalSeconds * 1000)
$timer.AutoReset = $true

$startTime = [DateTime]::UtcNow
$sourceId = "SyncProgressMonitor-$([Guid]::NewGuid())"
$eventAction = Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier $sourceId -MessageData @{
Path = $Path
StartTime = $startTime
} -Action {
$destination = $Event.MessageData.Path
$elapsed = [DateTime]::UtcNow - $Event.MessageData.StartTime
$elapsedFormatted = '{0}m{1}s' -f [math]::Floor($elapsed.TotalMinutes), $elapsed.Seconds

if (Test-Path $destination) {
$files = Get-ChildItem -Path $destination -Recurse -File -ErrorAction SilentlyContinue
$totalBytes = ($files | Measure-Object -Property Length -Sum -ErrorAction SilentlyContinue).Sum
$totalMB = [math]::Round($totalBytes / 1MB, 1)
Write-Host " [SYNC PROGRESS] $elapsedFormatted elapsed | $($files.Count) files | $totalMB MB downloaded"
}
else {
Write-Host " [SYNC PROGRESS] $elapsedFormatted elapsed | Waiting for first file..."
}
}

$timer.Start()

return [PSCustomObject]@{
Timer = $timer
EventSubscription = $sourceId
StartTime = $startTime
}
Comment thread
tablackburn marked this conversation as resolved.
}

function Stop-SyncProgressMonitor {
<#
.SYNOPSIS
Stops a progress monitor started by Start-SyncProgressMonitor

.PARAMETER Monitor
The monitor object returned by Start-SyncProgressMonitor
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[PSCustomObject]$Monitor
)

$Monitor.Timer.Stop()
Unregister-Event -SourceIdentifier $Monitor.EventSubscription -ErrorAction SilentlyContinue
$Monitor.Timer.Dispose()

$elapsed = [DateTime]::UtcNow - $Monitor.StartTime
$elapsedFormatted = '{0}m{1}s' -f [math]::Floor($elapsed.TotalMinutes), $elapsed.Seconds
Write-Host " [SYNC COMPLETE] Total time: $elapsedFormatted"
}

Export-ModuleMember -Function Test-IntegrationPrerequisites, Get-IntegrationTestContext, `
Get-IntegrationConfigPath, Invoke-IntegrationTestWithRetry, Backup-ServerConfiguration, `
Restore-ServerConfiguration, Remove-IntegrationTestServers
Restore-ServerConfiguration, Remove-IntegrationTestServers, Start-SyncProgressMonitor, `
Stop-SyncProgressMonitor
20 changes: 16 additions & 4 deletions tests/Integration/Public/MediaSync.Integration.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,14 @@ Describe 'Sync-PatMedia Integration Tests' -Skip:(-not $script:integrationEnable
It 'Downloads media files from playlist' {
if (-not $script:hasItems) { Set-ItResult -Skipped -Because 'Travel playlist has no items' }

# This actually downloads! Only runs if playlist has items
$result = Sync-PatMedia -Destination $script:syncDestination -PassThru -Confirm:$false
# Monitor download progress in CI logs (every 30s)
$monitor = Start-SyncProgressMonitor -Path $script:syncDestination
try {
$result = Sync-PatMedia -Destination $script:syncDestination -PassThru -Confirm:$false
}
finally {
Stop-SyncProgressMonitor -Monitor $monitor
}

$result | Should -Not -BeNullOrEmpty

Expand All @@ -273,8 +279,14 @@ Describe 'Sync-PatMedia Integration Tests' -Skip:(-not $script:integrationEnable
It 'Is idempotent - second run downloads nothing' {
if (-not $script:hasItems) { Set-ItResult -Skipped -Because 'Travel playlist has no items' }

# Run sync again - should detect existing files and skip
$result = Sync-PatMedia -Destination $script:syncDestination -PassThru -Confirm:$false
# Monitor for visibility even though this should be fast
$monitor = Start-SyncProgressMonitor -Path $script:syncDestination -IntervalSeconds 10
try {
$result = Sync-PatMedia -Destination $script:syncDestination -PassThru -Confirm:$false
}
finally {
Stop-SyncProgressMonitor -Monitor $monitor
}

# ItemsToAdd should be 0 since files already exist
$result.ItemsToAdd | Should -Be 0
Expand Down