Skip to content

Commit b66baf3

Browse files
Copilotkavishdevar
andcommitted
Add comprehensive Android testing infrastructure and Fastlane F-Droid setup
Co-authored-by: kavishdevar <46088622+kavishdevar@users.noreply.github.com>
1 parent 79dc917 commit b66baf3

File tree

17 files changed

+1333
-0
lines changed

17 files changed

+1333
-0
lines changed

.github/workflows/android.yml

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
name: Android CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Set up JDK 17
17+
uses: actions/setup-java@v4
18+
with:
19+
java-version: '17'
20+
distribution: 'temurin'
21+
22+
- name: Cache Gradle packages
23+
uses: actions/cache@v4
24+
with:
25+
path: |
26+
~/.gradle/caches
27+
~/.gradle/wrapper
28+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
29+
restore-keys: |
30+
${{ runner.os }}-gradle-
31+
32+
- name: Grant execute permission for gradlew
33+
run: chmod +x android/gradlew
34+
35+
- name: Run unit tests
36+
run: |
37+
cd android
38+
./gradlew test --stacktrace
39+
40+
- name: Build debug APK
41+
run: |
42+
cd android
43+
./gradlew assembleDebug --stacktrace
44+
45+
- name: Upload test results
46+
uses: actions/upload-artifact@v4
47+
if: always()
48+
with:
49+
name: test-results
50+
path: android/app/build/reports/tests/
51+
52+
build-fdroid:
53+
runs-on: ubuntu-latest
54+
needs: test
55+
if: github.ref == 'refs/heads/main'
56+
57+
steps:
58+
- uses: actions/checkout@v4
59+
60+
- name: Set up JDK 17
61+
uses: actions/setup-java@v4
62+
with:
63+
java-version: '17'
64+
distribution: 'temurin'
65+
66+
- name: Set up Ruby
67+
uses: ruby/setup-ruby@v1
68+
with:
69+
ruby-version: '3.0'
70+
bundler-cache: true
71+
working-directory: android
72+
73+
- name: Cache Gradle packages
74+
uses: actions/cache@v4
75+
with:
76+
path: |
77+
~/.gradle/caches
78+
~/.gradle/wrapper
79+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
80+
restore-keys: |
81+
${{ runner.os }}-gradle-
82+
83+
- name: Grant execute permission for gradlew
84+
run: chmod +x android/gradlew
85+
86+
- name: Install Fastlane
87+
run: |
88+
cd android
89+
gem install fastlane
90+
91+
- name: Build F-Droid release
92+
run: |
93+
cd android
94+
fastlane fdroid_release
95+
96+
- name: Upload F-Droid APK
97+
uses: actions/upload-artifact@v4
98+
with:
99+
name: fdroid-apk
100+
path: android/fastlane/outputs/*.apk
101+
102+
screenshots:
103+
runs-on: ubuntu-latest
104+
needs: test
105+
if: github.ref == 'refs/heads/main'
106+
107+
steps:
108+
- uses: actions/checkout@v4
109+
110+
- name: Set up JDK 17
111+
uses: actions/setup-java@v4
112+
with:
113+
java-version: '17'
114+
distribution: 'temurin'
115+
116+
- name: Set up Ruby
117+
uses: ruby/setup-ruby@v1
118+
with:
119+
ruby-version: '3.0'
120+
bundler-cache: true
121+
working-directory: android
122+
123+
- name: Enable KVM
124+
run: |
125+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
126+
sudo udevadm control --reload-rules
127+
sudo udevadm trigger --name-match=kvm
128+
129+
- name: Cache Gradle packages
130+
uses: actions/cache@v4
131+
with:
132+
path: |
133+
~/.gradle/caches
134+
~/.gradle/wrapper
135+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
136+
restore-keys: |
137+
${{ runner.os }}-gradle-
138+
139+
- name: Cache AVD
140+
uses: actions/cache@v4
141+
id: avd-cache
142+
with:
143+
path: |
144+
~/.android/avd/*
145+
~/.android/adb*
146+
key: avd-28
147+
148+
- name: Create AVD and generate screenshots
149+
uses: reactivecircus/android-emulator-runner@v2
150+
with:
151+
api-level: 28
152+
target: default
153+
arch: x86_64
154+
profile: Nexus 6
155+
script: |
156+
cd android
157+
gem install fastlane
158+
./gradlew assembleDebug assembleDebugAndroidTest
159+
fastlane screenshots
160+
161+
- name: Upload screenshots
162+
uses: actions/upload-artifact@v4
163+
with:
164+
name: screenshots
165+
path: android/fastlane/metadata/android/en-US/images/

android/Gemfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
source "https://rubygems.org"
2+
3+
gem "fastlane"
4+
gem "screengrab"

android/TESTING.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# LibrePods Android Testing & F-Droid Setup
2+
3+
This directory contains comprehensive testing infrastructure and F-Droid deployment configuration for the LibrePods Android app.
4+
5+
## Testing Infrastructure
6+
7+
### Overview
8+
The testing setup includes:
9+
- **Unit Tests**: Test core functionality with mock data
10+
- **Instrumented Tests**: UI tests that bypass root setup
11+
- **Screenshot Tests**: Automated screenshot generation for F-Droid
12+
- **Mock Data Providers**: Simulate various AirPods states without hardware
13+
14+
### Root Setup Bypass
15+
The key innovation in this testing setup is bypassing the root requirement for testing:
16+
17+
1. **Mock RadareOffsetFinder**: Tests mock `isHookOffsetAvailable()` to return `true`
18+
2. **Skip Onboarding**: Navigation starts at "settings" instead of "onboarding"
19+
3. **Mock AirPods State**: Use `MockData` class to simulate various device states
20+
21+
### Running Tests
22+
23+
#### Unit Tests
24+
```bash
25+
cd android
26+
./gradlew test
27+
```
28+
29+
#### Instrumented Tests
30+
```bash
31+
cd android
32+
./gradlew connectedAndroidTest
33+
```
34+
35+
#### Screenshot Generation
36+
```bash
37+
cd android
38+
fastlane screenshots
39+
```
40+
41+
### Test Structure
42+
43+
```
44+
app/src/
45+
├── test/java/me/kavishdevar/librepods/
46+
│ ├── MockData.kt # Mock data providers
47+
│ ├── MainActivityTest.kt # Activity unit tests
48+
│ └── RootBypassTest.kt # Root bypass validation
49+
├── androidTest/java/me/kavishdevar/librepods/
50+
│ ├── LibrePodsUITest.kt # UI component tests
51+
│ ├── NavigationTest.kt # Navigation flow tests
52+
│ └── screenshots/
53+
│ └── ScreenshotTest.kt # Automated screenshot generation
54+
```
55+
56+
### Mock Data
57+
58+
The `MockData` object provides various AirPods states for testing:
59+
60+
- `defaultMockState`: Normal connected state with good battery
61+
- `lowBatteryMockState`: Low battery warning scenario
62+
- `disconnectedMockState`: Disconnected AirPods
63+
- `oneEarbudOutMockState`: One earbud removed
64+
65+
## F-Droid Setup
66+
67+
### Fastlane Configuration
68+
69+
The app includes Fastlane configuration optimized for F-Droid:
70+
71+
#### Available Lanes
72+
- `fastlane test`: Run all tests
73+
- `fastlane debug`: Build debug APK
74+
- `fastlane fdroid_release`: Build F-Droid optimized release APK
75+
- `fastlane screenshots`: Generate automated screenshots
76+
- `fastlane prepare_fdroid`: Complete F-Droid preparation pipeline
77+
78+
#### F-Droid Specific Features
79+
- Unsigned APK generation for F-Droid signing
80+
- Screenshot automation for app store listings
81+
- Metadata generation in F-Droid format
82+
- APK validation and size checking
83+
84+
### Metadata Structure
85+
86+
```
87+
fastlane/metadata/android/en-US/
88+
├── title.txt # App title
89+
├── short_description.txt # Brief description
90+
├── full_description.txt # Detailed description
91+
├── changelogs/
92+
│ └── 7.txt # Version 7 changelog
93+
└── images/ # Generated screenshots
94+
├── phoneScreenshots/
95+
└── tenInchScreenshots/
96+
```
97+
98+
### CI/CD Integration
99+
100+
GitHub Actions workflow includes:
101+
- Automated testing on push/PR
102+
- F-Droid APK builds on main branch
103+
- Screenshot generation with Android emulator
104+
- Artifact uploads for releases
105+
106+
### Build Variants
107+
108+
The build configuration supports:
109+
- **Debug**: Development builds with debugging enabled
110+
- **Release**: F-Droid optimized builds (unsigned)
111+
112+
### Dependencies
113+
114+
Testing dependencies added:
115+
- JUnit 4 for unit testing
116+
- Espresso for UI testing
117+
- MockK for mocking
118+
- Robolectric for Android unit tests
119+
- Screengrab for automated screenshots
120+
- Compose UI testing framework
121+
122+
## Usage for F-Droid Submission
123+
124+
1. **Run full pipeline**:
125+
```bash
126+
cd android
127+
fastlane prepare_fdroid
128+
```
129+
130+
2. **Review generated files**:
131+
- APK: `fastlane/outputs/app-release-unsigned.apk`
132+
- Screenshots: `fastlane/metadata/android/en-US/images/`
133+
- Metadata: `fastlane/metadata/android/en-US/`
134+
135+
3. **Submit to F-Droid**:
136+
- Use the generated metadata and APK
137+
- Screenshots are automatically optimized for F-Droid format
138+
139+
## Development Notes
140+
141+
### Testing Without Root
142+
- Tests use mocked `RadareOffsetFinder` to bypass root checks
143+
- UI tests can access all app screens without actual root access
144+
- Mock data simulates real AirPods behavior patterns
145+
146+
### Screenshot Automation
147+
- Screenshots are generated using real UI components
148+
- Mock data ensures consistent visual state
149+
- Multiple device orientations and screen sizes supported
150+
- Automatic localization support (currently en-US)
151+
152+
### F-Droid Compliance
153+
- No proprietary dependencies
154+
- Reproducible builds
155+
- Proper AGPL v3 licensing
156+
- No tracking or telemetry in F-Droid builds
157+
158+
## Troubleshooting
159+
160+
### Common Issues
161+
162+
1. **Gradle sync fails**: Check Android SDK and JDK versions
163+
2. **Screenshot tests fail**: Ensure emulator has sufficient resources
164+
3. **Mock data not working**: Verify MockK setup in test dependencies
165+
166+
### Debug Commands
167+
168+
```bash
169+
# Check test configuration
170+
./gradlew tasks --all | grep test
171+
172+
# Verbose test output
173+
./gradlew test --info
174+
175+
# Clean build
176+
./gradlew clean build
177+
178+
# Check APK details
179+
aapt dump badging app/build/outputs/apk/release/app-release-unsigned.apk
180+
```

0 commit comments

Comments
 (0)