From ec9151b364ac630d8d8635a56cd17e3ffd5c0eee Mon Sep 17 00:00:00 2001 From: Lilach Date: Mon, 27 Jul 2026 15:19:00 +0100 Subject: [PATCH 1/9] run soak test for move functionality on a weekly basis --- devops-pipelines/move-soak-test.yml | 126 ++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 devops-pipelines/move-soak-test.yml diff --git a/devops-pipelines/move-soak-test.yml b/devops-pipelines/move-soak-test.yml new file mode 100644 index 000000000..11b2998bb --- /dev/null +++ b/devops-pipelines/move-soak-test.yml @@ -0,0 +1,126 @@ +schedules: + - cron: '0 1 * * Sun' + displayName: 'Sun 1am UTC test' + branches: + include: + - task/add-move-soak-test-sceduled-run + always: true + +trigger: none + +parameters: + - name: environment + type: string + default: dev + - name: agentPool + type: string + default: "LACC PreProd Pool" + - name: testFileSizeMb + type: number + default: 2048 # 2GB + +variables: + - group: lacc-automated-testing-${{ parameters.environment }} + - group: lacc-backend-config-${{ parameters.environment }} + +jobs: + - job: runMoveSoakTest + displayName: "Run Move Soak Test with Playwright" + pool: ${{ parameters.agentPool }} + variables: + - name: nodeVersion + value: "20.x" + - name: workingDir + value: "$(System.DefaultWorkingDirectory)/e2e/pw" + + steps: + - task: UseNode@1 + displayName: "Use Node.js" + inputs: + version: "$(nodeVersion)" + + - task: Npm@1 + displayName: "Install NPM Dependencies" + inputs: + command: "ci" + workingDir: "$(workingDir)" + + - script: node_modules/.bin/playwright install --with-deps chromium + displayName: "Install Browsers" + workingDirectory: $(workingDir) + + - script: | + npm run move-soak + workingDirectory: $(workingDir) + displayName: "Run Move Soak Test Scenarios" + env: + BASE_URL: $(RedirectUrlLccUi) + CMS_LOGIN_PAGE: "$(LccApiBaseUrl)/api/tactical/login" + EGRESS_BASE_URL: $(EgressOptionsUrl) + TENANT_ID: $(TenantId) + LCC_API_CLIENT_ID: $(CallingAppValidAudience) + E2E_AD_USER: $(AadUserName) + E2E_AD_PASSWORD: $(AadUserPassword) + CMS_USERNAME: $(CmsUserName) + CMS_PASSWORD: $(CmsUserPassword) + EGRESS_SERVICE_ACCOUNT_AUTH: $(EgressServiceAccountAuth) + DEFAULT_WORKSPACE_ID: $(E2eEgressWorkspaceId) + DEFAULT_WORKSPACE_NAME: $(E2eEgressWorkspaceName) + DEFAULT_CASE_URN: $(E2eTestsCaseUrn) + DEFAULT_CASE_ID: $(E2eTestsCaseId) + LCC_API_BASE_URL: $(LccApiBaseUrl) + NETAPP_OPERATION_NAME: $(E2eNetAppFolderName) + + - task: PublishTestResults@2 + displayName: "Publish Test Results (JUnit)" + inputs: + testResultsFormat: JUnit + testResultsFiles: "$(workingDir)/playwright-report/e2e-test-report.xml" + publishRunAttachments: false + condition: succeededOrFailed() + + - publish: "$(workingDir)/playwright-report" + artifact: "$(System.JobId)-e2e-playwright-report" + displayName: "Publish Report Artifact" + condition: succeededOrFailed() + + - job: cleanupTestFiles + displayName: "Cleanup Test Files from Egress and Shared Drive" + dependsOn: runMoveSoakTest + steps: + - script: | + if command -v pwsh &> /dev/null; then + echo "PowerShell already installed. Skipping installation." + else + echo "Installing PowerShell..." + bash '$(System.DefaultWorkingDirectory)/devops-pipelines/scripts/installPowershell.sh' + echo "Powershel version: $(pwsh -v)" + fi + displayName: "Install PowerShell" + + - task: PowerShell@2 + displayName: "Cleanup existingCaseAutomation NetApp folder" + inputs: + filePath: "$(System.DefaultWorkingDirectory)/devops-pipelines/scripts/test-automation-cleanup/Remove-SharedDriveFolderContent.ps1" + arguments: > + -ClientId $(CallingAppValidAudience) + -TenantId $(TenantId) + -AadUsername $(AadUserName) + -AadPassword $(AadUserPassword) + -CaseId $(E2eTestsCaseId) + -FolderPath "existingCaseAutomation" + -BaseUrl $(LccApiBaseUrl) + -ExcludePatterns "lcc-e2e-fixture-source" + -Force + + - task: PowerShell@2 + displayName: "Clear ExistingCaseAutomation Egress folder" + condition: succeededOrFailed() + inputs: + filePath: "$(System.DefaultWorkingDirectory)/devops-pipelines/scripts/test-automation-cleanup/Clear-EgressFolder.ps1" + arguments: > + -BaseUrl "$(EgressOptionsUrl)" ` + -ServiceAccountAuth "$(EgressServiceAccountAuth)" ` + -WorkspaceId "$(E2eEgressWorkspaceId)" ` + -FolderName "1. ABEs for Transcript" ` + -Force From c4eeb26d8f85e7cdb3f32c7c356629cfb85c85b2 Mon Sep 17 00:00:00 2001 From: Lilach Date: Mon, 27 Jul 2026 15:34:45 +0100 Subject: [PATCH 2/9] run soak test for move functionality on a weekly basis --- devops-pipelines/move-soak-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devops-pipelines/move-soak-test.yml b/devops-pipelines/move-soak-test.yml index 11b2998bb..ba2f93095 100644 --- a/devops-pipelines/move-soak-test.yml +++ b/devops-pipelines/move-soak-test.yml @@ -3,7 +3,7 @@ schedules: displayName: 'Sun 1am UTC test' branches: include: - - task/add-move-soak-test-sceduled-run + - main always: true trigger: none From d65c347f599f0cf32994dd12f26f4d56da62238d Mon Sep 17 00:00:00 2001 From: Lilach Date: Wed, 29 Jul 2026 14:54:47 +0100 Subject: [PATCH 3/9] test pipeline artifact publish --- devops-pipelines/move-playwright-test.yml | 4 ++- devops-pipelines/move-soak-test.yml | 11 +++--- e2e/pw/move-soak/playwright.config.ts | 2 +- e2e/pw/move-soak/tests/move-soak.scenarios.ts | 35 +++++++++++-------- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/devops-pipelines/move-playwright-test.yml b/devops-pipelines/move-playwright-test.yml index c8165e592..3d44fb0f8 100644 --- a/devops-pipelines/move-playwright-test.yml +++ b/devops-pipelines/move-playwright-test.yml @@ -30,6 +30,8 @@ jobs: value: "20.x" - name: workingDir value: "$(System.DefaultWorkingDirectory)/e2e/pw" + - name: transferMaterialsV1 # Staging renders the v1 ("Shared Drive") transfer screen for the E2E user. + value: ${{ ne(parameters.environment, 'dev') }} steps: - task: UseNode@1 @@ -54,7 +56,7 @@ jobs: displayName: "Run E2E Tests" env: CI: true - TRANSFER_MATERIALS_V1: true # Staging renders the v1 ("Shared Drive") transfer screen for the E2E user + TRANSFER_MATERIALS_V1: $(transferMaterialsV1) TEST_FILE_SIZE_MB: ${{ parameters.testFileSizeMb }} BASE_URL: $(RedirectUrlLccUi) CMS_LOGIN_PAGE: "$(LccApiBaseUrl)/api/tactical/login" diff --git a/devops-pipelines/move-soak-test.yml b/devops-pipelines/move-soak-test.yml index ba2f93095..3d083b4d9 100644 --- a/devops-pipelines/move-soak-test.yml +++ b/devops-pipelines/move-soak-test.yml @@ -15,13 +15,12 @@ parameters: - name: agentPool type: string default: "LACC PreProd Pool" - - name: testFileSizeMb - type: number - default: 2048 # 2GB variables: - group: lacc-automated-testing-${{ parameters.environment }} - group: lacc-backend-config-${{ parameters.environment }} + - name: transferMaterialsV1 # Staging renders the v1 ("Shared Drive") transfer screen for the E2E user. + value: ${{ ne(parameters.environment, 'dev') }} jobs: - job: runMoveSoakTest @@ -54,6 +53,7 @@ jobs: workingDirectory: $(workingDir) displayName: "Run Move Soak Test Scenarios" env: + TRANSFER_MATERIALS_V1: $(transferMaterialsV1) BASE_URL: $(RedirectUrlLccUi) CMS_LOGIN_PAGE: "$(LccApiBaseUrl)/api/tactical/login" EGRESS_BASE_URL: $(EgressOptionsUrl) @@ -71,15 +71,16 @@ jobs: LCC_API_BASE_URL: $(LccApiBaseUrl) NETAPP_OPERATION_NAME: $(E2eNetAppFolderName) + - task: PublishTestResults@2 displayName: "Publish Test Results (JUnit)" inputs: testResultsFormat: JUnit - testResultsFiles: "$(workingDir)/playwright-report/e2e-test-report.xml" + testResultsFiles: "$(workingDir)/move-soak/playwright-report/*-e2e-test-report.xml" publishRunAttachments: false condition: succeededOrFailed() - - publish: "$(workingDir)/playwright-report" + - publish: "$(workingDir)/playwright-report/*" artifact: "$(System.JobId)-e2e-playwright-report" displayName: "Publish Report Artifact" condition: succeededOrFailed() diff --git a/e2e/pw/move-soak/playwright.config.ts b/e2e/pw/move-soak/playwright.config.ts index 6c4c9eb64..d7036cf44 100644 --- a/e2e/pw/move-soak/playwright.config.ts +++ b/e2e/pw/move-soak/playwright.config.ts @@ -18,7 +18,7 @@ export default defineConfig({ reporter: [ ["list"], ["html", { outputFolder: `./playwright-report/${runId}` }], - ["junit", { outputFile: `./playwright-report/e2e-test-report-${runId}.xml` }], + ["junit", { outputFile: `./playwright-report/${runId}-e2e-test-report.xml` }], ], timeout: 120_000, expect: { timeout: 500_000 }, diff --git a/e2e/pw/move-soak/tests/move-soak.scenarios.ts b/e2e/pw/move-soak/tests/move-soak.scenarios.ts index 6003442af..d452e48ba 100644 --- a/e2e/pw/move-soak/tests/move-soak.scenarios.ts +++ b/e2e/pw/move-soak/tests/move-soak.scenarios.ts @@ -2,23 +2,30 @@ import { MoveSoakScenario } from "../helpers/types"; export const moveSoakScenarios: MoveSoakScenario[] = [ + // { + // name: "10 x 2GB - one full batch (peak parallel fan-out)", + // specs: [{ fileSizeMb: 2048, fileCount: 10 }], + // timeout: 45 * 60 * 1000, + // }, + // { + // name: "11 x 2GB - crosses the batch boundary into a second batch", + // specs: [{ fileSizeMb: 2048, fileCount: 11 }], + // timeout: 60 * 60 * 1000, + // }, + // { + // name: "Mixed batch - 5 x 2GB + 5 x 5MB share one batch", + // specs: [ + // { fileSizeMb: 2048, fileCount: 5 }, + // { fileSizeMb: 5, fileCount: 5 }, + // ], + // timeout: 45 * 60 * 1000, + // }, { - name: "10 x 2GB - one full batch (peak parallel fan-out)", - specs: [{ fileSizeMb: 2048, fileCount: 10 }], - timeout: 45 * 60 * 1000, - }, - { - name: "11 x 2GB - crosses the batch boundary into a second batch", - specs: [{ fileSizeMb: 2048, fileCount: 11 }], - timeout: 60 * 60 * 1000, - }, - { - name: "Mixed batch - 5 x 2GB + 5 x 5MB share one batch", + name: "test", specs: [ - { fileSizeMb: 2048, fileCount: 5 }, - { fileSizeMb: 5, fileCount: 5 }, + { fileSizeMb: 10, fileCount: 1 } ], - timeout: 45 * 60 * 1000, + timeout: 15 * 60 * 1000, }, ]; From a90b122a0c26b9d509d8b1b0bcc948128629baad Mon Sep 17 00:00:00 2001 From: Lilach Date: Wed, 29 Jul 2026 15:03:28 +0100 Subject: [PATCH 4/9] test pipeline artifact publish --- devops-pipelines/move-soak-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devops-pipelines/move-soak-test.yml b/devops-pipelines/move-soak-test.yml index 3d083b4d9..048f803f5 100644 --- a/devops-pipelines/move-soak-test.yml +++ b/devops-pipelines/move-soak-test.yml @@ -80,7 +80,7 @@ jobs: publishRunAttachments: false condition: succeededOrFailed() - - publish: "$(workingDir)/playwright-report/*" + - publish: "$(workingDir)/move-soak/playwright-report" artifact: "$(System.JobId)-e2e-playwright-report" displayName: "Publish Report Artifact" condition: succeededOrFailed() From 8904e7fb13d5486acbbbd9cf49cd5d4455e895a2 Mon Sep 17 00:00:00 2001 From: Lilach Date: Thu, 30 Jul 2026 09:55:06 +0100 Subject: [PATCH 5/9] use self-hosted pool for cleanup job --- devops-pipelines/move-soak-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/devops-pipelines/move-soak-test.yml b/devops-pipelines/move-soak-test.yml index 048f803f5..74645b9db 100644 --- a/devops-pipelines/move-soak-test.yml +++ b/devops-pipelines/move-soak-test.yml @@ -88,6 +88,7 @@ jobs: - job: cleanupTestFiles displayName: "Cleanup Test Files from Egress and Shared Drive" dependsOn: runMoveSoakTest + pool: ${{ parameters.agentPool }} steps: - script: | if command -v pwsh &> /dev/null; then From 7e151b8f0d953ab1632fddd1064f66c154c7b8e9 Mon Sep 17 00:00:00 2001 From: Lilach Date: Thu, 30 Jul 2026 10:23:07 +0100 Subject: [PATCH 6/9] uncomment real scenarios --- e2e/pw/move-soak/tests/move-soak.scenarios.ts | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/e2e/pw/move-soak/tests/move-soak.scenarios.ts b/e2e/pw/move-soak/tests/move-soak.scenarios.ts index d452e48ba..6003442af 100644 --- a/e2e/pw/move-soak/tests/move-soak.scenarios.ts +++ b/e2e/pw/move-soak/tests/move-soak.scenarios.ts @@ -2,30 +2,23 @@ import { MoveSoakScenario } from "../helpers/types"; export const moveSoakScenarios: MoveSoakScenario[] = [ - // { - // name: "10 x 2GB - one full batch (peak parallel fan-out)", - // specs: [{ fileSizeMb: 2048, fileCount: 10 }], - // timeout: 45 * 60 * 1000, - // }, - // { - // name: "11 x 2GB - crosses the batch boundary into a second batch", - // specs: [{ fileSizeMb: 2048, fileCount: 11 }], - // timeout: 60 * 60 * 1000, - // }, - // { - // name: "Mixed batch - 5 x 2GB + 5 x 5MB share one batch", - // specs: [ - // { fileSizeMb: 2048, fileCount: 5 }, - // { fileSizeMb: 5, fileCount: 5 }, - // ], - // timeout: 45 * 60 * 1000, - // }, { - name: "test", + name: "10 x 2GB - one full batch (peak parallel fan-out)", + specs: [{ fileSizeMb: 2048, fileCount: 10 }], + timeout: 45 * 60 * 1000, + }, + { + name: "11 x 2GB - crosses the batch boundary into a second batch", + specs: [{ fileSizeMb: 2048, fileCount: 11 }], + timeout: 60 * 60 * 1000, + }, + { + name: "Mixed batch - 5 x 2GB + 5 x 5MB share one batch", specs: [ - { fileSizeMb: 10, fileCount: 1 } + { fileSizeMb: 2048, fileCount: 5 }, + { fileSizeMb: 5, fileCount: 5 }, ], - timeout: 15 * 60 * 1000, + timeout: 45 * 60 * 1000, }, ]; From e06af7c10f71c7bc112436012eb0852298ca464a Mon Sep 17 00:00:00 2001 From: Lilach Date: Fri, 31 Jul 2026 10:24:10 +0100 Subject: [PATCH 7/9] increase job timeout to accommodate for long run --- devops-pipelines/move-playwright-test.yml | 6 +++--- devops-pipelines/move-soak-test.yml | 17 +++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/devops-pipelines/move-playwright-test.yml b/devops-pipelines/move-playwright-test.yml index 3d44fb0f8..5b9f2993e 100644 --- a/devops-pipelines/move-playwright-test.yml +++ b/devops-pipelines/move-playwright-test.yml @@ -1,6 +1,6 @@ schedules: - - cron: '0 1 * * Tue-Sat' - displayName: 'Weekday 1am UTC test' + - cron: "0 1 * * Tue-Sat" + displayName: "Weekday 1am UTC test" branches: include: - main @@ -27,7 +27,7 @@ jobs: - group: lacc-automated-testing-${{ parameters.environment }} - group: lacc-backend-config-${{ parameters.environment }} - name: nodeVersion - value: "20.x" + value: "24.x" - name: workingDir value: "$(System.DefaultWorkingDirectory)/e2e/pw" - name: transferMaterialsV1 # Staging renders the v1 ("Shared Drive") transfer screen for the E2E user. diff --git a/devops-pipelines/move-soak-test.yml b/devops-pipelines/move-soak-test.yml index 74645b9db..26959fba7 100644 --- a/devops-pipelines/move-soak-test.yml +++ b/devops-pipelines/move-soak-test.yml @@ -1,6 +1,6 @@ schedules: - - cron: '0 1 * * Sun' - displayName: 'Sun 1am UTC test' + - cron: "0 1 * * Sun" + displayName: "Sun 1am UTC test" branches: include: - main @@ -26,9 +26,10 @@ jobs: - job: runMoveSoakTest displayName: "Run Move Soak Test with Playwright" pool: ${{ parameters.agentPool }} + timeoutInMinutes: 150 variables: - name: nodeVersion - value: "20.x" + value: "24.x" - name: workingDir value: "$(System.DefaultWorkingDirectory)/e2e/pw" @@ -71,7 +72,6 @@ jobs: LCC_API_BASE_URL: $(LccApiBaseUrl) NETAPP_OPERATION_NAME: $(E2eNetAppFolderName) - - task: PublishTestResults@2 displayName: "Publish Test Results (JUnit)" inputs: @@ -88,6 +88,7 @@ jobs: - job: cleanupTestFiles displayName: "Cleanup Test Files from Egress and Shared Drive" dependsOn: runMoveSoakTest + condition: succeededOrFailed() pool: ${{ parameters.agentPool }} steps: - script: | @@ -121,8 +122,8 @@ jobs: inputs: filePath: "$(System.DefaultWorkingDirectory)/devops-pipelines/scripts/test-automation-cleanup/Clear-EgressFolder.ps1" arguments: > - -BaseUrl "$(EgressOptionsUrl)" ` - -ServiceAccountAuth "$(EgressServiceAccountAuth)" ` - -WorkspaceId "$(E2eEgressWorkspaceId)" ` - -FolderName "1. ABEs for Transcript" ` + -BaseUrl "$(EgressOptionsUrl)" + -ServiceAccountAuth "$(EgressServiceAccountAuth)" + -WorkspaceId "$(E2eEgressWorkspaceId)" + -FolderName "1. ABEs for Transcript" -Force From 3c517cdf3b2968d6d81620d28f841097f6c5c2f9 Mon Sep 17 00:00:00 2001 From: Lilach Date: Mon, 3 Aug 2026 15:24:59 +0100 Subject: [PATCH 8/9] remove debug lines --- devops-pipelines/move-playwright-test.yml | 6 +++++- devops-pipelines/move-soak-test.yml | 6 +++++- devops-pipelines/templates/e2e-playwright-test-job.yml | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/devops-pipelines/move-playwright-test.yml b/devops-pipelines/move-playwright-test.yml index 5b9f2993e..ca077ca08 100644 --- a/devops-pipelines/move-playwright-test.yml +++ b/devops-pipelines/move-playwright-test.yml @@ -26,8 +26,12 @@ jobs: variables: - group: lacc-automated-testing-${{ parameters.environment }} - group: lacc-backend-config-${{ parameters.environment }} + # Pin Node.js to v22 because Node.js v24 has a memory retention issue when + # using Undici multipart FormData uploads. Chunked uploads cause RSS to grow + # by approximately the total uploaded file size. This does not reproduce on + # Node.js v22. Revisit when the Node.js/Undici issue is resolved. - name: nodeVersion - value: "24.x" + value: "22.x" - name: workingDir value: "$(System.DefaultWorkingDirectory)/e2e/pw" - name: transferMaterialsV1 # Staging renders the v1 ("Shared Drive") transfer screen for the E2E user. diff --git a/devops-pipelines/move-soak-test.yml b/devops-pipelines/move-soak-test.yml index 26959fba7..58cc54baa 100644 --- a/devops-pipelines/move-soak-test.yml +++ b/devops-pipelines/move-soak-test.yml @@ -28,8 +28,12 @@ jobs: pool: ${{ parameters.agentPool }} timeoutInMinutes: 150 variables: + # Pin Node.js to v22 because Node.js v24 has a memory retention issue when + # using Undici multipart FormData uploads. Chunked uploads cause RSS to grow + # by approximately the total uploaded file size. This does not reproduce on + # Node.js v22. Revisit when the Node.js/Undici issue is resolved. - name: nodeVersion - value: "24.x" + value: "22.x" - name: workingDir value: "$(System.DefaultWorkingDirectory)/e2e/pw" diff --git a/devops-pipelines/templates/e2e-playwright-test-job.yml b/devops-pipelines/templates/e2e-playwright-test-job.yml index 80ac1d199..b61cc5d01 100644 --- a/devops-pipelines/templates/e2e-playwright-test-job.yml +++ b/devops-pipelines/templates/e2e-playwright-test-job.yml @@ -19,8 +19,12 @@ jobs: variables: - group: lacc-automated-testing-${{ parameters.environment }} - group: lacc-backend-config-${{ parameters.environment }} + # Pin Node.js to v22 because Node.js v24 has a memory retention issue when + # using Undici multipart FormData uploads. Chunked uploads cause RSS to grow + # by approximately the total uploaded file size. This does not reproduce on + # Node.js v22. Revisit when the Node.js/Undici issue is resolved. - name: nodeVersion - value: "24.x" + value: "22.x" - name: workingDir value: "$(System.DefaultWorkingDirectory)/e2e/pw" - name: transferMaterialsV1 # Staging renders the v1 ("Shared Drive") transfer screen for the E2E user. From 84b758cb7adf706c109bd9324f5f20658b1d4b63 Mon Sep 17 00:00:00 2001 From: Lilach Date: Tue, 4 Aug 2026 10:22:40 +0100 Subject: [PATCH 9/9] add retry for Egress cleanup script authentication step --- .../Clear-EgressFolder.ps1 | 66 ++++++++++++++++--- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/devops-pipelines/scripts/test-automation-cleanup/Clear-EgressFolder.ps1 b/devops-pipelines/scripts/test-automation-cleanup/Clear-EgressFolder.ps1 index 0121c39ad..6b5a6f864 100644 --- a/devops-pipelines/scripts/test-automation-cleanup/Clear-EgressFolder.ps1 +++ b/devops-pipelines/scripts/test-automation-cleanup/Clear-EgressFolder.ps1 @@ -23,17 +23,63 @@ Import-Module (Join-Path $PSScriptRoot 'EgressCleanupHelperModule.psm1') # ============================================================ Write-Host "[1/3] Authenticating to Egress..." -ForegroundColor Yellow -try { - $AuthHeader = Connect-EgressServiceAccount ` - -BaseUrl $BaseUrl ` - -AuthToken $ServiceAccountAuth -} -catch { - Write-Error $_.Exception.Message - exit 1 -} +$maxAttempts = 3 +$retryDelaySeconds = 15 + +for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) { + try { + + Write-Host "Authentication attempt $attempt/$maxAttempts" -Write-Host " [OK] Authenticated" -ForegroundColor Green + $AuthHeader = Connect-EgressServiceAccount ` + -BaseUrl $BaseUrl ` + -AuthToken $ServiceAccountAuth + + Write-Host " [OK] Authenticated" -ForegroundColor Green + break + } + catch { + Write-Warning "Authentication attempt $attempt failed." + + Write-Warning "Exception type: $($_.Exception.GetType().FullName)" + Write-Warning "Exception message: $($_.Exception.Message)" + + if ($_.Exception.Response) { + try { + $statusCode = [int]$_.Exception.Response.StatusCode + $statusDescription = $_.Exception.Response.StatusDescription + + Write-Warning "HTTP Status: $statusCode $statusDescription" + } + catch {} + + try { + $responseStream = $_.Exception.Response.GetResponseStream() + + if ($responseStream) { + $reader = New-Object System.IO.StreamReader($responseStream) + $responseBody = $reader.ReadToEnd() + + if (-not [string]::IsNullOrWhiteSpace($responseBody)) { + Write-Warning "Response body:" + Write-Warning $responseBody + } + } + } + catch { + Write-Warning "Unable to read error response body." + } + } + + if ($attempt -eq $maxAttempts) { + Write-Error "Authentication failed after $maxAttempts attempts." + exit 1 + } + + Write-Host "Retrying in $retryDelaySeconds seconds..." + Start-Sleep -Seconds $retryDelaySeconds + } +} # ============================================================ # LIST FILES