diff --git a/.github/scripts/smoke-test.sh b/.github/scripts/smoke-test.sh new file mode 100755 index 00000000..2a2da4d1 --- /dev/null +++ b/.github/scripts/smoke-test.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# Installs a release APK on the running emulator, launches it and waits for the +# first-run welcome screen. Fails if the app crashes, dies, or never shows the +# screen. Matches the screen by view id, not text, so it holds in any locale. +set -euo pipefail + +APK="$1" +PKG="io.pezkuwichain.wallet" +OUT="${SMOKE_OUT:-smoke-out}" +TIMEOUT=120 +mkdir -p "$OUT" + +fail() { + echo "::error::$1" + adb exec-out screencap -p > "$OUT/screen.png" || true + adb shell uiautomator dump /sdcard/ui.xml >/dev/null 2>&1 && adb pull /sdcard/ui.xml "$OUT/ui.xml" >/dev/null || true + adb logcat -d > "$OUT/logcat.txt" || true + exit 1 +} + +adb install -r "$APK" >/dev/null || fail "install failed" +adb logcat -c +adb shell monkey -p "$PKG" -c android.intent.category.LAUNCHER 1 >/dev/null 2>&1 || fail "launch failed" + +for _ in $(seq 1 $((TIMEOUT / 3))); do + sleep 3 + if adb logcat -d -b crash | grep -q "Process: $PKG"; then + fail "the app crashed on launch" + fi + adb shell pidof "$PKG" >/dev/null || fail "the app process is gone" + adb shell uiautomator dump /sdcard/ui.xml >/dev/null 2>&1 || continue + if adb exec-out cat /sdcard/ui.xml | grep -q "$PKG:id/welcomeCreateWalletButton" && + adb exec-out cat /sdcard/ui.xml | grep -q "$PKG:id/welcomeRestoreWalletButton"; then + echo "welcome screen shown, both create and restore buttons present" + adb exec-out screencap -p > "$OUT/screen.png" || true + exit 0 + fi +done +fail "the welcome screen did not appear within ${TIMEOUT}s" diff --git a/.github/workflows/appium-mobile-tests.yml b/.github/workflows/appium-mobile-tests.yml deleted file mode 100644 index 7a564e0e..00000000 --- a/.github/workflows/appium-mobile-tests.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Appium Mobile Tests - -on: - workflow_call: - inputs: - app_url: - type: string - description: URL to download the app from - required: true - test_grep: - type: string - description: Test pattern to run (pytest marker or test name) - required: false - default: "android" - allure_job_run_id: - type: string - description: ALLURE_JOB_RUN_ID service parameter. Leave blank. - required: false - default: "" - allure_username: - type: string - description: ALLURE_USERNAME service parameter. Leave blank. - required: false - default: "" - secrets: - WORKFLOW_TOKEN: - required: true - ALLURE_TOKEN: - required: false - -env: - PYTHON_VERSION: '3.9' - CI: true - ALLURE_ENDPOINT: https://pezkuwi.testops.cloud/ - ALLURE_PROJECT_ID: 103 - -permissions: - contents: read - -jobs: - trigger-tests: - runs-on: ubuntu-latest - steps: - - name: Trigger mobile tests in test repository - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.WORKFLOW_TOKEN }} - script: | - const response = await github.rest.actions.createWorkflowDispatch({ - owner: 'pezkuwichain', - repo: 'appium-mobile-tests', - workflow_id: 'browserstack-tests.yml', - ref: 'master', - inputs: { - app_url: '${{ inputs.app_url }}', - ALLURE_JOB_RUN_ID: '${{ inputs.allure_job_run_id }}', - ALLURE_USERNAME: '${{ inputs.allure_username }}' - } - }); - - console.log('Mobile tests triggered successfully'); - console.log('App URL:', '${{ inputs.app_url }}'); - - - name: Wait for test completion (optional) - if: false - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.WORKFLOW_TOKEN }} - script: | - console.log('Waiting for test completion...'); - diff --git a/.github/workflows/emulator_smoke_test.yml b/.github/workflows/emulator_smoke_test.yml new file mode 100644 index 00000000..89455d91 --- /dev/null +++ b/.github/workflows/emulator_smoke_test.yml @@ -0,0 +1,73 @@ +name: Emulator smoke test + +# Installs the release APK on an Android emulator and checks it starts and +# reaches the welcome screen. Called by the release workflow on every build. +# A pull request that changes the test runs it against the latest release APK +# from main; it can also be run by hand against the APK of a given run. + +on: + workflow_call: + workflow_dispatch: + inputs: + run-id: + description: "Run whose 'apk' artifact to test" + required: true + pull_request: + paths: + - .github/workflows/emulator_smoke_test.yml + - .github/scripts/smoke-test.sh + +permissions: + contents: read + actions: read + +jobs: + smoke-test: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + + - name: Pick the APK to test + id: apk + env: + GH_TOKEN: ${{ github.token }} + RUN_ID: ${{ inputs.run-id }} + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + RUN_ID=$(gh api "repos/${{ github.repository }}/actions/artifacts?name=apk&per_page=20" \ + --jq '[.artifacts[] | select(.expired | not) | select(.workflow_run.head_branch == "main")][0].workflow_run.id') + [ -n "$RUN_ID" ] && [ "$RUN_ID" != "null" ] || { echo "::error::no release APK from main to test"; exit 1; } + fi + echo "run-id=${RUN_ID:-${{ github.run_id }}}" >> "$GITHUB_OUTPUT" + + - name: Download built artifact + uses: actions/download-artifact@v4 + with: + name: apk + path: app + run-id: ${{ steps.apk.outputs.run-id }} + github-token: ${{ github.token }} + + - 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: Launch the app on an emulator + uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2.38.0 + with: + api-level: 34 + target: google_apis + arch: x86_64 + disable-animations: true + script: .github/scripts/smoke-test.sh app/releaseMarket/app-releaseMarket.apk + + - name: Upload screen, view tree and logcat + if: always() + uses: actions/upload-artifact@v4 + with: + name: smoke-test-output + path: smoke-out/ + if-no-files-found: ignore diff --git a/.github/workflows/push_develop.yml b/.github/workflows/push_develop.yml index 912981b9..072cfa30 100644 --- a/.github/workflows/push_develop.yml +++ b/.github/workflows/push_develop.yml @@ -69,14 +69,9 @@ jobs: run: | echo "App uploaded to: ${{ steps.s3_upload.outputs.s3_url }}" - appium-mobile-tests: - needs: [upload-to-s3] - if: ${{ always() && needs.upload-to-s3.result == 'success' }} - uses: ./.github/workflows/appium-mobile-tests.yml - with: - app_url: ${{ needs.upload-to-s3.outputs.s3_url }} - test_grep: "android" - allure_job_run_id: "" - secrets: - WORKFLOW_TOKEN: ${{ secrets.PAT_TOKEN }} - ALLURE_TOKEN: ${{ secrets.ALLURE_TOKEN }} + smoke-test: + needs: build + permissions: + contents: read + actions: read + uses: ./.github/workflows/emulator_smoke_test.yml