diff --git a/app-runner/Private/AndroidHelpers.ps1 b/app-runner/Private/AndroidHelpers.ps1 index af0c199..48d1f17 100644 --- a/app-runner/Private/AndroidHelpers.ps1 +++ b/app-runner/Private/AndroidHelpers.ps1 @@ -140,3 +140,36 @@ function Format-LogcatOutput { } } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) } + +<# +.SYNOPSIS +Parses a logcat filter string into an array of filterspec tokens. + +.DESCRIPTION +Splits a whitespace-separated logcat filter string into individual "tag[:priority]" +filterspec tokens, as accepted by `adb logcat` and by Appium's logcatFilterSpecs +capability. A tag on its own means "tag:V" (verbose); "*:S" silences everything else. +Empty tokens are removed. + +.PARAMETER FilterString +The raw logcat filter string. May be null or empty, in which case an empty array is returned. + +.EXAMPLE +ConvertTo-LogcatFilterSpec -FilterString "godot:V sentry-native:V *:S" +Returns: @('godot:V', 'sentry-native:V', '*:S') +#> +function ConvertTo-LogcatFilterSpec { + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [AllowNull()] + [AllowEmptyString()] + [string]$FilterString + ) + + if ([string]::IsNullOrWhiteSpace($FilterString)) { + return @() + } + + return @($FilterString -split '\s+' | Where-Object { $_ -ne '' }) +} diff --git a/app-runner/Private/DeviceProviders/SauceLabsProvider.ps1 b/app-runner/Private/DeviceProviders/SauceLabsProvider.ps1 index 22f86f6..07609f0 100644 --- a/app-runner/Private/DeviceProviders/SauceLabsProvider.ps1 +++ b/app-runner/Private/DeviceProviders/SauceLabsProvider.ps1 @@ -31,6 +31,10 @@ Requirements: - SAUCE_REGION - SauceLabs region (e.g., us-west-1, eu-central-1) - SAUCE_DEVICE_NAME - Device name (optional if using -Target parameter) - SAUCE_SESSION_NAME - Session name for SauceLabs dashboard (optional, defaults to "App Runner Test") + - SAUCE_LOGCAT_FILTER - Android only, optional. Whitespace-separated logcat filterspecs + ("tag[:priority]", e.g. "godot:V sentry-native:V *:S") applied to the Appium session via + the logcatFilterSpecs capability, trimming the otherwise very noisy system-wide logcat to + the given tags at capture time. Unset means the full, unfiltered logcat is returned. Note: Device name must match a device available in the specified region. @@ -51,6 +55,7 @@ class SauceLabsProvider : DeviceProvider { [string]$SessionName = $null [string]$CurrentPackageName = $null [string]$MobilePlatform = $null # 'Android' or 'iOS' + [string[]]$LogcatFilterSpecs = @() # Android only: optional logcat filterspecs to trim noisy system logs SauceLabsProvider([string]$MobilePlatform) { if ($MobilePlatform -notin @('Android', 'iOS')) { @@ -73,6 +78,12 @@ class SauceLabsProvider : DeviceProvider { "App Runner $MobilePlatform Test" } + # Read optional logcat filter (Android only). Applied at capture time via the + # logcatFilterSpecs session capability to trim the noisy system-wide logcat. + if ($MobilePlatform -eq 'Android') { + $this.LogcatFilterSpecs = ConvertTo-LogcatFilterSpec -FilterString $env:SAUCE_LOGCAT_FILTER + } + # Validate required credentials if (-not $this.Username -or -not $this.AccessKey) { throw "SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables must be set" @@ -282,6 +293,14 @@ class SauceLabsProvider : DeviceProvider { } } + # Apply logcat filtering at capture time so the driver's logcat buffer only holds the + # requested tags. This keeps app markers from being evicted by the flood of system-wide + # log lines on noisy devices (a full logcat buffer can span only a few seconds). + if ($this.MobilePlatform -eq 'Android' -and $this.LogcatFilterSpecs.Count -gt 0) { + $capabilities.capabilities.alwaysMatch['appium:logcatFilterSpecs'] = $this.LogcatFilterSpecs + Write-Host "Applying logcat filter: $($this.LogcatFilterSpecs -join ' ')" -ForegroundColor Cyan + } + $sessionResponse = $this.InvokeSauceLabsApi('POST', $sessionUri, $capabilities, $false, $null) # Extract session ID (response format varies) diff --git a/app-runner/README.md b/app-runner/README.md index a64f578..c4920bd 100644 --- a/app-runner/README.md +++ b/app-runner/README.md @@ -224,6 +224,10 @@ Connect-Device -Platform "Xbox" -TimeoutSeconds 300 # 5 minutes - SauceLabs account with Real Device Cloud access - Environment variables: `SAUCE_USERNAME`, `SAUCE_ACCESS_KEY`, `SAUCE_REGION` - Valid SauceLabs device ID or capabilities for device selection +- Optional `SAUCE_LOGCAT_FILTER` (Android only): whitespace-separated logcat filterspecs + (`tag[:priority]`, e.g. `godot:V sentry-native:V *:S`) applied via the `logcatFilterSpecs` + session capability to trim the noisy system-wide logcat down to the given tags at capture + time. Unset returns the full logcat. ### Desktop Platform Requirements diff --git a/app-runner/Tests/AndroidHelpers.Tests.ps1 b/app-runner/Tests/AndroidHelpers.Tests.ps1 index e315c02..2885937 100644 --- a/app-runner/Tests/AndroidHelpers.Tests.ps1 +++ b/app-runner/Tests/AndroidHelpers.Tests.ps1 @@ -168,4 +168,33 @@ Describe 'AndroidHelpers' -Tag 'Unit', 'Android' { $result[1] | Should -Be '01-01 12:00:01.000 1234 5678 E Tag: Error with special chars: @#$%^&*()' } } + + Context 'ConvertTo-LogcatFilterSpec' { + It 'Splits a whitespace-separated filter string into filterspecs' { + $result = ConvertTo-LogcatFilterSpec -FilterString 'godot:V sentry-native:V *:S' + + $result.Count | Should -Be 3 + $result[0] | Should -Be 'godot:V' + $result[1] | Should -Be 'sentry-native:V' + $result[2] | Should -Be '*:S' + } + + It 'Collapses runs of whitespace and ignores leading/trailing spaces' { + $result = ConvertTo-LogcatFilterSpec -FilterString " godot:V *:S " + + $result.Count | Should -Be 2 + $result[0] | Should -Be 'godot:V' + $result[1] | Should -Be '*:S' + } + + It 'Returns an empty array for null input' { + $result = @(ConvertTo-LogcatFilterSpec -FilterString $null) + $result.Count | Should -Be 0 + } + + It 'Returns an empty array for whitespace-only input' { + $result = @(ConvertTo-LogcatFilterSpec -FilterString ' ') + $result.Count | Should -Be 0 + } + } }