-
-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add Android support (adb, SauceLabs) #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 47 commits
b1d7d0f
86e48f9
927b225
4a55e0a
bd38cdc
26c1d8e
a3e4fce
7635aaa
da7d0da
c50bc0c
cba2075
42c246a
7c0bb74
3d5dd3e
842b08d
d9e7839
db0f6b1
ec9f09d
c1f33de
d3b0813
ff45311
c0d3757
f41f9fe
8578335
e9551b8
a715195
b207c34
73d96cb
92d93c4
b2ff8d1
e05a67f
31b012a
295c5d8
baa451e
312965a
922266c
cbb67b4
a2a1654
4b229ff
1957e89
5fd78f6
b31283e
5d2c793
da4faeb
d66a5cd
b88b632
e1a9413
f7e5f5c
c4971d8
1ec6480
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,64 @@ | ||||||||||||||||||||
| name: Test ADB Provider | ||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why a separate file? the other one (test-powershell-module.yml) exists just because it's used for multiple modules.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||
| permissions: | ||||||||||||||||||||
| contents: read | ||||||||||||||||||||
|
|
||||||||||||||||||||
| on: | ||||||||||||||||||||
| workflow_call: | ||||||||||||||||||||
| inputs: | ||||||||||||||||||||
| module-path: | ||||||||||||||||||||
| description: 'Path to the module directory' | ||||||||||||||||||||
| required: true | ||||||||||||||||||||
| type: string | ||||||||||||||||||||
|
|
||||||||||||||||||||
| jobs: | ||||||||||||||||||||
| test: | ||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||
| defaults: | ||||||||||||||||||||
| run: | ||||||||||||||||||||
| working-directory: ${{ inputs.module-path }} | ||||||||||||||||||||
| shell: pwsh | ||||||||||||||||||||
|
|
||||||||||||||||||||
| steps: | ||||||||||||||||||||
| - name: Checkout repository | ||||||||||||||||||||
| uses: actions/checkout@v4 | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Enable KVM group permissions | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules | ||||||||||||||||||||
| sudo udevadm control --reload-rules | ||||||||||||||||||||
| sudo udevadm trigger --name-match=kvm | ||||||||||||||||||||
| - name: Setup Android directories | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| mkdir -p $HOME/.android/avd | ||||||||||||||||||||
| touch $HOME/.android/repositories.cfg | ||||||||||||||||||||
| - name: Install Android SDK Build Tools | ||||||||||||||||||||
| shell: bash | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| ${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager --install "build-tools;35.0.0" | ||||||||||||||||||||
| echo "${ANDROID_HOME}/build-tools/35.0.0" >> $GITHUB_PATH | ||||||||||||||||||||
| - name: Run ADB Provider Integration Tests | ||||||||||||||||||||
| uses: reactivecircus/android-emulator-runner@d94c3fbe4fe6a29e4a5ba47c12fb47677c73656b | ||||||||||||||||||||
| timeout-minutes: 45 | ||||||||||||||||||||
| with: | ||||||||||||||||||||
| api-level: 35 | ||||||||||||||||||||
| target: 'google_apis' | ||||||||||||||||||||
| arch: x86_64 | ||||||||||||||||||||
| force-avd-creation: true | ||||||||||||||||||||
| disable-animations: true | ||||||||||||||||||||
| disable-spellchecker: true | ||||||||||||||||||||
| emulator-options: > | ||||||||||||||||||||
| -no-window | ||||||||||||||||||||
| -no-snapshot-save | ||||||||||||||||||||
| -gpu swiftshader_indirect | ||||||||||||||||||||
| -noaudio | ||||||||||||||||||||
| -no-boot-anim | ||||||||||||||||||||
| -camera-back none | ||||||||||||||||||||
| -camera-front none | ||||||||||||||||||||
| script: | | ||||||||||||||||||||
| adb wait-for-device | ||||||||||||||||||||
| echo "Android emulator is ready" | ||||||||||||||||||||
| adb devices | ||||||||||||||||||||
| cd ${{ inputs.module-path }} && pwsh -Command "Invoke-Pester Tests/Adb.Tests.ps1 -CI" | ||||||||||||||||||||
|
Comment on lines
+61
to
+64
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The issue is that each line in the |
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| # Android Helper Functions | ||
| # Shared utilities for Android device providers (ADB and SauceLabs) | ||
|
|
||
| <# | ||
| .SYNOPSIS | ||
| Converts an Android activity path into package name and activity name components. | ||
|
|
||
| .DESCRIPTION | ||
| Converts the ExecutablePath format used by Android apps: "package.name/activity.name" | ||
| Returns a hashtable with PackageName and ActivityName properties. | ||
|
|
||
| .PARAMETER ExecutablePath | ||
| The full activity path in format "package.name/activity.name" | ||
|
|
||
| .EXAMPLE | ||
| ConvertFrom-AndroidActivityPath "io.sentry.unreal.sample/com.epicgames.unreal.GameActivity" | ||
| Returns: @{ PackageName = "io.sentry.unreal.sample"; ActivityName = "com.epicgames.unreal.GameActivity" } | ||
|
|
||
| .EXAMPLE | ||
| ConvertFrom-AndroidActivityPath "com.example.app/.MainActivity" | ||
| Returns: @{ PackageName = "com.example.app"; ActivityName = ".MainActivity" } | ||
| #> | ||
| function ConvertFrom-AndroidActivityPath { | ||
| [CmdletBinding()] | ||
| param( | ||
| [Parameter(Mandatory = $true)] | ||
| [string]$ExecutablePath | ||
| ) | ||
|
|
||
| if ($ExecutablePath -notmatch '^([^/]+)/(.+)$') { | ||
| throw "ExecutablePath must be in format 'package.name/activity.name'. Got: $ExecutablePath" | ||
| } | ||
|
|
||
| return @{ | ||
| PackageName = $matches[1] | ||
| ActivityName = $matches[2] | ||
| } | ||
| } | ||
|
|
||
| <# | ||
| .SYNOPSIS | ||
| Validates that Android Intent extras are in the correct format. | ||
|
|
||
| .DESCRIPTION | ||
| Android Intent extras should be passed in the format understood by `am start`. | ||
| This function validates and optionally formats the arguments string. | ||
|
|
||
| Common Intent extra formats: | ||
| -e key value String extra | ||
| -es key value String extra (explicit) | ||
| -ez key true|false Boolean extra | ||
| -ei key value Integer extra | ||
| -el key value Long extra | ||
|
|
||
| .PARAMETER Arguments | ||
| The arguments string to validate/format | ||
|
|
||
| .EXAMPLE | ||
| Test-IntentExtrasFormat "-e cmdline -crash-capture" | ||
| Returns: $true | ||
|
|
||
| .EXAMPLE | ||
| Test-IntentExtrasFormat "-e test true -ez debug false" | ||
| Returns: $true | ||
| #> | ||
| function Test-IntentExtrasFormat { | ||
| [CmdletBinding()] | ||
| param( | ||
| [Parameter(Mandatory = $false)] | ||
| [string]$Arguments | ||
| ) | ||
|
|
||
| if ([string]::IsNullOrWhiteSpace($Arguments)) { | ||
| return $true | ||
| } | ||
|
|
||
| # Intent extras must start with flags: -e, -es, -ez, -ei, -el, -ef, -eu, etc. | ||
| # Followed by at least one whitespace and additional content | ||
| if ($Arguments -notmatch '^--?[a-z]{1,2}\s+') { | ||
| throw "Invalid Intent extras format: '$Arguments'. Must start with flags like -e, -es, -ez, -ei, -el, etc. followed by key-value pairs." | ||
| } | ||
|
|
||
| return $true | ||
| } | ||
|
|
||
| <# | ||
| .SYNOPSIS | ||
| Extracts the package name from an APK file using aapt. | ||
|
|
||
| .DESCRIPTION | ||
| Extracts the real package name from an APK file using aapt (Android Asset Packaging Tool). | ||
| Requires aapt or aapt2 to be available in PATH. | ||
|
|
||
| .PARAMETER ApkPath | ||
| Path to the APK file | ||
|
|
||
| .EXAMPLE | ||
| Get-ApkPackageName "MyApp.apk" | ||
| Returns: "com.example.myapp" (actual package name from AndroidManifest.xml) | ||
|
|
||
| .EXAMPLE | ||
| Get-ApkPackageName "SentryPlayground.apk" | ||
| Returns: "io.sentry.sample" | ||
|
|
||
| .NOTES | ||
| Requires aapt or aapt2 to be in PATH or Android SDK to be installed. | ||
| Throws an error if aapt is not available or if the package name cannot be extracted. | ||
| #> | ||
| function Get-ApkPackageName { | ||
| [CmdletBinding()] | ||
| param( | ||
| [Parameter(Mandatory = $true)] | ||
| [string]$ApkPath | ||
| ) | ||
|
|
||
| if (-not (Test-Path $ApkPath)) { | ||
| throw "APK file not found: $ApkPath" | ||
| } | ||
|
|
||
| if ($ApkPath -notlike '*.apk') { | ||
| throw "File must be an .apk file. Got: $ApkPath" | ||
| } | ||
|
|
||
| # Find aapt or aapt2 | ||
| $aaptCmd = Get-Command aapt -ErrorAction SilentlyContinue | ||
| if (-not $aaptCmd) { | ||
| $aaptCmd = Get-Command aapt2 -ErrorAction SilentlyContinue | ||
| } | ||
|
|
||
| if (-not $aaptCmd) { | ||
| throw "aapt or aapt2 not found in PATH. Please install Android SDK Build Tools and ensure aapt is available in PATH." | ||
| } | ||
|
|
||
| Write-Debug "Using $($aaptCmd.Name) to extract package name from APK" | ||
|
|
||
| try { | ||
| $PSNativeCommandUseErrorActionPreference = $false | ||
| $output = & $aaptCmd.Name dump badging $ApkPath 2>&1 | ||
|
|
||
| # Parse output for package name: package: name='com.example.app' | ||
| foreach ($line in $output) { | ||
| if ($line -match "package:\s+name='([^']+)'") { | ||
| $packageName = $matches[1] | ||
| Write-Debug "Extracted package name: $packageName" | ||
| return $packageName | ||
| } | ||
| } | ||
|
|
||
| throw "Failed to extract package name from APK using aapt. APK may be corrupted or invalid." | ||
| } | ||
| finally { | ||
| $PSNativeCommandUseErrorActionPreference = $true | ||
| } | ||
| } | ||
|
|
||
| <# | ||
| .SYNOPSIS | ||
| Parses logcat output into structured format. | ||
|
|
||
| .DESCRIPTION | ||
| Converts raw logcat output (array of strings) into a consistent format | ||
| that can be used by test utilities like Get-EventIds. | ||
|
|
||
| .PARAMETER LogcatOutput | ||
| Array of logcat log lines (raw output from adb or SauceLabs) | ||
|
|
||
| .EXAMPLE | ||
| $logs = adb -s emulator-5554 logcat -d | ||
| Format-LogcatOutput $logs | ||
| #> | ||
| function Format-LogcatOutput { | ||
| [CmdletBinding()] | ||
| param( | ||
| [Parameter(Mandatory = $false)] | ||
| [object[]]$LogcatOutput | ||
| ) | ||
|
|
||
| if ($null -eq $LogcatOutput -or $LogcatOutput.Count -eq 0) { | ||
| return @() | ||
| } | ||
|
|
||
| # Ensure output is an array of strings | ||
| return @($LogcatOutput | ForEach-Object { | ||
| if ($null -ne $_) { | ||
| $_.ToString() | ||
| } | ||
| } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.