diff --git a/.github/workflows/test-run-android.yml b/.github/workflows/test-run-android.yml index b73168f32..6f86b1216 100644 --- a/.github/workflows/test-run-android.yml +++ b/.github/workflows/test-run-android.yml @@ -95,7 +95,7 @@ jobs: adb wait-for-device adb shell input keyevent 82 adb devices -l - pwsh -Command '$env:SENTRY_TEST_APK = "samples/IntegrationTest/Build/test.apk"; Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI' + pwsh -Command '$env:SENTRY_TEST_PLATFORM = "Android"; $env:SENTRY_TEST_APP = "samples/IntegrationTest/Build/test.apk"; Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI' - name: Upload test results on failure if: ${{ failure() }} diff --git a/.github/workflows/test-run-desktop.yml b/.github/workflows/test-run-desktop.yml index 283312350..a9da553d2 100644 --- a/.github/workflows/test-run-desktop.yml +++ b/.github/workflows/test-run-desktop.yml @@ -48,16 +48,18 @@ jobs: timeout-minutes: 20 run: | xvfb-run pwsh -Command ' + $env:SENTRY_TEST_PLATFORM = "Desktop"; $env:SENTRY_TEST_APP = "samples/IntegrationTest/Build/test"; - Invoke-Pester -Path test/IntegrationTest/Integration.Tests.Desktop.ps1 -CI' + Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI' shell: bash - name: Run Integration Tests (Windows) if: inputs.platform == 'windows' timeout-minutes: 20 run: | + $env:SENTRY_TEST_PLATFORM = "Desktop" $env:SENTRY_TEST_APP = "samples/IntegrationTest/Build/test.exe" - Invoke-Pester -Path test/IntegrationTest/Integration.Tests.Desktop.ps1 -CI + Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI - name: Upload test results on failure if: ${{ failure() }} diff --git a/.github/workflows/test-run-ios.yml b/.github/workflows/test-run-ios.yml index e3e320c4f..83d639d9d 100644 --- a/.github/workflows/test-run-ios.yml +++ b/.github/workflows/test-run-ios.yml @@ -64,9 +64,10 @@ jobs: id: integration-test timeout-minutes: 20 run: | + $env:SENTRY_TEST_PLATFORM = "iOS" $env:SENTRY_TEST_APP = "samples/IntegrationTest/Build/IntegrationTest.app" $env:SENTRY_IOS_VERSION = "${{ inputs.ios-version }}" - Invoke-Pester -Path test/IntegrationTest/Integration.Tests.iOS.ps1 -CI + Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI echo "status=success" >> $env:GITHUB_OUTPUT - name: Upload test results on failure diff --git a/.github/workflows/test-run-webgl.yml b/.github/workflows/test-run-webgl.yml index 5afc4fc9c..78d82e806 100644 --- a/.github/workflows/test-run-webgl.yml +++ b/.github/workflows/test-run-webgl.yml @@ -41,8 +41,9 @@ jobs: - name: Run Integration Tests timeout-minutes: 20 run: | - $env:SENTRY_WEBGL_BUILD_PATH = "samples/IntegrationTest/Build" - Invoke-Pester -Path test/IntegrationTest/Integration.Tests.WebGL.ps1 -CI + $env:SENTRY_TEST_PLATFORM = "WebGL" + $env:SENTRY_TEST_APP = "samples/IntegrationTest/Build" + Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI - name: Upload test results on failure if: ${{ failure() }} diff --git a/Directory.Build.targets b/Directory.Build.targets index f9cad2841..9375f617a 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -379,7 +379,7 @@ Related: https://forum.unity.com/threads/6572-debugger-agent-unable-to-listen-on - + diff --git a/test/IntegrationTest/Integration.Tests.Desktop.ps1 b/test/IntegrationTest/Integration.Tests.Desktop.ps1 deleted file mode 100644 index 11b3e82e6..000000000 --- a/test/IntegrationTest/Integration.Tests.Desktop.ps1 +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env pwsh -# -# Integration tests for Sentry Unity SDK (Desktop: Windows, Linux) -# -# Environment variables: -# SENTRY_TEST_APP: path to the test executable -# SENTRY_TEST_DSN: test DSN -# SENTRY_AUTH_TOKEN: authentication token for Sentry API - -Set-StrictMode -Version latest -$ErrorActionPreference = "Stop" - -# Import app-runner modules -. $PSScriptRoot/../../modules/app-runner/import-modules.ps1 - -# Import shared test cases and utility functions -. $PSScriptRoot/CommonTestCases.ps1 - -BeforeAll { - # Run integration test action on device - function Invoke-TestAction { - param ( - [Parameter(Mandatory=$true)] - [string]$Action - ) - - Write-Host "Running $Action..." - - $appArgs = @("--test", $Action, "-logFile", "-") - - $runResult = Invoke-DeviceApp -ExecutablePath $env:SENTRY_TEST_APP -Arguments $appArgs - - # Save result to JSON file - $runResult | ConvertTo-Json -Depth 5 | Out-File -FilePath (Get-OutputFilePath "${Action}-result.json") - - # Launch app again to ensure crash report is sent - if ($Action -eq "crash-capture") { - Write-Host "Running crash-send to ensure crash report is sent..." - - $sendArgs = @("--test", "crash-send", "-logFile", "-") - $sendResult = Invoke-DeviceApp -ExecutablePath $env:SENTRY_TEST_APP -Arguments $sendArgs - - # Save crash-send result to JSON for debugging - $sendResult | ConvertTo-Json -Depth 5 | Out-File -FilePath (Get-OutputFilePath "crash-send-result.json") - - # Print crash-send output - Write-Host "::group::App output (crash-send)" - $sendResult.Output | ForEach-Object { Write-Host $_ } - Write-Host "::endgroup::" - - # Attach to runResult for test access - $runResult | Add-Member -NotePropertyName "CrashSendOutput" -NotePropertyValue $sendResult.Output - } - - # Print app output so it's visible in CI logs - Write-Host "::group::App output ($Action)" - $runResult.Output | ForEach-Object { Write-Host $_ } - Write-Host "::endgroup::" - - return $runResult - } - - # Create directory for the test results - New-Item -ItemType Directory -Path "$PSScriptRoot/results/" -ErrorAction Continue 2>&1 | Out-Null - Set-OutputDir -Path "$PSScriptRoot/results/" - - # Initialize test parameters - $script:TestSetup = [PSCustomObject]@{ - Platform = "Desktop" - AppPath = $env:SENTRY_TEST_APP - Dsn = $env:SENTRY_TEST_DSN - AuthToken = $env:SENTRY_AUTH_TOKEN - } - - # Validate environment - if ([string]::IsNullOrEmpty($script:TestSetup.AppPath)) { - throw "SENTRY_TEST_APP environment variable is not set." - } - if (-not (Test-Path $script:TestSetup.AppPath)) { - throw "App not found at: $($script:TestSetup.AppPath)" - } - if ([string]::IsNullOrEmpty($script:TestSetup.Dsn)) { - throw "SENTRY_TEST_DSN environment variable is not set." - } - if ([string]::IsNullOrEmpty($script:TestSetup.AuthToken)) { - throw "SENTRY_AUTH_TOKEN environment variable is not set." - } - - Connect-SentryApi ` - -ApiToken $script:TestSetup.AuthToken ` - -DSN $script:TestSetup.Dsn - - Connect-Device -Platform "Local" -} - - -AfterAll { - Disconnect-SentryApi - Disconnect-Device -} - - -Describe "Unity Desktop Integration Tests" { - - Context "Message Capture" { - BeforeAll { - $script:runEvent = $null - $script:runResult = Invoke-TestAction -Action "message-capture" - - $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 - if ($eventId) { - Write-Host "::group::Getting event content" - $script:runEvent = Get-SentryTestEvent -EventId "$eventId" - Write-Host "::endgroup::" - } - } - - It "" -ForEach $CommonTestCases { - & $testBlock -SentryEvent $runEvent -TestType "message-capture" -RunResult $runResult -TestSetup $script:TestSetup - } - - It "Has message level info" { - ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "info" - } - - It "Has message content" { - $runEvent.title | Should -Not -BeNullOrEmpty - } - } - - Context "Exception Capture" { - BeforeAll { - $script:runEvent = $null - $script:runResult = Invoke-TestAction -Action "exception-capture" - - $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 - if ($eventId) { - Write-Host "::group::Getting event content" - $script:runEvent = Get-SentryTestEvent -EventId "$eventId" - Write-Host "::endgroup::" - } - } - - It "" -ForEach $CommonTestCases { - & $testBlock -SentryEvent $runEvent -TestType "exception-capture" -RunResult $runResult -TestSetup $script:TestSetup - } - - It "Has exception information" { - $runEvent.exception | Should -Not -BeNullOrEmpty - $runEvent.exception.values | Should -Not -BeNullOrEmpty - } - - It "Has exception with stacktrace" { - $exception = $runEvent.exception.values[0] - $exception | Should -Not -BeNullOrEmpty - $exception.type | Should -Not -BeNullOrEmpty - $exception.stacktrace | Should -Not -BeNullOrEmpty - } - - It "Has error level" { - ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "error" - } - } - - Context "Crash Capture" { - BeforeAll { - $script:runEvent = $null - $script:runResult = Invoke-TestAction -Action "crash-capture" - - $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 - if ($eventId) { - Write-Host "::group::Getting event content" - $script:runEvent = Get-SentryTestEvent -TagName "test.crash_id" -TagValue "$eventId" -TimeoutSeconds 120 - Write-Host "::endgroup::" - } - } - - It "" -ForEach $CommonTestCases { - & $testBlock -SentryEvent $runEvent -TestType "crash-capture" -RunResult $runResult -TestSetup $script:TestSetup - } - - It "Has fatal level" { - ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "fatal" - } - - It "Has exception with stacktrace" { - $runEvent.exception | Should -Not -BeNullOrEmpty - $runEvent.exception.values | Should -Not -BeNullOrEmpty - $exception = $runEvent.exception.values[0] - $exception | Should -Not -BeNullOrEmpty - $exception.stacktrace | Should -Not -BeNullOrEmpty - } - - It "Reports crashedLastRun as Crashed on relaunch" { - $crashedLastRunLine = $runResult.CrashSendOutput | Where-Object { - $_ -match "crashedLastRun=Crashed" - } - $crashedLastRunLine | Should -Not -BeNullOrEmpty -Because "Native SDK should report crashedLastRun=Crashed after a native crash" - } - - It "Crash-send completes flush successfully" { - $flushLine = $runResult.CrashSendOutput | Where-Object { - $_ -match "Flush complete" - } - $flushLine | Should -Not -BeNullOrEmpty -Because "crash-send should complete its flush before quitting" - } - } -} diff --git a/test/IntegrationTest/Integration.Tests.WebGL.ps1 b/test/IntegrationTest/Integration.Tests.WebGL.ps1 deleted file mode 100644 index b1a207586..000000000 --- a/test/IntegrationTest/Integration.Tests.WebGL.ps1 +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env pwsh -# -# Integration tests for Sentry Unity SDK (WebGL) -# -# Environment variables: -# SENTRY_WEBGL_BUILD_PATH: path to the WebGL build directory -# SENTRY_TEST_DSN: test DSN -# SENTRY_AUTH_TOKEN: authentication token for Sentry API - -Set-StrictMode -Version latest -$ErrorActionPreference = "Stop" - -# Import app-runner modules -. $PSScriptRoot/../../modules/app-runner/import-modules.ps1 - -# Import shared test cases and utility functions -. $PSScriptRoot/CommonTestCases.ps1 - -BeforeAll { - # Run integration test action via WebGL (HTTP server + headless Chrome) - function Invoke-TestAction { - param ( - [Parameter(Mandatory=$true)] - [string]$Action - ) - - Write-Host "Running $Action..." - - $serverScript = Join-Path $PSScriptRoot "webgl-server.py" - $buildPath = $env:SENTRY_WEBGL_BUILD_PATH - $timeoutSeconds = 120 - - $process = Start-Process -FilePath "python3" ` - -ArgumentList @($serverScript, $buildPath, $Action, $timeoutSeconds) ` - -NoNewWindow -PassThru -RedirectStandardOutput "$PSScriptRoot/results/${Action}-stdout.txt" ` - -RedirectStandardError "$PSScriptRoot/results/${Action}-stderr.txt" - - $process | Wait-Process -Timeout ($timeoutSeconds + 30) - - $exitCode = $process.ExitCode - $stdoutContent = Get-Content "$PSScriptRoot/results/${Action}-stdout.txt" -Raw -ErrorAction SilentlyContinue - $stderrContent = Get-Content "$PSScriptRoot/results/${Action}-stderr.txt" -Raw -ErrorAction SilentlyContinue - - # Parse the JSON array of console lines from stdout - $output = @() - if ($stdoutContent) { - try { - $output = $stdoutContent | ConvertFrom-Json - } - catch { - Write-Host "Failed to parse webgl-server.py output as JSON: $_" - Write-Host "Raw stdout: $stdoutContent" - $output = @($stdoutContent) - } - } - - if ($stderrContent) { - Write-Host "::group::Server stderr ($Action)" - Write-Host $stderrContent - Write-Host "::endgroup::" - } - - $runResult = [PSCustomObject]@{ - Output = $output - ExitCode = $exitCode - } - - # Save result to JSON file - $runResult | ConvertTo-Json -Depth 5 | Out-File -FilePath (Get-OutputFilePath "${Action}-result.json") - - # Print app output so it's visible in CI logs - Write-Host "::group::Browser console output ($Action)" - $runResult.Output | ForEach-Object { Write-Host $_ } - Write-Host "::endgroup::" - - if ($exitCode -ne 0) { - Write-Warning "WebGL test action '$Action' did not complete (exit code: $exitCode)" - } - - return $runResult - } - - # Create directory for the test results - New-Item -ItemType Directory -Path "$PSScriptRoot/results/" -ErrorAction Continue 2>&1 | Out-Null - Set-OutputDir -Path "$PSScriptRoot/results/" - - # Initialize test parameters - $script:TestSetup = [PSCustomObject]@{ - Platform = "WebGL" - BuildPath = $env:SENTRY_WEBGL_BUILD_PATH - Dsn = $env:SENTRY_TEST_DSN - AuthToken = $env:SENTRY_AUTH_TOKEN - } - - # Validate environment - if ([string]::IsNullOrEmpty($script:TestSetup.BuildPath)) { - throw "SENTRY_WEBGL_BUILD_PATH environment variable is not set." - } - if (-not (Test-Path $script:TestSetup.BuildPath)) { - throw "WebGL build not found at: $($script:TestSetup.BuildPath)" - } - if ([string]::IsNullOrEmpty($script:TestSetup.Dsn)) { - throw "SENTRY_TEST_DSN environment variable is not set." - } - if ([string]::IsNullOrEmpty($script:TestSetup.AuthToken)) { - throw "SENTRY_AUTH_TOKEN environment variable is not set." - } - - Connect-SentryApi ` - -ApiToken $script:TestSetup.AuthToken ` - -DSN $script:TestSetup.Dsn -} - - -AfterAll { - Disconnect-SentryApi -} - - -Describe "Unity WebGL Integration Tests" { - - Context "Message Capture" { - BeforeAll { - $script:runEvent = $null - $script:runResult = Invoke-TestAction -Action "message-capture" - - $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 - if ($eventId) { - Write-Host "::group::Getting event content" - $script:runEvent = Get-SentryTestEvent -EventId "$eventId" - Write-Host "::endgroup::" - } - } - - It "" -ForEach $CommonTestCases { - & $testBlock -SentryEvent $runEvent -TestType "message-capture" -RunResult $runResult -TestSetup $script:TestSetup - } - - It "Has message level info" { - ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "info" - } - - It "Has message content" { - $runEvent.title | Should -Not -BeNullOrEmpty - } - } - - Context "Exception Capture" { - BeforeAll { - $script:runEvent = $null - $script:runResult = Invoke-TestAction -Action "exception-capture" - - $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 - if ($eventId) { - Write-Host "::group::Getting event content" - $script:runEvent = Get-SentryTestEvent -EventId "$eventId" - Write-Host "::endgroup::" - } - } - - It "" -ForEach $CommonTestCases { - & $testBlock -SentryEvent $runEvent -TestType "exception-capture" -RunResult $runResult -TestSetup $script:TestSetup - } - - It "Has exception information" { - $runEvent.exception | Should -Not -BeNullOrEmpty - $runEvent.exception.values | Should -Not -BeNullOrEmpty - } - - It "Has exception with stacktrace" { - $exception = $runEvent.exception.values[0] - $exception | Should -Not -BeNullOrEmpty - $exception.type | Should -Not -BeNullOrEmpty - $exception.stacktrace | Should -Not -BeNullOrEmpty - } - - It "Has error level" { - ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "error" - } - } -} diff --git a/test/IntegrationTest/Integration.Tests.iOS.ps1 b/test/IntegrationTest/Integration.Tests.iOS.ps1 deleted file mode 100644 index b1d52a451..000000000 --- a/test/IntegrationTest/Integration.Tests.iOS.ps1 +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/env pwsh -# -# Integration tests for Sentry Unity SDK (iOS Simulator) -# -# Environment variables: -# SENTRY_TEST_APP: path to the test .app bundle -# SENTRY_IOS_VERSION: iOS simulator version (e.g. "17.0" or "latest") -# SENTRY_TEST_DSN: test DSN -# SENTRY_AUTH_TOKEN: authentication token for Sentry API - -Set-StrictMode -Version latest -$ErrorActionPreference = "Stop" - -# Import app-runner modules -. $PSScriptRoot/../../modules/app-runner/import-modules.ps1 - -# Import shared test cases and utility functions -. $PSScriptRoot/CommonTestCases.ps1 - - -BeforeAll { - $script:BundleId = "com.DefaultCompany.IntegrationTest" - - # Run integration test action on device - function Invoke-TestAction { - param ( - [Parameter(Mandatory=$true)] - [string]$Action - ) - - Write-Host "Running $Action..." - - $appArgs = @("--test", $Action) - - $runResult = Invoke-DeviceApp -ExecutablePath $script:BundleId -Arguments $appArgs - - # Save result to JSON file - $runResult | ConvertTo-Json -Depth 5 | Out-File -FilePath (Get-OutputFilePath "${Action}-result.json") - - # Launch app again to ensure crash report is sent - if ($Action -eq "crash-capture") { - Write-Host "Running crash-send to ensure crash report is sent..." - - $sendArgs = @("--test", "crash-send") - $sendResult = Invoke-DeviceApp -ExecutablePath $script:BundleId -Arguments $sendArgs - - # Save crash-send result to JSON for debugging - $sendResult | ConvertTo-Json -Depth 5 | Out-File -FilePath (Get-OutputFilePath "crash-send-result.json") - - # Print crash-send output - Write-Host "::group::App output (crash-send)" - $sendResult.Output | ForEach-Object { Write-Host $_ } - Write-Host "::endgroup::" - - # Attach to runResult for test access - $runResult | Add-Member -NotePropertyName "CrashSendOutput" -NotePropertyValue $sendResult.Output - } - - # Print app output so it's visible in CI logs - Write-Host "::group::App output ($Action)" - $runResult.Output | ForEach-Object { Write-Host $_ } - Write-Host "::endgroup::" - - return $runResult - } - - # Create directory for the test results - New-Item -ItemType Directory -Path "$PSScriptRoot/results/" -ErrorAction Continue 2>&1 | Out-Null - Set-OutputDir -Path "$PSScriptRoot/results/" - - # Initialize test parameters - $script:TestSetup = [PSCustomObject]@{ - Platform = "iOS" - AppPath = $env:SENTRY_TEST_APP - iOSVersion = $env:SENTRY_IOS_VERSION - Dsn = $env:SENTRY_TEST_DSN - AuthToken = $env:SENTRY_AUTH_TOKEN - } - - # Validate environment - if ([string]::IsNullOrEmpty($script:TestSetup.AppPath)) { - throw "SENTRY_TEST_APP environment variable is not set." - } - if (-not (Test-Path $script:TestSetup.AppPath)) { - throw "App not found at: $($script:TestSetup.AppPath)" - } - if ([string]::IsNullOrEmpty($script:TestSetup.iOSVersion)) { - throw "SENTRY_IOS_VERSION environment variable is not set." - } - if ([string]::IsNullOrEmpty($script:TestSetup.Dsn)) { - throw "SENTRY_TEST_DSN environment variable is not set." - } - if ([string]::IsNullOrEmpty($script:TestSetup.AuthToken)) { - throw "SENTRY_AUTH_TOKEN environment variable is not set." - } - - Connect-SentryApi ` - -ApiToken $script:TestSetup.AuthToken ` - -DSN $script:TestSetup.Dsn - - $target = $script:TestSetup.iOSVersion - # Convert bare version numbers (e.g. "17.0") to "iOS 17.0" format expected by iOSSimulatorProvider - if ($target -match '^\d+\.\d+$') { - $target = "iOS $target" - } - Connect-Device -Platform "iOSSimulator" -Target $target - Install-DeviceApp -Path $script:TestSetup.AppPath -} - - -AfterAll { - Disconnect-SentryApi - Disconnect-Device -} - - -Describe "Unity iOS Integration Tests" { - - Context "Message Capture" { - BeforeAll { - $script:runEvent = $null - $script:runResult = Invoke-TestAction -Action "message-capture" - - $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 - if ($eventId) { - Write-Host "::group::Getting event content" - $script:runEvent = Get-SentryTestEvent -EventId "$eventId" - Write-Host "::endgroup::" - } - } - - It "" -ForEach $CommonTestCases { - & $testBlock -SentryEvent $runEvent -TestType "message-capture" -RunResult $runResult -TestSetup $script:TestSetup - } - - It "Has message level info" { - ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "info" - } - - It "Has message content" { - $runEvent.title | Should -Not -BeNullOrEmpty - } - } - - Context "Exception Capture" { - BeforeAll { - $script:runEvent = $null - $script:runResult = Invoke-TestAction -Action "exception-capture" - - $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 - if ($eventId) { - Write-Host "::group::Getting event content" - $script:runEvent = Get-SentryTestEvent -EventId "$eventId" - Write-Host "::endgroup::" - } - } - - It "" -ForEach $CommonTestCases { - & $testBlock -SentryEvent $runEvent -TestType "exception-capture" -RunResult $runResult -TestSetup $script:TestSetup - } - - It "Has exception information" { - $runEvent.exception | Should -Not -BeNullOrEmpty - $runEvent.exception.values | Should -Not -BeNullOrEmpty - } - - It "Has exception with stacktrace" { - $exception = $runEvent.exception.values[0] - $exception | Should -Not -BeNullOrEmpty - $exception.type | Should -Not -BeNullOrEmpty - $exception.stacktrace | Should -Not -BeNullOrEmpty - } - - It "Has error level" { - ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "error" - } - } - - Context "Crash Capture" { - BeforeAll { - $script:runEvent = $null - $script:runResult = Invoke-TestAction -Action "crash-capture" - - $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 - if ($eventId) { - Write-Host "::group::Getting event content" - $script:runEvent = Get-SentryTestEvent -TagName "test.crash_id" -TagValue "$eventId" -TimeoutSeconds 120 - Write-Host "::endgroup::" - } - } - - It "" -ForEach $CommonTestCases { - & $testBlock -SentryEvent $runEvent -TestType "crash-capture" -RunResult $runResult -TestSetup $script:TestSetup - } - - It "Has fatal level" { - ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "fatal" - } - - It "Has exception with stacktrace" { - $runEvent.exception | Should -Not -BeNullOrEmpty - $runEvent.exception.values | Should -Not -BeNullOrEmpty - $exception = $runEvent.exception.values[0] - $exception | Should -Not -BeNullOrEmpty - $exception.stacktrace | Should -Not -BeNullOrEmpty - } - - It "Reports crashedLastRun as Crashed on relaunch" { - $crashedLastRunLine = $runResult.CrashSendOutput | Where-Object { - $_ -match "crashedLastRun=Crashed" - } - $crashedLastRunLine | Should -Not -BeNullOrEmpty -Because "Native SDK should report crashedLastRun=Crashed after a native crash" - } - - It "Crash-send completes flush successfully" { - $flushLine = $runResult.CrashSendOutput | Where-Object { - $_ -match "Flush complete" - } - $flushLine | Should -Not -BeNullOrEmpty -Because "crash-send should complete its flush before quitting" - } - } -} diff --git a/test/IntegrationTest/Integration.Tests.ps1 b/test/IntegrationTest/Integration.Tests.ps1 index 3b4d32be4..e547dc59a 100644 --- a/test/IntegrationTest/Integration.Tests.ps1 +++ b/test/IntegrationTest/Integration.Tests.ps1 @@ -1,11 +1,16 @@ #!/usr/bin/env pwsh # -# Integration tests for Sentry Unity SDK (Android) +# Integration tests for Sentry Unity SDK # # Environment variables: -# SENTRY_TEST_APK: path to the test APK file +# SENTRY_TEST_PLATFORM: target platform (Android, Desktop, iOS, WebGL) # SENTRY_TEST_DSN: test DSN # SENTRY_AUTH_TOKEN: authentication token for Sentry API +# +# SENTRY_TEST_APP: path to the test app (APK, executable, .app bundle, or WebGL build directory) +# +# Platform-specific environment variables: +# iOS: SENTRY_IOS_VERSION - iOS simulator version (e.g. "17.0" or "latest") Set-StrictMode -Version latest $ErrorActionPreference = "Stop" @@ -16,11 +21,80 @@ $ErrorActionPreference = "Stop" # Import shared test cases and utility functions . $PSScriptRoot/CommonTestCases.ps1 - BeforeAll { - $script:PackageName = "io.sentry.unity.integrationtest" + # Build app arguments for a given test action + function Get-AppArguments { + param([string]$Action) + + switch ($script:Platform) { + "Android" { return @("-e", "test", $Action) } + "Desktop" { return @("--test", $Action, "-logFile", "-") } + "iOS" { return @("--test", $Action) } + } + } + + # Run a WebGL test action via headless Chrome + function Invoke-WebGLTestAction { + param ( + [Parameter(Mandatory=$true)] + [string]$Action + ) + + $serverScript = Join-Path $PSScriptRoot "webgl-server.py" + $buildPath = $env:SENTRY_TEST_APP + $timeoutSeconds = 120 + + $process = Start-Process -FilePath "python3" ` + -ArgumentList @($serverScript, $buildPath, $Action, $timeoutSeconds) ` + -NoNewWindow -PassThru -RedirectStandardOutput "$PSScriptRoot/results/${Action}-stdout.txt" ` + -RedirectStandardError "$PSScriptRoot/results/${Action}-stderr.txt" - # Run integration test action on device + $process | Wait-Process -Timeout ($timeoutSeconds + 30) -ErrorAction SilentlyContinue + + $exitCode = $process.ExitCode + $stdoutContent = Get-Content "$PSScriptRoot/results/${Action}-stdout.txt" -Raw -ErrorAction SilentlyContinue + $stderrContent = Get-Content "$PSScriptRoot/results/${Action}-stderr.txt" -Raw -ErrorAction SilentlyContinue + + # Parse the JSON array of console lines from stdout + $output = @() + if ($stdoutContent) { + try { + $output = $stdoutContent | ConvertFrom-Json + } + catch { + Write-Host "Failed to parse webgl-server.py output as JSON: $_" + Write-Host "Raw stdout: $stdoutContent" + $output = @($stdoutContent) + } + } + + if ($stderrContent) { + Write-Host "::group::Server stderr ($Action)" + Write-Host $stderrContent + Write-Host "::endgroup::" + } + + $runResult = [PSCustomObject]@{ + Output = $output + ExitCode = $exitCode + } + + # Save result to JSON file + $runResult | ConvertTo-Json -Depth 5 | Out-File -FilePath (Get-OutputFilePath "${Action}-result.json") + + # Print app output so it's visible in CI logs + Write-Host "::group::Browser console output ($Action)" + $runResult.Output | ForEach-Object { Write-Host $_ } + Write-Host "::endgroup::" + + if ($exitCode -ne 0) { + Write-Warning "WebGL test action '$Action' did not complete (exit code: $exitCode)" + } + + return $runResult + } + + # Run integration test action function Invoke-TestAction { param ( [Parameter(Mandatory=$true)] @@ -29,9 +103,12 @@ BeforeAll { Write-Host "Running $Action..." - $extras = @("-e", "test", $Action) + if ($script:Platform -eq "WebGL") { + return Invoke-WebGLTestAction -Action $Action + } - $runResult = Invoke-DeviceApp -ExecutablePath $script:AndroidComponent -Arguments $extras + $appArgs = Get-AppArguments -Action $Action + $runResult = Invoke-DeviceApp -ExecutablePath $script:ExecutablePath -Arguments $appArgs # Save result to JSON file $runResult | ConvertTo-Json -Depth 5 | Out-File -FilePath (Get-OutputFilePath "${Action}-result.json") @@ -40,8 +117,8 @@ BeforeAll { if ($Action -eq "crash-capture") { Write-Host "Running crash-send to ensure crash report is sent..." - $sendExtras = @("-e", "test", "crash-send") - $sendResult = Invoke-DeviceApp -ExecutablePath $script:AndroidComponent -Arguments $sendExtras + $sendArgs = Get-AppArguments -Action "crash-send" + $sendResult = Invoke-DeviceApp -ExecutablePath $script:ExecutablePath -Arguments $sendArgs # Save crash-send result to JSON for debugging $sendResult | ConvertTo-Json -Depth 5 | Out-File -FilePath (Get-OutputFilePath "crash-send-result.json") @@ -63,57 +140,94 @@ BeforeAll { return $runResult } + $script:Platform = $env:SENTRY_TEST_PLATFORM + if ([string]::IsNullOrEmpty($script:Platform)) { + throw "SENTRY_TEST_PLATFORM environment variable is not set. Expected: Android, Desktop, iOS, or WebGL" + } + + # Validate common environment + if ([string]::IsNullOrEmpty($env:SENTRY_TEST_DSN)) { + throw "SENTRY_TEST_DSN environment variable is not set." + } + if ([string]::IsNullOrEmpty($env:SENTRY_AUTH_TOKEN)) { + throw "SENTRY_AUTH_TOKEN environment variable is not set." + } + if ([string]::IsNullOrEmpty($env:SENTRY_TEST_APP)) { + throw "SENTRY_TEST_APP environment variable is not set." + } + if (-not (Test-Path $env:SENTRY_TEST_APP)) { + throw "App not found at: $env:SENTRY_TEST_APP" + } + + # Platform-specific device setup + switch ($script:Platform) { + "Android" { + $script:PackageName = "io.sentry.unity.integrationtest" + + Connect-Device -Platform "Adb" + Install-DeviceApp -Path $env:SENTRY_TEST_APP + + # Detect the launcher activity from the installed package + $dumpOutput = & adb shell dumpsys package $script:PackageName 2>&1 | Out-String + if ($dumpOutput -match "com.unity3d.player.UnityPlayerGameActivity") { + $script:ExecutablePath = "$($script:PackageName)/com.unity3d.player.UnityPlayerGameActivity" + } else { + $script:ExecutablePath = "$($script:PackageName)/com.unity3d.player.UnityPlayerActivity" + } + Write-Host "Detected activity: $($script:ExecutablePath)" + } + "Desktop" { + $script:ExecutablePath = $env:SENTRY_TEST_APP + Connect-Device -Platform "Local" + } + "iOS" { + if ([string]::IsNullOrEmpty($env:SENTRY_IOS_VERSION)) { + throw "SENTRY_IOS_VERSION environment variable is not set." + } + + $script:ExecutablePath = "com.DefaultCompany.IntegrationTest" + + $target = $env:SENTRY_IOS_VERSION + # Convert bare version numbers (e.g. "17.0") to "iOS 17.0" format expected by iOSSimulatorProvider + if ($target -match '^\d+\.\d+$') { + $target = "iOS $target" + } + Connect-Device -Platform "iOSSimulator" -Target $target + Install-DeviceApp -Path $env:SENTRY_TEST_APP + } + "WebGL" { + } + default { + throw "Unknown platform: $($script:Platform). Expected: Android, Desktop, iOS, or WebGL" + } + } + # Create directory for the test results New-Item -ItemType Directory -Path "$PSScriptRoot/results/" -ErrorAction Continue 2>&1 | Out-Null Set-OutputDir -Path "$PSScriptRoot/results/" # Initialize test parameters $script:TestSetup = [PSCustomObject]@{ - Platform = "Android" - ApkPath = $env:SENTRY_TEST_APK + Platform = $script:Platform Dsn = $env:SENTRY_TEST_DSN AuthToken = $env:SENTRY_AUTH_TOKEN } - # Validate environment - if ([string]::IsNullOrEmpty($script:TestSetup.ApkPath)) { - throw "SENTRY_TEST_APK environment variable is not set." - } - if (-not (Test-Path $script:TestSetup.ApkPath)) { - throw "APK not found at: $($script:TestSetup.ApkPath)" - } - if ([string]::IsNullOrEmpty($script:TestSetup.Dsn)) { - throw "SENTRY_TEST_DSN environment variable is not set." - } - if ([string]::IsNullOrEmpty($script:TestSetup.AuthToken)) { - throw "SENTRY_AUTH_TOKEN environment variable is not set." - } - Connect-SentryApi ` -ApiToken $script:TestSetup.AuthToken ` -DSN $script:TestSetup.Dsn - - Connect-Device -Platform "Adb" - Install-DeviceApp -Path $script:TestSetup.ApkPath - - # Detect the launcher activity from the installed package - $dumpOutput = & adb shell dumpsys package $script:PackageName 2>&1 | Out-String - if ($dumpOutput -match "com.unity3d.player.UnityPlayerGameActivity") { - $script:AndroidComponent = "$($script:PackageName)/com.unity3d.player.UnityPlayerGameActivity" - } else { - $script:AndroidComponent = "$($script:PackageName)/com.unity3d.player.UnityPlayerActivity" - } - Write-Host "Detected activity: $($script:AndroidComponent)" } AfterAll { Disconnect-SentryApi - Disconnect-Device + if ($script:Platform -ne "WebGL") { + Disconnect-Device + } } -Describe "Unity Android Integration Tests" { +Describe "Unity $($env:SENTRY_TEST_PLATFORM) Integration Tests" { Context "Message Capture" { BeforeAll { @@ -174,48 +288,60 @@ Describe "Unity Android Integration Tests" { ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "error" } } +} - Context "Crash Capture" { - BeforeAll { - $script:runEvent = $null - $script:runResult = Invoke-TestAction -Action "crash-capture" - - $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 - if ($eventId) { - Write-Host "::group::Getting event content" - $script:runEvent = Get-SentryTestEvent -TagName "test.crash_id" -TagValue "$eventId" -TimeoutSeconds 120 - Write-Host "::endgroup::" +if ($env:SENTRY_TEST_PLATFORM -ne "WebGL") { + Describe "Unity $($env:SENTRY_TEST_PLATFORM) Crash Tests" { + + Context "Crash Capture" { + BeforeAll { + $script:runEvent = $null + $script:runResult = Invoke-TestAction -Action "crash-capture" + + # Validate crash-send completed before polling Sentry (avoids a 300s blind wait) + $flushLine = $runResult.CrashSendOutput | Where-Object { $_ -match "Flush complete" } + if (-not $flushLine) { + $crashSendOutput = ($runResult.CrashSendOutput | Out-String) + throw "crash-send did not complete flush. The crash envelope was likely not sent. Output:`n$crashSendOutput" + } + + $eventId = Get-EventIds -AppOutput $script:runResult.Output -ExpectedCount 1 + if ($eventId) { + Write-Host "::group::Getting event content" + $script:runEvent = Get-SentryTestEvent -TagName "test.crash_id" -TagValue "$eventId" -TimeoutSeconds 300 + Write-Host "::endgroup::" + } } - } - It "" -ForEach $CommonTestCases { - & $testBlock -SentryEvent $runEvent -TestType "crash-capture" -RunResult $runResult -TestSetup $script:TestSetup - } + It "" -ForEach $CommonTestCases { + & $testBlock -SentryEvent $runEvent -TestType "crash-capture" -RunResult $runResult -TestSetup $script:TestSetup + } - It "Has fatal level" { - ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "fatal" - } + It "Has fatal level" { + ($runEvent.tags | Where-Object { $_.key -eq "level" }).value | Should -Be "fatal" + } - It "Has exception with stacktrace" { - $runEvent.exception | Should -Not -BeNullOrEmpty - $runEvent.exception.values | Should -Not -BeNullOrEmpty - $exception = $runEvent.exception.values[0] - $exception | Should -Not -BeNullOrEmpty - $exception.stacktrace | Should -Not -BeNullOrEmpty - } + It "Has exception with stacktrace" { + $runEvent.exception | Should -Not -BeNullOrEmpty + $runEvent.exception.values | Should -Not -BeNullOrEmpty + $exception = $runEvent.exception.values[0] + $exception | Should -Not -BeNullOrEmpty + $exception.stacktrace | Should -Not -BeNullOrEmpty + } - It "Reports crashedLastRun as Crashed on relaunch" { - $crashedLastRunLine = $runResult.CrashSendOutput | Where-Object { - $_ -match "crashedLastRun=Crashed" + It "Reports crashedLastRun as Crashed on relaunch" { + $crashedLastRunLine = $runResult.CrashSendOutput | Where-Object { + $_ -match "crashedLastRun=Crashed" + } + $crashedLastRunLine | Should -Not -BeNullOrEmpty -Because "Native SDK should report crashedLastRun=Crashed after a native crash" } - $crashedLastRunLine | Should -Not -BeNullOrEmpty -Because "Native SDK should report crashedLastRun=Crashed after a native crash" - } - It "Crash-send completes flush successfully" { - $flushLine = $runResult.CrashSendOutput | Where-Object { - $_ -match "Flush complete" + It "Crash-send completes flush successfully" { + $flushLine = $runResult.CrashSendOutput | Where-Object { + $_ -match "Flush complete" + } + $flushLine | Should -Not -BeNullOrEmpty -Because "crash-send should complete its flush before quitting" } - $flushLine | Should -Not -BeNullOrEmpty -Because "crash-send should complete its flush before quitting" } } } diff --git a/test/Scripts.Integration.Test/integration-test.ps1 b/test/Scripts.Integration.Test/integration-test.ps1 index 37c4a4783..06a0b2716 100644 --- a/test/Scripts.Integration.Test/integration-test.ps1 +++ b/test/Scripts.Integration.Test/integration-test.ps1 @@ -86,20 +86,24 @@ Else { Switch -Regex ($Platform) { "^(Windows|MacOS|Linux)$" { + $env:SENTRY_TEST_PLATFORM = "Desktop" $env:SENTRY_TEST_APP = GetNewProjectBuildPath - Invoke-Pester -Path test/IntegrationTest/Integration.Tests.Desktop.ps1 -CI + Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI } "^(Android)$" { - $env:SENTRY_TEST_APK = "$(GetNewProjectBuildPath)/test.apk" + $env:SENTRY_TEST_PLATFORM = "Android" + $env:SENTRY_TEST_APP = "$(GetNewProjectBuildPath)/test.apk" Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI } "^iOS$" { + $env:SENTRY_TEST_PLATFORM = "iOS" $env:SENTRY_TEST_APP = "$(GetNewProjectBuildPath)/IntegrationTest.app" - Invoke-Pester -Path test/IntegrationTest/Integration.Tests.iOS.ps1 -CI + Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI } "^WebGL$" { - $env:SENTRY_WEBGL_BUILD_PATH = GetNewProjectBuildPath - Invoke-Pester -Path test/IntegrationTest/Integration.Tests.WebGL.ps1 -CI + $env:SENTRY_TEST_PLATFORM = "WebGL" + $env:SENTRY_TEST_APP = GetNewProjectBuildPath + Invoke-Pester -Path test/IntegrationTest/Integration.Tests.ps1 -CI } "^Switch$" { Write-PhaseSuccess "Switch build completed - no automated test execution available"