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.
This commit is contained in:
parent
17f25d41c9
commit
f79d6350c3
4 changed files with 257 additions and 0 deletions
|
|
@ -131,3 +131,50 @@ document paths; **no** real wallet payments until approved.
|
||||||
|
|
||||||
When Android tooling is installed, append a short “installed on …”
|
When Android tooling is installed, append a short “installed on …”
|
||||||
section here (date, `adb version`, AVD name, `ANDROID_HOME`).
|
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 |
|
||||||
|
|
|
||||||
3
scripts/taler-monitoring/android-test/.gitignore
vendored
Normal file
3
scripts/taler-monitoring/android-test/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
apks/*.apk
|
||||||
|
out/
|
||||||
|
*.png
|
||||||
13
scripts/taler-monitoring/android-test/README.md
Normal file
13
scripts/taler-monitoring/android-test/README.md
Normal file
|
|
@ -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).
|
||||||
194
scripts/taler-monitoring/android-test/run-android-pay-smoke.sh
Executable file
194
scripts/taler-monitoring/android-test/run-android-pay-smoke.sh
Executable file
|
|
@ -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."
|
||||||
Loading…
Add table
Add a link
Reference in a new issue