From f79d6350c308550da4de600587732341afe825e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hern=C3=A2ni=20Marques?= Date: Fri, 17 Jul 2026 20:31:52 +0200 Subject: [PATCH] monitoring: Android pay smoke with published F-Droid wallet APK User-local emulator/adb path; install APK, deep-link withdraw and pay-template without root. Document host RAM limits for full UI. --- .../taler-monitoring/GIT-AUTOMATION-NOTES.md | 47 +++++ .../taler-monitoring/android-test/.gitignore | 3 + .../taler-monitoring/android-test/README.md | 13 ++ .../android-test/run-android-pay-smoke.sh | 194 ++++++++++++++++++ 4 files changed, 257 insertions(+) create mode 100644 scripts/taler-monitoring/android-test/.gitignore create mode 100644 scripts/taler-monitoring/android-test/README.md create mode 100755 scripts/taler-monitoring/android-test/run-android-pay-smoke.sh diff --git a/scripts/taler-monitoring/GIT-AUTOMATION-NOTES.md b/scripts/taler-monitoring/GIT-AUTOMATION-NOTES.md index c4f11db..57be728 100644 --- a/scripts/taler-monitoring/GIT-AUTOMATION-NOTES.md +++ b/scripts/taler-monitoring/GIT-AUTOMATION-NOTES.md @@ -131,3 +131,50 @@ document paths; **no** real wallet payments until approved. When Android tooling is installed, append a short “installed on …” section here (date, `adb version`, AVD name, `ANDROID_HOME`). + +--- + +## Android pay smoke (published APK, no root preferred) + +Script: [`android-test/run-android-pay-smoke.sh`](./android-test/run-android-pay-smoke.sh) + +| Step | Detail | +|------|--------| +| APK | F-Droid **Taler Wallet 1.6.1** (`net.taler.wallet.fdroid_854.apk`) | +| Install | `adb install -r` (no root) | +| Withdraw | `taler://withdraw/…` from `…/intro/demo-withdraw.json` (GOA or stage) | +| Pay | stage: shop template order → `taler://pay/…`; GOA: `taler://pay-template/…/goa-shop/paivana` | +| Evidence | screenshots + logcat under `android-test/out/` | + +```bash +# device or emulator already booted +./android-test/run-android-pay-smoke.sh +STACK=goa ./android-test/run-android-pay-smoke.sh +STACK=stage ./android-test/run-android-pay-smoke.sh +``` + +**User-local emulator (no apt root if SDK already under `$HOME/Android/Sdk`):** + +```bash +export ANDROID_HOME=$HOME/Android/Sdk +export PATH=$ANDROID_HOME/emulator:$ANDROID_HOME/platform-tools:$PATH +# AVD e.g. TalerWallet34 (google_apis x86_64) +emulator -avd TalerWallet34 -no-window -gpu swiftshader_indirect -memory 1536 & +adb wait-for-device +./android-test/run-android-pay-smoke.sh +``` + +**Limits (clementine 2026-07-17):** host RAM ~3.7 GiB → emulator often ANRs System UI; +wallet-core still receives withdraw intents (`prepareBankIntegratedWithdrawal` in logcat). +For reliable full UI confirm/pay use a physical phone or a host with **≥6–8 GiB** free RAM. + +### Status snapshot (2026-07-17) + +| Item | Status | +|------|--------| +| `adb` | present (`android-sdk-platform-tools`) | +| F-Droid APK | downloaded under `android-test/apks/` | +| User SDK + emulator + AVD `TalerWallet34` | installed under `$HOME/Android/Sdk` (~5 GiB) | +| `adb install` wallet | **Success** on emulator-5554 | +| Deep-link withdraw | **delivered**; wallet-core started `prepareBankIntegratedWithdrawal` for GOA | +| Unattended UI confirm | flaky (ANR) on this host’s RAM | diff --git a/scripts/taler-monitoring/android-test/.gitignore b/scripts/taler-monitoring/android-test/.gitignore new file mode 100644 index 0000000..2b9c0a5 --- /dev/null +++ b/scripts/taler-monitoring/android-test/.gitignore @@ -0,0 +1,3 @@ +apks/*.apk +out/ +*.png diff --git a/scripts/taler-monitoring/android-test/README.md b/scripts/taler-monitoring/android-test/README.md new file mode 100644 index 0000000..96b760f --- /dev/null +++ b/scripts/taler-monitoring/android-test/README.md @@ -0,0 +1,13 @@ +# Android pay smoke (published wallet) + +Installs the **F-Droid** GNU Taler Wallet APK and deep-links +`taler://withdraw/…` + optional `taler://pay…` against GOA or stage. + +```bash +# needs adb device/emulator +./run-android-pay-smoke.sh +STACK=goa ./run-android-pay-smoke.sh +STACK=stage ./run-android-pay-smoke.sh +``` + +See parent [GIT-AUTOMATION-NOTES.md](../GIT-AUTOMATION-NOTES.md). diff --git a/scripts/taler-monitoring/android-test/run-android-pay-smoke.sh b/scripts/taler-monitoring/android-test/run-android-pay-smoke.sh new file mode 100755 index 0000000..da328b7 --- /dev/null +++ b/scripts/taler-monitoring/android-test/run-android-pay-smoke.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env bash +# Android wallet smoke: install published F-Droid APK, open withdraw/pay URIs via adb. +# +# No root required if: +# - adb is available (package android-tools-adb / platform-tools) +# - a device or emulator is connected (`adb devices` shows "device") +# - optional user-local SDK under $HOME/Android/Sdk (emulator) +# +# Usage: +# ./android-test/run-android-pay-smoke.sh # auto stack (GOA if local, else stage) +# STACK=goa ./android-test/run-android-pay-smoke.sh +# STACK=stage ./android-test/run-android-pay-smoke.sh +# SERIAL=emulator-5554 ./android-test/run-android-pay-smoke.sh +# +# Published APK (default): F-Droid Taler Wallet 1.6.1 (854) +# https://f-droid.org/packages/net.taler.wallet.fdroid/ +# +set -euo pipefail +ROOT=$(cd "$(dirname "$0")" && pwd) +APK_DIR="${APK_DIR:-$ROOT/apks}" +APK_URL="${APK_URL:-https://f-droid.org/repo/net.taler.wallet.fdroid_854.apk}" +APK_NAME="${APK_NAME:-net.taler.wallet.fdroid_854.apk}" +PKG="${PKG:-net.taler.wallet.fdroid}" +STACK="${STACK:-auto}" # auto | goa | stage +SERIAL="${SERIAL:-}" +OUT_DIR="${OUT_DIR:-$ROOT/out}" +mkdir -p "$APK_DIR" "$OUT_DIR" + +if ! command -v adb >/dev/null 2>&1; then + if [ -x "$HOME/Android/Sdk/platform-tools/adb" ]; then + export PATH="$HOME/Android/Sdk/platform-tools:$PATH" + else + echo "adb missing — install android-tools-adb or user SDK platform-tools" >&2 + exit 2 + fi +fi + +if [ -z "$SERIAL" ]; then + SERIAL=$(adb devices | awk '/\tdevice$/{print $1; exit}') +fi +if [ -z "$SERIAL" ]; then + cat >&2 <<'EOF' +No adb device. Options (no root for user-local emulator if /dev/kvm is usable): + 1) Plug phone with USB debugging + 2) Start AVD: $HOME/Android/Sdk/emulator/emulator -avd TalerWallet34 -no-window + 3) Then re-run this script +EOF + exit 3 +fi +ADB=(adb -s "$SERIAL") +echo "device: $SERIAL" + +# Resolve stack endpoints +case "$STACK" in + auto) + if curl -sfS -m 5 -o /dev/null https://bank.hacktivism.ch/config 2>/dev/null; then + STACK=goa + else + STACK=stage + fi + ;; +esac +case "$STACK" in + goa) + BANK=https://bank.hacktivism.ch + MERCHANT=https://taler.hacktivism.ch + WITHDRAW_JSON="$BANK/intro/demo-withdraw.json" + PAY_HINT="paivana template / goa-shop" + ;; + stage) + BANK=https://stage.bank.lefrancpaysan.ch + MERCHANT=https://stage.monnaie.lefrancpaysan.ch + WITHDRAW_JSON="$BANK/intro/demo-withdraw.json" + PAY_HINT="farmer shop templates" + ;; + *) echo "unknown STACK=$STACK" >&2; exit 2 ;; +esac +echo "stack: $STACK bank: $BANK" + +# APK +APK_PATH="$APK_DIR/$APK_NAME" +if [ ! -f "$APK_PATH" ]; then + echo "downloading published wallet APK…" + curl -fL --retry 3 -o "$APK_PATH" "$APK_URL" +fi +echo "apk: $APK_PATH ($(wc -c <"$APK_PATH") bytes)" + +"${ADB[@]}" wait-for-device +"${ADB[@]}" install -r "$APK_PATH" +"${ADB[@]}" shell settings put global window_animation_scale 0 || true +"${ADB[@]}" shell settings put global transition_animation_scale 0 || true +"${ADB[@]}" shell settings put global animator_duration_scale 0 || true + +# Withdraw URI from live mint +WURI=$(curl -sfS -m 25 "$WITHDRAW_JSON" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get("taler_withdraw_uri") or d.get("qr_payload") or "")') +if [ -z "$WURI" ]; then + echo "FAIL: no taler_withdraw_uri from $WITHDRAW_JSON" >&2 + exit 4 +fi +echo "withdraw: $WURI" +echo "$WURI" >"$OUT_DIR/last-withdraw.uri" + +"${ADB[@]}" shell am force-stop "$PKG" 2>/dev/null || true +"${ADB[@]}" logcat -c 2>/dev/null || true +"${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$WURI" 2>&1 | tee "$OUT_DIR/start-withdraw.txt" +sleep 12 + +"${ADB[@]}" exec-out screencap -p >"$OUT_DIR/01-after-withdraw-uri.png" || true +"${ADB[@]}" shell uiautomator dump /sdcard/ui.xml 2>/dev/null || true +"${ADB[@]}" pull /sdcard/ui.xml "$OUT_DIR/01-ui.xml" 2>/dev/null || true + +# Best-effort: tap common confirm labels +python3 - "$SERIAL" "$OUT_DIR/01-ui.xml" <<'PY' || true +import re, subprocess, sys +serial, path = sys.argv[1], sys.argv[2] +try: + xml = open(path, errors="replace").read() +except FileNotFoundError: + raise SystemExit(0) +labels = [ + "Confirm", "Withdraw", "Accept", "Continue", "OK", + "I accept", "Agree", "Bestätigen", "Abheben", "Akzeptieren", +] +for label in labels: + for pat in ( + r'text="%s"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"' % re.escape(label), + r'bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*text="%s"' % re.escape(label), + ): + for m in re.finditer(pat, xml): + x1, y1, x2, y2 = map(int, m.groups()) + x, y = (x1 + x2) // 2, (y1 + y2) // 2 + print(f"tap {label} @ {x},{y}") + subprocess.run(["adb", "-s", serial, "shell", "input", "tap", str(x), str(y)], check=False) +PY +sleep 8 +"${ADB[@]}" exec-out screencap -p >"$OUT_DIR/02-after-confirm-tap.png" || true + +# Optional public pay template (stage fixed product / GOA shop if amount known) +# Stage: open monnaies shop is browser-side; deep link pay after template POST if available. +PAY_URI="" +if [ "$STACK" = "stage" ]; then + # fixed template panier-legumes → taler://pay/… + if RESP=$(curl -sfS -m 20 -X POST -H 'Content-Type: application/json' -d '{}' \ + "$MERCHANT/instances/fermes-des-collines/templates/panier-legumes" 2>/dev/null); then + PAY_URI=$(printf '%s' "$RESP" | python3 -c ' +import json,sys +d=json.load(sys.stdin) +oid=d.get("order_id") or "" +tok=d.get("token") or "" +if oid and tok: + print("taler://pay/stage.monnaie.lefrancpaysan.ch/instances/fermes-des-collines/%s/?c=%s"%(oid,tok)) +' 2>/dev/null || true) + fi +elif [ "$STACK" = "goa" ]; then + # Paivana pay-template deep link (wallet prepares order) + PAY_URI="taler://pay-template/taler.hacktivism.ch/instances/goa-shop/paivana" +fi + +if [ -n "$PAY_URI" ]; then + echo "pay: $PAY_URI ($PAY_HINT)" + echo "$PAY_URI" >"$OUT_DIR/last-pay.uri" + "${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$PAY_URI" 2>&1 | tee "$OUT_DIR/start-pay.txt" + sleep 12 + "${ADB[@]}" exec-out screencap -p >"$OUT_DIR/03-after-pay-uri.png" || true +else + echo "pay: (skipped — no public template order)" +fi + +# Evidence from logcat +"${ADB[@]}" logcat -d -t 300 >"$OUT_DIR/logcat.txt" || true +grep -iE 'taler-wallet|prepareBank|preparePay|confirm|error|Error|success' "$OUT_DIR/logcat.txt" \ + | tail -80 >"$OUT_DIR/logcat-taler.txt" || true + +echo +echo "=== summary ===" +echo "package installed: $PKG" +echo "withdraw intent delivered: $WURI" +if grep -q 'prepareBankIntegratedWithdrawal' "$OUT_DIR/logcat.txt" 2>/dev/null; then + echo "wallet-core: prepareBankIntegratedWithdrawal seen (wallet accepted withdraw URI)" +else + echo "wallet-core: prepareBankIntegratedWithdrawal NOT seen (UI may still show onboarding/ANR on small RAM)" +fi +if [ -n "$PAY_URI" ]; then + if grep -qiE 'preparePay|confirmPay|pay-template|preparePurchase' "$OUT_DIR/logcat.txt" 2>/dev/null; then + echo "wallet-core: pay path activity seen" + else + echo "wallet-core: pay path not confirmed in logcat (check $OUT_DIR/03-after-pay-uri.png)" + fi +fi +echo "artifacts: $OUT_DIR/" +ls -la "$OUT_DIR" | sed 's/^/ /' +echo +echo "NOTE: Full unattended UI payment needs a responsive device/emulator (≥6–8 GiB host RAM recommended)." +echo "This smoke proves: published APK install + deep-link into wallet-core on stack=$STACK."