-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add comprehensive Android testing infrastructure and Fastlane F-Droid setup with root bypass strategy #184
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 2 commits
79dc917
b66baf3
5a66a54
599b820
ab8ea7c
8b62511
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,165 @@ | |||||||||||||||||||||||
| name: Android CI | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| on: | |||||||||||||||||||||||
| push: | |||||||||||||||||||||||
| branches: [ main, develop ] | |||||||||||||||||||||||
| pull_request: | |||||||||||||||||||||||
| branches: [ main, develop ] | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| jobs: | |||||||||||||||||||||||
| test: | |||||||||||||||||||||||
| runs-on: ubuntu-latest | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| steps: | |||||||||||||||||||||||
| - uses: actions/checkout@v4 | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Set up JDK 17 | |||||||||||||||||||||||
| uses: actions/setup-java@v4 | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| java-version: '17' | |||||||||||||||||||||||
| distribution: 'temurin' | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Cache Gradle packages | |||||||||||||||||||||||
| uses: actions/cache@v4 | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| path: | | |||||||||||||||||||||||
| ~/.gradle/caches | |||||||||||||||||||||||
| ~/.gradle/wrapper | |||||||||||||||||||||||
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | |||||||||||||||||||||||
| restore-keys: | | |||||||||||||||||||||||
| ${{ runner.os }}-gradle- | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Grant execute permission for gradlew | |||||||||||||||||||||||
| run: chmod +x android/gradlew | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Run unit tests | |||||||||||||||||||||||
| run: | | |||||||||||||||||||||||
| cd android | |||||||||||||||||||||||
| ./gradlew test --stacktrace | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Build debug APK | |||||||||||||||||||||||
| run: | | |||||||||||||||||||||||
| cd android | |||||||||||||||||||||||
| ./gradlew assembleDebug --stacktrace | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Upload test results | |||||||||||||||||||||||
| uses: actions/upload-artifact@v4 | |||||||||||||||||||||||
| if: always() | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| name: test-results | |||||||||||||||||||||||
| path: android/app/build/reports/tests/ | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| build-fdroid: | |||||||||||||||||||||||
| runs-on: ubuntu-latest | |||||||||||||||||||||||
| needs: test | |||||||||||||||||||||||
| if: github.ref == 'refs/heads/main' | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| steps: | |||||||||||||||||||||||
| - uses: actions/checkout@v4 | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Set up JDK 17 | |||||||||||||||||||||||
| uses: actions/setup-java@v4 | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| java-version: '17' | |||||||||||||||||||||||
| distribution: 'temurin' | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Set up Ruby | |||||||||||||||||||||||
| uses: ruby/setup-ruby@v1 | |||||||||||||||||||||||
Check warningCode scanning / CodeQL Unpinned tag for a non-immutable Action in workflow Medium
Unpinned 3rd party Action 'Android CI' step
Uses Step Error loading related location Loading |
|||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| ruby-version: '3.0' | |||||||||||||||||||||||
| bundler-cache: true | |||||||||||||||||||||||
| working-directory: android | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Cache Gradle packages | |||||||||||||||||||||||
| uses: actions/cache@v4 | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| path: | | |||||||||||||||||||||||
| ~/.gradle/caches | |||||||||||||||||||||||
| ~/.gradle/wrapper | |||||||||||||||||||||||
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | |||||||||||||||||||||||
| restore-keys: | | |||||||||||||||||||||||
| ${{ runner.os }}-gradle- | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Grant execute permission for gradlew | |||||||||||||||||||||||
| run: chmod +x android/gradlew | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Install Fastlane | |||||||||||||||||||||||
| run: | | |||||||||||||||||||||||
| cd android | |||||||||||||||||||||||
| gem install fastlane | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Build F-Droid release | |||||||||||||||||||||||
| run: | | |||||||||||||||||||||||
| cd android | |||||||||||||||||||||||
| fastlane fdroid_release | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Upload F-Droid APK | |||||||||||||||||||||||
| uses: actions/upload-artifact@v4 | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| name: fdroid-apk | |||||||||||||||||||||||
| path: android/fastlane/outputs/*.apk | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| screenshots: | |||||||||||||||||||||||
|
Comment on lines
+53
to
+102
Check warningCode scanning / CodeQL Workflow does not contain permissions Medium
Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
Copilot AutofixAI 7 months ago To fix the issue, we will add a
Suggested changeset
1
.github/workflows/android.yml
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
|
|||||||||||||||||||||||
| runs-on: ubuntu-latest | |||||||||||||||||||||||
| needs: test | |||||||||||||||||||||||
| if: github.ref == 'refs/heads/main' | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| steps: | |||||||||||||||||||||||
| - uses: actions/checkout@v4 | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Set up JDK 17 | |||||||||||||||||||||||
| uses: actions/setup-java@v4 | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| java-version: '17' | |||||||||||||||||||||||
| distribution: 'temurin' | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Set up Ruby | |||||||||||||||||||||||
| uses: ruby/setup-ruby@v1 | |||||||||||||||||||||||
Check warningCode scanning / CodeQL Unpinned tag for a non-immutable Action in workflow Medium
Unpinned 3rd party Action 'Android CI' step
Uses Step Error loading related location Loading |
|||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| ruby-version: '3.0' | |||||||||||||||||||||||
| bundler-cache: true | |||||||||||||||||||||||
| working-directory: android | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Enable KVM | |||||||||||||||||||||||
| 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: Cache Gradle packages | |||||||||||||||||||||||
| uses: actions/cache@v4 | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| path: | | |||||||||||||||||||||||
| ~/.gradle/caches | |||||||||||||||||||||||
| ~/.gradle/wrapper | |||||||||||||||||||||||
| key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} | |||||||||||||||||||||||
| restore-keys: | | |||||||||||||||||||||||
| ${{ runner.os }}-gradle- | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Cache AVD | |||||||||||||||||||||||
| uses: actions/cache@v4 | |||||||||||||||||||||||
| id: avd-cache | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| path: | | |||||||||||||||||||||||
| ~/.android/avd/* | |||||||||||||||||||||||
| ~/.android/adb* | |||||||||||||||||||||||
| key: avd-28 | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Create AVD and generate screenshots | |||||||||||||||||||||||
| uses: reactivecircus/android-emulator-runner@v2 | |||||||||||||||||||||||
Check warningCode scanning / CodeQL Unpinned tag for a non-immutable Action in workflow Medium
Unpinned 3rd party Action 'Android CI' step
Uses Step Error loading related location Loading |
|||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| api-level: 28 | |||||||||||||||||||||||
| target: default | |||||||||||||||||||||||
| arch: x86_64 | |||||||||||||||||||||||
| profile: Nexus 6 | |||||||||||||||||||||||
| script: | | |||||||||||||||||||||||
| cd android | |||||||||||||||||||||||
| gem install fastlane | |||||||||||||||||||||||
| ./gradlew assembleDebug assembleDebugAndroidTest | |||||||||||||||||||||||
| fastlane screenshots | |||||||||||||||||||||||
|
|
|||||||||||||||||||||||
| - name: Upload screenshots | |||||||||||||||||||||||
| uses: actions/upload-artifact@v4 | |||||||||||||||||||||||
| with: | |||||||||||||||||||||||
| name: screenshots | |||||||||||||||||||||||
| path: android/fastlane/metadata/android/en-US/images/ | |||||||||||||||||||||||
|
Comment on lines
+103
to
+165
Check warningCode scanning / CodeQL Workflow does not contain permissions Medium
Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
Copilot AutofixAI 7 months ago To fix the issue, we will add a
The
Suggested changeset
1
.github/workflows/android.yml
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
|
|||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| source "https://rubygems.org" | ||
|
|
||
| gem "fastlane" | ||
| gem "screengrab" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| # LibrePods Android Testing & F-Droid Setup | ||
|
|
||
| This directory contains comprehensive testing infrastructure and F-Droid deployment configuration for the LibrePods Android app. | ||
|
|
||
| ## Testing Infrastructure | ||
|
|
||
| ### Overview | ||
| The testing setup includes: | ||
| - **Unit Tests**: Test core functionality with mock data | ||
| - **Instrumented Tests**: UI tests that bypass root setup | ||
| - **Screenshot Tests**: Automated screenshot generation for F-Droid | ||
| - **Mock Data Providers**: Simulate various AirPods states without hardware | ||
|
|
||
| ### Root Setup Bypass | ||
| The key innovation in this testing setup is bypassing the root requirement for testing: | ||
|
|
||
| 1. **Mock RadareOffsetFinder**: Tests mock `isHookOffsetAvailable()` to return `true` | ||
| 2. **Skip Onboarding**: Navigation starts at "settings" instead of "onboarding" | ||
| 3. **Mock AirPods State**: Use `MockData` class to simulate various device states | ||
|
|
||
| ### Running Tests | ||
|
|
||
| #### Unit Tests | ||
| ```bash | ||
| cd android | ||
| ./gradlew test | ||
| ``` | ||
|
|
||
| #### Instrumented Tests | ||
| ```bash | ||
| cd android | ||
| ./gradlew connectedAndroidTest | ||
| ``` | ||
|
|
||
| #### Screenshot Generation | ||
| ```bash | ||
| cd android | ||
| fastlane screenshots | ||
| ``` | ||
|
|
||
| ### Test Structure | ||
|
|
||
| ``` | ||
| app/src/ | ||
| βββ test/java/me/kavishdevar/librepods/ | ||
| β βββ MockData.kt # Mock data providers | ||
| β βββ MainActivityTest.kt # Activity unit tests | ||
| β βββ RootBypassTest.kt # Root bypass validation | ||
| βββ androidTest/java/me/kavishdevar/librepods/ | ||
| β βββ LibrePodsUITest.kt # UI component tests | ||
| β βββ NavigationTest.kt # Navigation flow tests | ||
| β βββ screenshots/ | ||
| β βββ ScreenshotTest.kt # Automated screenshot generation | ||
| ``` | ||
|
|
||
| ### Mock Data | ||
|
|
||
| The `MockData` object provides various AirPods states for testing: | ||
|
|
||
| - `defaultMockState`: Normal connected state with good battery | ||
| - `lowBatteryMockState`: Low battery warning scenario | ||
| - `disconnectedMockState`: Disconnected AirPods | ||
| - `oneEarbudOutMockState`: One earbud removed | ||
|
|
||
| ## F-Droid Setup | ||
|
|
||
| ### Fastlane Configuration | ||
|
|
||
| The app includes Fastlane configuration optimized for F-Droid: | ||
|
|
||
| #### Available Lanes | ||
| - `fastlane test`: Run all tests | ||
| - `fastlane debug`: Build debug APK | ||
| - `fastlane fdroid_release`: Build F-Droid optimized release APK | ||
| - `fastlane screenshots`: Generate automated screenshots | ||
| - `fastlane prepare_fdroid`: Complete F-Droid preparation pipeline | ||
|
|
||
| #### F-Droid Specific Features | ||
| - Unsigned APK generation for F-Droid signing | ||
| - Screenshot automation for app store listings | ||
| - Metadata generation in F-Droid format | ||
| - APK validation and size checking | ||
|
|
||
| ### Metadata Structure | ||
|
|
||
| ``` | ||
| fastlane/metadata/android/en-US/ | ||
| βββ title.txt # App title | ||
| βββ short_description.txt # Brief description | ||
| βββ full_description.txt # Detailed description | ||
| βββ changelogs/ | ||
| β βββ 7.txt # Version 7 changelog | ||
| βββ images/ # Generated screenshots | ||
| βββ phoneScreenshots/ | ||
| βββ tenInchScreenshots/ | ||
| ``` | ||
|
|
||
| ### CI/CD Integration | ||
|
|
||
| GitHub Actions workflow includes: | ||
| - Automated testing on push/PR | ||
| - F-Droid APK builds on main branch | ||
| - Screenshot generation with Android emulator | ||
| - Artifact uploads for releases | ||
|
|
||
| ### Build Variants | ||
|
|
||
| The build configuration supports: | ||
| - **Debug**: Development builds with debugging enabled | ||
| - **Release**: F-Droid optimized builds (unsigned) | ||
|
|
||
| ### Dependencies | ||
|
|
||
| Testing dependencies added: | ||
| - JUnit 4 for unit testing | ||
| - Espresso for UI testing | ||
| - MockK for mocking | ||
| - Robolectric for Android unit tests | ||
| - Screengrab for automated screenshots | ||
| - Compose UI testing framework | ||
|
|
||
| ## Usage for F-Droid Submission | ||
|
|
||
| 1. **Run full pipeline**: | ||
| ```bash | ||
| cd android | ||
| fastlane prepare_fdroid | ||
| ``` | ||
|
|
||
| 2. **Review generated files**: | ||
| - APK: `fastlane/outputs/app-release-unsigned.apk` | ||
| - Screenshots: `fastlane/metadata/android/en-US/images/` | ||
| - Metadata: `fastlane/metadata/android/en-US/` | ||
|
|
||
| 3. **Submit to F-Droid**: | ||
| - Use the generated metadata and APK | ||
| - Screenshots are automatically optimized for F-Droid format | ||
|
|
||
| ## Development Notes | ||
|
|
||
| ### Testing Without Root | ||
| - Tests use mocked `RadareOffsetFinder` to bypass root checks | ||
| - UI tests can access all app screens without actual root access | ||
| - Mock data simulates real AirPods behavior patterns | ||
|
|
||
| ### Screenshot Automation | ||
| - Screenshots are generated using real UI components | ||
| - Mock data ensures consistent visual state | ||
| - Multiple device orientations and screen sizes supported | ||
| - Automatic localization support (currently en-US) | ||
|
|
||
| ### F-Droid Compliance | ||
| - No proprietary dependencies | ||
| - Reproducible builds | ||
| - Proper AGPL v3 licensing | ||
| - No tracking or telemetry in F-Droid builds | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Common Issues | ||
|
|
||
| 1. **Gradle sync fails**: Check Android SDK and JDK versions | ||
| 2. **Screenshot tests fail**: Ensure emulator has sufficient resources | ||
| 3. **Mock data not working**: Verify MockK setup in test dependencies | ||
|
|
||
| ### Debug Commands | ||
|
|
||
| ```bash | ||
| # Check test configuration | ||
| ./gradlew tasks --all | grep test | ||
|
|
||
| # Verbose test output | ||
| ./gradlew test --info | ||
|
|
||
| # Clean build | ||
| ./gradlew clean build | ||
|
|
||
| # Check APK details | ||
| aapt dump badging app/build/outputs/apk/release/app-release-unsigned.apk | ||
| ``` |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Copilot Autofix
AI 7 months ago
To fix the issue, we will add a
permissionsblock at the root of the workflow file. This block will define the minimum required permissions for the workflow. Based on the provided workflow, the jobs primarily involve reading repository contents, caching dependencies, and uploading artifacts. Therefore, thecontents: readpermission is sufficient. If any job requires additional permissions (e.g.,pull-requests: write), they can be specified at the job level.