Skip to content

fix: copy symmetric key on export to prevent JSI ArrayBuffer GC corruption #232

fix: copy symmetric key on export to prevent JSI ArrayBuffer GC corruption

fix: copy symmetric key on export to prevent JSI ArrayBuffer GC corruption #232

name: End-to-End Tests for Android
concurrency:
group: '${{ github.workflow }}-${{ github.ref }}'
cancel-in-progress: true
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- '.github/workflows/e2e-android-test.yml'
- 'example/**'
- 'cpp/**'
- 'nitrogen/**'
- 'src/**'
- 'packages/react-native-quick-crypto/android/**'
push:
branches: [main]
paths:
- 'example/**'
- 'cpp/**'
- 'nitrogen/**'
- 'src/**'
- 'packages/react-native-quick-crypto/android/**'
env:
EMULATOR_API_LEVEL: 34
jobs:
# ============================================================================
# Build Job - Gradle build + lint (runs in parallel with AVD setup)
# ============================================================================
build:
name: Build
runs-on: ubuntu-latest
env:
GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.caching=true'
steps:
- name: Maximize build space
uses: AdityaGarg8/remove-unwanted-software@v5
with:
remove-dotnet: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
remove-docker-images: 'true'
- name: Checkout
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: '20'
- name: Install Bun
uses: ./.github/actions/setup-bun
- name: Setup JDK
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '17'
- name: Install System Dependencies
run: |
sudo apt-get update
sudo apt-get install -y libssl-dev pkg-config
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Install Dependencies
run: bun install
- name: Restore Gradle cache
uses: actions/cache/restore@v5
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
example/android/.gradle
example/android/build
example/android/app/.cxx
example/android/app/build
packages/react-native-quick-crypto/android/.cxx
packages/react-native-quick-crypto/android/build
node_modules/.bun/react-native-nitro-modules*/node_modules/react-native-nitro-modules/android/.cxx
node_modules/.bun/react-native-nitro-modules*/node_modules/react-native-nitro-modules/android/build
key: ${{ runner.os }}-gradle-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Build Android App
working-directory: ./example/android
run: |
echo "Building Android app (x86_64 only)..."
./gradlew :app:assembleDebug -PreactNativeArchitectures=x86_64 --build-cache 2>&1 | tee $HOME/android-build.log
- name: Run Gradle Lint
working-directory: ./example/android
run: ./gradlew :react-native-quick-crypto:lintDebug -PreactNativeArchitectures=x86_64
- name: Parse Gradle Lint Report
uses: yutailang0119/action-android-lint@v4
with:
report-path: packages/react-native-quick-crypto/android/build/reports/lint-results-debug.xml
- name: Stop Gradle Daemon
if: always()
working-directory: ./example/android
run: ./gradlew --stop
- name: Upload APK
uses: actions/upload-artifact@v4
with:
name: android-apk
path: example/android/app/build/outputs/apk/debug/app-debug.apk
retention-days: 1
- name: Upload Build Log
if: always()
uses: actions/upload-artifact@v4
with:
name: android-build-log
path: ~/android-build.log
retention-days: 5
- name: Save Gradle cache
if: always()
uses: actions/cache/save@v5
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
example/android/.gradle
example/android/build
example/android/app/.cxx
example/android/app/build
packages/react-native-quick-crypto/android/.cxx
packages/react-native-quick-crypto/android/build
node_modules/.bun/react-native-nitro-modules*/node_modules/react-native-nitro-modules/android/.cxx
node_modules/.bun/react-native-nitro-modules*/node_modules/react-native-nitro-modules/android/build
key: ${{ runner.os }}-gradle-${{ github.run_id }}
# ============================================================================
# AVD Job - Create and cache emulator snapshot (runs in parallel with build)
# ============================================================================
avd:
name: Emulator
runs-on: ubuntu-latest
steps:
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- 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: Restore AVD cache
uses: actions/cache/restore@v5
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-pixel7pro-${{ env.EMULATOR_API_LEVEL }}-${{ github.run_id }}
restore-keys: |
avd-pixel7pro-${{ env.EMULATOR_API_LEVEL }}-
- name: Create AVD and Generate Snapshot for Caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ env.EMULATOR_API_LEVEL }}
arch: x86_64
profile: pixel_7_pro
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
disable-animations: false
script: echo "Generated AVD snapshot for caching."
- name: Save AVD cache
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@v5
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-pixel7pro-${{ env.EMULATOR_API_LEVEL }}-${{ github.run_id }}
# ============================================================================
# Test Job - Run E2E tests (needs both build and AVD)
# ============================================================================
test:
name: Test
needs: [build, avd]
runs-on: ubuntu-latest
env:
OUTPUT_DIR: ~/output
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: '20'
- name: Install Bun
uses: ./.github/actions/setup-bun
- name: Create Directories
run: |
mkdir -p $HOME/output
mkdir -p $HOME/.maestro/tests/
- name: Setup Android SDK
uses: android-actions/setup-android@v3
- name: Restore node_modules cache
uses: actions/cache/restore@v5
with:
path: node_modules
key: ${{ runner.os }}-node-modules-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-node-modules-
- name: Install Dependencies
run: bun install
- name: Save node_modules cache
uses: actions/cache/save@v5
with:
path: node_modules
key: ${{ runner.os }}-node-modules-${{ github.run_id }}
- name: Download APK
uses: actions/download-artifact@v4
with:
name: android-apk
path: example/android/app/build/outputs/apk/debug/
- name: Install Maestro CLI
run: |
export MAESTRO_VERSION=2.0.10
curl -Ls "https://get.maestro.mobile.dev" | bash
echo "$HOME/.maestro/bin" >> $GITHUB_PATH
- 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: Restore AVD cache
uses: actions/cache/restore@v5
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-pixel7pro-${{ env.EMULATOR_API_LEVEL }}-${{ github.run_id }}
restore-keys: |
avd-pixel7pro-${{ env.EMULATOR_API_LEVEL }}-
- name: Run E2E Tests
uses: reactivecircus/android-emulator-runner@v2
id: test_android
continue-on-error: true
with:
api-level: ${{ env.EMULATOR_API_LEVEL }}
arch: x86_64
profile: pixel_7_pro
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -no-metrics
disable-animations: true
working-directory: ./example
script: ./test/e2e/scripts/test-android.sh
- name: Collect Screenshots
if: always()
run: |
mkdir -p $HOME/output/screenshots
LATEST_SCREENSHOT=$(find $HOME/output -name "screenshot-*.png" -type f 2>/dev/null | sort -r | head -1)
if [ -n "$LATEST_SCREENSHOT" ]; then
echo "Copying screenshot from $LATEST_SCREENSHOT to screenshots/android-test-result.png"
cp "$LATEST_SCREENSHOT" $HOME/output/screenshots/android-test-result.png
else
echo "No screenshot found to copy"
fi
- name: Post Maestro Screenshot to PR
if: always()
uses: ./.github/actions/post-maestro-screenshot
with:
platform: android
github-token: ${{ secrets.GITHUB_TOKEN }}
test-outcome: ${{ steps.test_android.outcome }}
imgbb-api-key: ${{ secrets.IMGBB_API_KEY }}
- name: Upload Test Output
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-android-test-output
path: |
${{ env.OUTPUT_DIR }}/*.log
${{ env.OUTPUT_DIR }}/screenshots/*.png
retention-days: 5
- name: Exit with Test Result
if: always()
run: |
if [ "${{ steps.test_android.outcome }}" != "success" ]; then
exit 1
fi