android-test: smoke is withdraw then pay, both first-class
Structure Abheben before Bezahlen with multi-round UI; SMOKE_STRICT requires wallet-core signals for both legs when enabled.
This commit is contained in:
parent
d368b40709
commit
83a3369dd5
4 changed files with 261 additions and 139 deletions
|
|
@ -14,7 +14,7 @@ GUI is planned via flags (below), not required to use these scripts today.
|
||||||
| F-Droid published APK install | **done** | `net.taler.wallet.fdroid` 1.6.1 / 854 |
|
| F-Droid published APK install | **done** | `net.taler.wallet.fdroid` 1.6.1 / 854 |
|
||||||
| Source build + same smoke | **done** | `:wallet:assembleFdroidDebug` → `net.taler.wallet.fdroid.debug` |
|
| Source build + same smoke | **done** | `:wallet:assembleFdroidDebug` → `net.taler.wallet.fdroid.debug` |
|
||||||
| Default source branch | **done** | `dev/hernani-inference/fix-bank-withdraw-auto-exchange` (minimal GOA exchange auto-add) |
|
| Default source branch | **done** | `dev/hernani-inference/fix-bank-withdraw-auto-exchange` (minimal GOA exchange auto-add) |
|
||||||
| Deep-link entry (≡ QR) | **done** | `adb` `VIEW` `taler://withdraw/…` / `taler://pay…` |
|
| Deep-link entry (≡ QR) | **done** | `adb` `VIEW` **withdraw then pay** (`taler://withdraw/…` → `taler://pay…`) |
|
||||||
| Explorer API mint (chain) | **done** | `run-goa-gui-chain.sh` (GOA + stage) |
|
| Explorer API mint (chain) | **done** | `run-goa-gui-chain.sh` (GOA + stage) |
|
||||||
| UI taps via uiautomator | **done** | best-effort Confirm/ToS/Pay; ANR → prefer **Wait** |
|
| UI taps via uiautomator | **done** | best-effort Confirm/ToS/Pay; ANR → prefer **Wait** |
|
||||||
| Screenshots / logcat artifacts | **done** | under `out*`, `out-gui-chain/` (gitignored) |
|
| Screenshots / logcat artifacts | **done** | under `out*`, `out-gui-chain/` (gitignored) |
|
||||||
|
|
@ -38,7 +38,7 @@ Host-CLI-Settlement.
|
||||||
|-----------|----------------|
|
|-----------|----------------|
|
||||||
| APK installieren | F-Droid `net.taler.wallet.fdroid` **oder** Source `assembleFdroidDebug` (`.debug`) |
|
| APK installieren | F-Droid `net.taler.wallet.fdroid` **oder** Source `assembleFdroidDebug` (`.debug`) |
|
||||||
| GOA-Exchange ohne manuelles Add | Source-Build von `fix-bank-withdraw-auto-exchange` (Default in `run-android-build-and-smoke.sh`) |
|
| GOA-Exchange ohne manuelles Add | Source-Build von `fix-bank-withdraw-auto-exchange` (Default in `run-android-build-and-smoke.sh`) |
|
||||||
| Withdraw/Pay **starten** | `adb` deep-link `taler://withdraw/…` / `taler://pay…` (Ersatz für QR-Scan) |
|
| **Abheben + Bezahlen** | Beide Beine: erst Withdraw-URI + Taps, dann Pay-URI + Taps (`DO_WITHDRAW`/`DO_PAY`) |
|
||||||
| Light UI-Drive | Confirm / Accept / Pay-Taps über Label-Suche (`lib_ui.py`, gui-smoke, chain) |
|
| Light UI-Drive | Confirm / Accept / Pay-Taps über Label-Suche (`lib_ui.py`, gui-smoke, chain) |
|
||||||
| Multi-Runden-Taps | `run-android-gui-smoke.sh` / `run-goa-gui-chain.sh` (best-effort) |
|
| Multi-Runden-Taps | `run-android-gui-smoke.sh` / `run-goa-gui-chain.sh` (best-effort) |
|
||||||
| Explorer-Mint (Kette) | `run-goa-gui-chain.sh` + `EXP_PW_FILE` (GOA + stage) |
|
| Explorer-Mint (Kette) | `run-goa-gui-chain.sh` + `EXP_PW_FILE` (GOA + stage) |
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,18 @@
|
||||||
# Android pay smoke
|
# Android wallet smoke (Abheben + Bezahlen)
|
||||||
|
|
||||||
## 1) Published F-Droid wallet
|
Smokes always cover **withdraw first**, then **pay** (not pay-only).
|
||||||
|
|
||||||
|
| Leg | Default | What |
|
||||||
|
|-----|---------|------|
|
||||||
|
| **1 WITHDRAW** | on | `taler://withdraw/…` + Confirm/Abheben taps |
|
||||||
|
| **2 PAY** | on | `taler://pay…` / pay-template + Pay taps |
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# needs adb device/emulator
|
# needs adb device/emulator
|
||||||
./run-android-pay-smoke.sh
|
./run-android-pay-smoke.sh
|
||||||
STACK=goa ./run-android-pay-smoke.sh
|
STACK=goa ./run-android-pay-smoke.sh
|
||||||
STACK=stage ./run-android-pay-smoke.sh
|
DO_PAY=0 ./run-android-pay-smoke.sh # withdraw only
|
||||||
|
DO_WITHDRAW=0 DO_PAY=1 … # pay only (unusual)
|
||||||
```
|
```
|
||||||
|
|
||||||
APK: F-Droid **1.6.1** (`net.taler.wallet.fdroid`).
|
APK: F-Droid **1.6.1** (`net.taler.wallet.fdroid`).
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# GUI-oriented Android smoke (vanilla level): deep-link entry + UI taps.
|
# GUI-oriented Android smoke: **withdraw (Abheben)** then **pay**, each with
|
||||||
|
# deep-link entry + multi-round uiautomator taps. Not pay-only.
|
||||||
#
|
#
|
||||||
# Entry shortcut (legitimate — same as scanning a QR on the landing):
|
# 1) taler://withdraw/… + Confirm/Abheben/ToS taps
|
||||||
# adb VIEW taler://withdraw/… and taler://pay…
|
# 2) taler://pay… + Pay/Confirm taps
|
||||||
# Then drives the **graphical UI** via uiautomator dump + taps (Confirm / ToS / Pay).
|
|
||||||
#
|
|
||||||
# Systems: STACK=goa | stage | auto
|
|
||||||
# APK: published F-Droid or APK_PATH=… (from-source)
|
|
||||||
#
|
#
|
||||||
# See GUI-AUTOMATION-NOTES.md
|
# See GUI-AUTOMATION-NOTES.md
|
||||||
#
|
#
|
||||||
|
|
@ -85,20 +82,28 @@ echo "apk: $APK_PATH pkg: $PKG"
|
||||||
"${ADB[@]}" shell settings put global transition_animation_scale 0 || true
|
"${ADB[@]}" shell settings put global transition_animation_scale 0 || true
|
||||||
"${ADB[@]}" shell settings put global animator_duration_scale 0 || true
|
"${ADB[@]}" shell settings put global animator_duration_scale 0 || true
|
||||||
|
|
||||||
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 "")')
|
: "${DO_WITHDRAW:=1}"
|
||||||
[ -n "$WURI" ] || { echo "no withdraw uri" >&2; exit 4; }
|
: "${DO_PAY:=1}"
|
||||||
echo "withdraw: $WURI"
|
: "${SMOKE_STRICT:=0}"
|
||||||
echo "$WURI" >"$OUT_DIR/last-withdraw.uri"
|
|
||||||
|
WURI=""
|
||||||
|
PAY_URI=""
|
||||||
|
WITHDRAW_OK=0
|
||||||
|
PAY_OK=0
|
||||||
|
|
||||||
"${ADB[@]}" shell am force-stop "$PKG" 2>/dev/null || true
|
"${ADB[@]}" shell am force-stop "$PKG" 2>/dev/null || true
|
||||||
"${ADB[@]}" logcat -c 2>/dev/null || true
|
"${ADB[@]}" logcat -c 2>/dev/null || true
|
||||||
|
|
||||||
# --- Shortcut A: deep-link withdraw (≡ QR scan on landing) ---
|
if [ "$DO_WITHDRAW" = "1" ]; then
|
||||||
"${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$WURI" | tee "$OUT_DIR/start-withdraw.txt"
|
echo
|
||||||
sleep 5
|
echo "======== 1 WITHDRAW (Abheben) ========"
|
||||||
|
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 "")')
|
||||||
# --- Graphical: drive UI ---
|
[ -n "$WURI" ] || { echo "no withdraw uri" >&2; exit 4; }
|
||||||
python3 - "$ROOT/lib_ui.py" "$SERIAL" "$OUT_DIR" "$GUI_ROUNDS" "$GUI_SLEEP" <<'PY'
|
echo "withdraw: $WURI"
|
||||||
|
echo "$WURI" >"$OUT_DIR/last-withdraw.uri"
|
||||||
|
"${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$WURI" | tee "$OUT_DIR/start-withdraw.txt"
|
||||||
|
sleep 5
|
||||||
|
python3 - "$ROOT/lib_ui.py" "$SERIAL" "$OUT_DIR" "$GUI_ROUNDS" "$GUI_SLEEP" <<'PY'
|
||||||
import json, sys, importlib.util
|
import json, sys, importlib.util
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
lib_path, serial, out, rounds, sleep_s = (
|
lib_path, serial, out, rounds, sleep_s = (
|
||||||
|
|
@ -112,26 +117,28 @@ st = lib.gui_drive(serial, out / "gui-withdraw", rounds=rounds, sleep_s=sleep_s,
|
||||||
print("gui-withdraw taps:", st.get("taps"))
|
print("gui-withdraw taps:", st.get("taps"))
|
||||||
print("gui-withdraw anr:", st.get("anr_dismissals"))
|
print("gui-withdraw anr:", st.get("anr_dismissals"))
|
||||||
PY
|
PY
|
||||||
|
|
||||||
# Pay URI
|
|
||||||
PAY_URI=""
|
|
||||||
if [ "$STACK" = "stage" ]; then
|
|
||||||
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"";
|
|
||||||
print("taler://pay/stage.monnaie.lefrancpaysan.ch/instances/fermes-des-collines/%s/?c=%s"%(oid,tok) if oid and tok else "")')
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
PAY_URI="taler://pay-template/taler.hacktivism.ch/instances/goa-shop/paivana"
|
echo "======== 1 WITHDRAW skipped (DO_WITHDRAW=0) ========"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$PAY_URI" ]; then
|
if [ "$DO_PAY" = "1" ]; then
|
||||||
echo "pay: $PAY_URI"
|
echo
|
||||||
echo "$PAY_URI" >"$OUT_DIR/last-pay.uri"
|
echo "======== 2 PAY (Bezahlen) ========"
|
||||||
# Shortcut B: deep-link pay (≡ scan pay QR / open paywall link)
|
if [ "$STACK" = "stage" ]; then
|
||||||
"${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$PAY_URI" | tee "$OUT_DIR/start-pay.txt"
|
if RESP=$(curl -sfS -m 20 -X POST -H 'Content-Type: application/json' -d '{}' \
|
||||||
sleep 5
|
"$MERCHANT/instances/fermes-des-collines/templates/panier-legumes" 2>/dev/null); then
|
||||||
python3 - "$ROOT/lib_ui.py" "$SERIAL" "$OUT_DIR" "$GUI_ROUNDS" "$GUI_SLEEP" <<'PY'
|
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"";
|
||||||
|
print("taler://pay/stage.monnaie.lefrancpaysan.ch/instances/fermes-des-collines/%s/?c=%s"%(oid,tok) if oid and tok else "")')
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
PAY_URI="taler://pay-template/taler.hacktivism.ch/instances/goa-shop/paivana"
|
||||||
|
fi
|
||||||
|
if [ -n "$PAY_URI" ]; then
|
||||||
|
echo "pay: $PAY_URI"
|
||||||
|
echo "$PAY_URI" >"$OUT_DIR/last-pay.uri"
|
||||||
|
"${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$PAY_URI" | tee "$OUT_DIR/start-pay.txt"
|
||||||
|
sleep 5
|
||||||
|
python3 - "$ROOT/lib_ui.py" "$SERIAL" "$OUT_DIR" "$GUI_ROUNDS" "$GUI_SLEEP" <<'PY'
|
||||||
import json, sys, importlib.util
|
import json, sys, importlib.util
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
lib_path, serial, out, rounds, sleep_s = (
|
lib_path, serial, out, rounds, sleep_s = (
|
||||||
|
|
@ -145,29 +152,50 @@ st = lib.gui_drive(serial, out / "gui-pay", rounds=rounds, sleep_s=sleep_s, phas
|
||||||
print("gui-pay taps:", st.get("taps"))
|
print("gui-pay taps:", st.get("taps"))
|
||||||
print("gui-pay anr:", st.get("anr_dismissals"))
|
print("gui-pay anr:", st.get("anr_dismissals"))
|
||||||
PY
|
PY
|
||||||
|
else
|
||||||
|
echo "pay: (no URI)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "======== 2 PAY skipped (DO_PAY=0) ========"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
"${ADB[@]}" logcat -d -t 400 >"$OUT_DIR/logcat.txt" || true
|
"${ADB[@]}" logcat -d -t 500 >"$OUT_DIR/logcat.txt" || true
|
||||||
grep -iE 'taler-wallet|prepareBank|preparePay|confirm|Error|success' "$OUT_DIR/logcat.txt" \
|
grep -iE 'taler-wallet|prepareBank|acceptWithdrawal|confirmWithdrawal|preparePay|confirmPay|Error|success|withdraw|pay' \
|
||||||
| tail -100 >"$OUT_DIR/logcat-taler.txt" || true
|
"$OUT_DIR/logcat.txt" | tail -100 >"$OUT_DIR/logcat-taler.txt" || true
|
||||||
|
|
||||||
|
if [ "$DO_WITHDRAW" = "1" ] && grep -qE 'prepareBankIntegratedWithdrawal|acceptWithdrawal|confirmWithdrawal' \
|
||||||
|
"$OUT_DIR/logcat.txt" 2>/dev/null; then
|
||||||
|
WITHDRAW_OK=1
|
||||||
|
fi
|
||||||
|
if [ "$DO_PAY" = "1" ] && [ -n "$PAY_URI" ] && \
|
||||||
|
grep -qiE 'preparePay|confirmPay|preparePurchase|checkPay|pay-template|PayForTemplate' \
|
||||||
|
"$OUT_DIR/logcat.txt" 2>/dev/null; then
|
||||||
|
PAY_OK=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rc=0
|
||||||
echo
|
echo
|
||||||
echo "=== GUI smoke summary ($STACK) ==="
|
echo "=== GUI smoke summary ($STACK) — withdraw + pay ==="
|
||||||
echo "package: $PKG"
|
echo "package: $PKG DO_WITHDRAW=$DO_WITHDRAW DO_PAY=$DO_PAY STRICT=$SMOKE_STRICT"
|
||||||
echo "shortcut withdraw URI: delivered"
|
if [ "$DO_WITHDRAW" = "1" ]; then
|
||||||
echo "GUI withdraw: see $OUT_DIR/gui-withdraw-status.json + screenshots"
|
echo "withdraw URI: delivered → $OUT_DIR/gui-withdraw-status.json"
|
||||||
[ -n "$PAY_URI" ] && echo "shortcut pay URI: delivered"
|
echo "withdraw wallet-core: $([ "$WITHDRAW_OK" = 1 ] && echo YES || echo NO)"
|
||||||
[ -n "$PAY_URI" ] && echo "GUI pay: see $OUT_DIR/gui-pay-status.json + screenshots"
|
if [ "$SMOKE_STRICT" = "1" ] && [ "$WITHDRAW_OK" != "1" ]; then
|
||||||
if grep -q prepareBankIntegratedWithdrawal "$OUT_DIR/logcat.txt" 2>/dev/null; then
|
echo "FAIL: strict withdraw missing"; rc=11
|
||||||
echo "wallet-core: prepareBankIntegratedWithdrawal YES"
|
fi
|
||||||
else
|
|
||||||
echo "wallet-core: prepareBankIntegratedWithdrawal no (ANR/slow UI?)"
|
|
||||||
fi
|
fi
|
||||||
if grep -qiE 'preparePay|confirmPay|pay-template|preparePurchase' "$OUT_DIR/logcat.txt" 2>/dev/null; then
|
if [ "$DO_PAY" = "1" ]; then
|
||||||
echo "wallet-core: pay path YES"
|
echo "pay URI: ${PAY_URI:-none} → $OUT_DIR/gui-pay-status.json"
|
||||||
else
|
echo "pay wallet-core: $([ "$PAY_OK" = 1 ] && echo YES || echo NO)"
|
||||||
echo "wallet-core: pay path not confirmed in logcat"
|
if [ "$SMOKE_STRICT" = "1" ] && [ "$PAY_OK" != "1" ]; then
|
||||||
|
echo "FAIL: strict pay missing"; [ "$rc" -eq 0 ] && rc=13
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if grep -qiE "isn't responding|not responding" "$OUT_DIR/logcat.txt" 2>/dev/null \
|
||||||
|
|| grep -rqiE "isn't responding" "$OUT_DIR/gui-withdraw" "$OUT_DIR/gui-pay" 2>/dev/null; then
|
||||||
|
echo "FAIL: ANR"; rc=10
|
||||||
fi
|
fi
|
||||||
echo "artifacts: $OUT_DIR/"
|
echo "artifacts: $OUT_DIR/"
|
||||||
ls -la "$OUT_DIR" | sed 's/^/ /'
|
ls -la "$OUT_DIR" | sed 's/^/ /'
|
||||||
echo "Documented shortcuts → GUI-AUTOMATION-NOTES.md"
|
echo "Documented shortcuts → GUI-AUTOMATION-NOTES.md"
|
||||||
|
exit "$rc"
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,20 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Android wallet smoke: install APK (published F-Droid **or** from-source), open
|
# Android wallet smoke: install APK, then **withdraw (Abheben)** and **pay** via
|
||||||
# withdraw/pay URIs via adb.
|
# deep-link + best-effort UI taps. Both legs are first-class (not pay-only).
|
||||||
#
|
#
|
||||||
# No root required if:
|
# Flow (default both on):
|
||||||
# - adb is available (package android-tools-adb / platform-tools)
|
# 1) WITHDRAW taler://withdraw/… from bank demo-withdraw.json + confirm taps
|
||||||
# - a device or emulator is connected (`adb devices` shows "device")
|
# 2) PAY taler://pay… / pay-template + optional taps
|
||||||
# - optional user-local SDK under $HOME/Android/Sdk (emulator)
|
#
|
||||||
|
# Env:
|
||||||
|
# DO_WITHDRAW=1 (default) DO_PAY=1 (default)
|
||||||
|
# SMOKE_STRICT=1 → require wallet-core withdraw (+ pay if DO_PAY) + no ANR
|
||||||
|
# WITHDRAW_GUI_ROUNDS multi-round Abheben taps (default 6)
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# ./android-test/run-android-pay-smoke.sh # published F-Droid APK
|
# ./android-test/run-android-pay-smoke.sh
|
||||||
# STACK=goa ./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
|
# DO_PAY=0 ./android-test/run-android-pay-smoke.sh # withdraw-only
|
||||||
# # from-source (built first):
|
|
||||||
# ./android-test/run-android-build-and-smoke.sh
|
|
||||||
# APK_PATH=/path/to.apk PKG=net.taler.wallet.fdroid.debug ./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
|
set -euo pipefail
|
||||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
|
@ -98,32 +96,63 @@ fi
|
||||||
echo "apk: $APK_PATH ($(wc -c <"$APK_PATH") bytes)"
|
echo "apk: $APK_PATH ($(wc -c <"$APK_PATH") bytes)"
|
||||||
echo "pkg: $PKG"
|
echo "pkg: $PKG"
|
||||||
|
|
||||||
|
: "${DO_WITHDRAW:=1}"
|
||||||
|
: "${DO_PAY:=1}"
|
||||||
|
: "${WITHDRAW_GUI_ROUNDS:=6}"
|
||||||
|
: "${PAY_GUI_ROUNDS:=4}"
|
||||||
|
: "${SMOKE_STRICT:=0}"
|
||||||
|
|
||||||
"${ADB[@]}" wait-for-device
|
"${ADB[@]}" wait-for-device
|
||||||
"${ADB[@]}" install -r "$APK_PATH"
|
"${ADB[@]}" install -r "$APK_PATH"
|
||||||
"${ADB[@]}" shell settings put global window_animation_scale 0 || true
|
"${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 transition_animation_scale 0 || true
|
||||||
"${ADB[@]}" shell settings put global animator_duration_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[@]}" shell am force-stop "$PKG" 2>/dev/null || true
|
||||||
"${ADB[@]}" logcat -c 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
|
WURI=""
|
||||||
"${ADB[@]}" shell uiautomator dump /sdcard/ui.xml 2>/dev/null || true
|
PAY_URI=""
|
||||||
"${ADB[@]}" pull /sdcard/ui.xml "$OUT_DIR/01-ui.xml" 2>/dev/null || true
|
WITHDRAW_OK=0
|
||||||
|
PAY_OK=0
|
||||||
|
|
||||||
# Best-effort: tap common confirm labels
|
# ═══════════════════════════════════════════════════════════════
|
||||||
python3 - "$SERIAL" "$OUT_DIR/01-ui.xml" <<'PY' || true
|
# 1) WITHDRAW / Abheben (required by default — not pay-only)
|
||||||
|
# ═══════════════════════════════════════════════════════════════
|
||||||
|
if [ "$DO_WITHDRAW" = "1" ]; then
|
||||||
|
echo
|
||||||
|
echo "======== 1 WITHDRAW (Abheben) ========"
|
||||||
|
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 URI: $WURI"
|
||||||
|
echo "$WURI" >"$OUT_DIR/last-withdraw.uri"
|
||||||
|
|
||||||
|
"${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$WURI" 2>&1 | tee "$OUT_DIR/start-withdraw.txt"
|
||||||
|
sleep 6
|
||||||
|
"${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
|
||||||
|
|
||||||
|
# Multi-round confirm / Abheben / ToS (same idea as GUI smoke)
|
||||||
|
if [ -f "$ROOT/lib_ui.py" ]; then
|
||||||
|
python3 - "$ROOT/lib_ui.py" "$SERIAL" "$OUT_DIR" "$WITHDRAW_GUI_ROUNDS" 2 <<'PY' || true
|
||||||
|
import json, sys, importlib.util
|
||||||
|
from pathlib import Path
|
||||||
|
lib_path, serial, out, rounds, sleep_s = (
|
||||||
|
Path(sys.argv[1]), sys.argv[2], Path(sys.argv[3]), int(sys.argv[4]), float(sys.argv[5])
|
||||||
|
)
|
||||||
|
spec = importlib.util.spec_from_file_location("lib_ui", lib_path)
|
||||||
|
lib = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(lib)
|
||||||
|
st = lib.gui_drive(serial, out / "gui-withdraw", rounds=rounds, sleep_s=sleep_s, phase="wd")
|
||||||
|
(out / "gui-withdraw-status.json").write_text(json.dumps(st, indent=2))
|
||||||
|
print("withdraw GUI taps:", st.get("taps"), "anr:", st.get("anr_dismissals"))
|
||||||
|
PY
|
||||||
|
else
|
||||||
|
python3 - "$SERIAL" "$OUT_DIR/01-ui.xml" <<'PY' || true
|
||||||
import re, subprocess, sys
|
import re, subprocess, sys
|
||||||
serial, path = sys.argv[1], sys.argv[2]
|
serial, path = sys.argv[1], sys.argv[2]
|
||||||
try:
|
try:
|
||||||
|
|
@ -131,31 +160,46 @@ try:
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
raise SystemExit(0)
|
raise SystemExit(0)
|
||||||
labels = [
|
labels = [
|
||||||
"Confirm", "Withdraw", "Accept", "Continue", "OK",
|
"Confirm", "Confirm withdrawal", "Withdraw", "Accept", "Continue", "OK",
|
||||||
"I accept", "Agree", "Bestätigen", "Abheben", "Akzeptieren",
|
"I accept", "Agree", "Bestätigen", "Abheben", "Akzeptieren", "Retirer",
|
||||||
]
|
]
|
||||||
for label in labels:
|
for label in labels:
|
||||||
for pat in (
|
for pat in (
|
||||||
r'text="%s"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"' % re.escape(label),
|
r'text="%s"[^>]*bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"' % re.escape(label),
|
||||||
r'bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*text="%s"' % re.escape(label),
|
r'bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*text="%s"' % re.escape(label),
|
||||||
):
|
):
|
||||||
for m in re.finditer(pat, xml):
|
for m in re.finditer(pat, xml, flags=re.I):
|
||||||
x1, y1, x2, y2 = map(int, m.groups())
|
x1, y1, x2, y2 = map(int, m.groups())
|
||||||
x, y = (x1 + x2) // 2, (y1 + y2) // 2
|
x, y = (x1 + x2) // 2, (y1 + y2) // 2
|
||||||
print(f"tap {label} @ {x},{y}")
|
print(f"tap {label} @ {x},{y}")
|
||||||
subprocess.run(["adb", "-s", serial, "shell", "input", "tap", str(x), str(y)], check=False)
|
subprocess.run(["adb", "-s", serial, "shell", "input", "tap", str(x), str(y)], check=False)
|
||||||
PY
|
PY
|
||||||
sleep 8
|
sleep 8
|
||||||
"${ADB[@]}" exec-out screencap -p >"$OUT_DIR/02-after-confirm-tap.png" || true
|
fi
|
||||||
|
"${ADB[@]}" exec-out screencap -p >"$OUT_DIR/02-after-withdraw-taps.png" || true
|
||||||
|
# Mid-flow logcat: withdraw must register before pay
|
||||||
|
"${ADB[@]}" logcat -d -t 400 >"$OUT_DIR/logcat-after-withdraw.txt" || true
|
||||||
|
if grep -qE 'prepareBankIntegratedWithdrawal|acceptWithdrawal|confirmWithdrawal' \
|
||||||
|
"$OUT_DIR/logcat-after-withdraw.txt" 2>/dev/null; then
|
||||||
|
WITHDRAW_OK=1
|
||||||
|
echo "withdraw: wallet-core activity YES"
|
||||||
|
else
|
||||||
|
echo "withdraw: wallet-core activity NOT seen yet (onboarding/ANR/slow?)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "======== 1 WITHDRAW skipped (DO_WITHDRAW=0) ========"
|
||||||
|
fi
|
||||||
|
|
||||||
# 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.
|
# 2) PAY (after withdraw; still first-class, but second leg)
|
||||||
PAY_URI=""
|
# ═══════════════════════════════════════════════════════════════
|
||||||
if [ "$STACK" = "stage" ]; then
|
if [ "$DO_PAY" = "1" ]; then
|
||||||
# fixed template panier-legumes → taler://pay/…
|
echo
|
||||||
if RESP=$(curl -sfS -m 20 -X POST -H 'Content-Type: application/json' -d '{}' \
|
echo "======== 2 PAY (Bezahlen) ========"
|
||||||
"$MERCHANT/instances/fermes-des-collines/templates/panier-legumes" 2>/dev/null); then
|
if [ "$STACK" = "stage" ]; then
|
||||||
PAY_URI=$(printf '%s' "$RESP" | python3 -c '
|
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
|
import json,sys
|
||||||
d=json.load(sys.stdin)
|
d=json.load(sys.stdin)
|
||||||
oid=d.get("order_id") or ""
|
oid=d.get("order_id") or ""
|
||||||
|
|
@ -163,58 +207,102 @@ tok=d.get("token") or ""
|
||||||
if oid and tok:
|
if oid and tok:
|
||||||
print("taler://pay/stage.monnaie.lefrancpaysan.ch/instances/fermes-des-collines/%s/?c=%s"%(oid,tok))
|
print("taler://pay/stage.monnaie.lefrancpaysan.ch/instances/fermes-des-collines/%s/?c=%s"%(oid,tok))
|
||||||
' 2>/dev/null || true)
|
' 2>/dev/null || true)
|
||||||
|
fi
|
||||||
|
elif [ "$STACK" = "goa" ]; then
|
||||||
|
PAY_URI="taler://pay-template/taler.hacktivism.ch/instances/goa-shop/paivana"
|
||||||
fi
|
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
|
if [ -n "$PAY_URI" ]; then
|
||||||
echo "pay: $PAY_URI ($PAY_HINT)"
|
echo "pay URI: $PAY_URI ($PAY_HINT)"
|
||||||
echo "$PAY_URI" >"$OUT_DIR/last-pay.uri"
|
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"
|
"${ADB[@]}" shell am start -a android.intent.action.VIEW -d "$PAY_URI" 2>&1 | tee "$OUT_DIR/start-pay.txt"
|
||||||
sleep 12
|
sleep 6
|
||||||
"${ADB[@]}" exec-out screencap -p >"$OUT_DIR/03-after-pay-uri.png" || true
|
if [ -f "$ROOT/lib_ui.py" ]; then
|
||||||
|
python3 - "$ROOT/lib_ui.py" "$SERIAL" "$OUT_DIR" "$PAY_GUI_ROUNDS" 2 <<'PY' || true
|
||||||
|
import json, sys, importlib.util
|
||||||
|
from pathlib import Path
|
||||||
|
lib_path, serial, out, rounds, sleep_s = (
|
||||||
|
Path(sys.argv[1]), sys.argv[2], Path(sys.argv[3]), int(sys.argv[4]), float(sys.argv[5])
|
||||||
|
)
|
||||||
|
spec = importlib.util.spec_from_file_location("lib_ui", lib_path)
|
||||||
|
lib = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(lib)
|
||||||
|
st = lib.gui_drive(serial, out / "gui-pay", rounds=rounds, sleep_s=sleep_s, phase="pay")
|
||||||
|
(out / "gui-pay-status.json").write_text(json.dumps(st, indent=2))
|
||||||
|
print("pay GUI taps:", st.get("taps"), "anr:", st.get("anr_dismissals"))
|
||||||
|
PY
|
||||||
|
fi
|
||||||
|
"${ADB[@]}" exec-out screencap -p >"$OUT_DIR/03-after-pay-uri.png" || true
|
||||||
|
else
|
||||||
|
echo "pay: (no public template URI for stack=$STACK)"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "pay: (skipped — no public template order)"
|
echo "======== 2 PAY skipped (DO_PAY=0) ========"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Evidence from logcat
|
# Final evidence
|
||||||
"${ADB[@]}" logcat -d -t 300 >"$OUT_DIR/logcat.txt" || true
|
"${ADB[@]}" logcat -d -t 500 >"$OUT_DIR/logcat.txt" || true
|
||||||
grep -iE 'taler-wallet|prepareBank|preparePay|confirm|error|Error|success' "$OUT_DIR/logcat.txt" \
|
grep -iE 'taler-wallet|prepareBank|acceptWithdrawal|confirmWithdrawal|preparePay|confirmPay|error|Error|success|withdraw|pay' \
|
||||||
| tail -80 >"$OUT_DIR/logcat-taler.txt" || true
|
"$OUT_DIR/logcat.txt" | tail -100 >"$OUT_DIR/logcat-taler.txt" || true
|
||||||
|
|
||||||
|
# Re-evaluate withdraw/pay from full logcat
|
||||||
|
if [ "$DO_WITHDRAW" = "1" ]; then
|
||||||
|
if grep -qE 'prepareBankIntegratedWithdrawal|acceptWithdrawal|confirmWithdrawal' \
|
||||||
|
"$OUT_DIR/logcat.txt" 2>/dev/null; then
|
||||||
|
WITHDRAW_OK=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ "$DO_PAY" = "1" ] && [ -n "$PAY_URI" ]; then
|
||||||
|
if grep -qiE 'preparePay|confirmPay|preparePurchase|checkPay|pay-template|PayForTemplate' \
|
||||||
|
"$OUT_DIR/logcat.txt" 2>/dev/null; then
|
||||||
|
PAY_OK=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# SMOKE_STRICT=1 (matrix gate default): ANR or missing wallet-core withdraw = hard fail
|
|
||||||
: "${SMOKE_STRICT:=0}"
|
|
||||||
rc=0
|
rc=0
|
||||||
echo
|
echo
|
||||||
echo "=== summary ==="
|
echo "=== summary (withdraw + pay) ==="
|
||||||
echo "package installed: $PKG"
|
echo "package: $PKG stack: $STACK"
|
||||||
echo "withdraw intent delivered: $WURI"
|
echo "DO_WITHDRAW=$DO_WITHDRAW DO_PAY=$DO_PAY SMOKE_STRICT=$SMOKE_STRICT"
|
||||||
if grep -qiE "isn't responding|isn.t responding|System UI isn" "$OUT_DIR/01-ui.xml" 2>/dev/null \
|
if [ "$DO_WITHDRAW" = "1" ]; then
|
||||||
|| grep -qiE "isn't responding|not responding" "$OUT_DIR/logcat.txt" 2>/dev/null; then
|
echo "withdraw URI: ${WURI:-(none)}"
|
||||||
echo "FAIL: System UI / app ANR (host too small or emulator hung)"
|
if [ "$WITHDRAW_OK" = "1" ]; then
|
||||||
rc=10
|
echo "withdraw wallet-core: YES"
|
||||||
fi
|
|
||||||
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)"
|
|
||||||
if [ "$SMOKE_STRICT" = "1" ]; then
|
|
||||||
echo "FAIL: SMOKE_STRICT=1 requires prepareBankIntegratedWithdrawal in logcat"
|
|
||||||
rc=11
|
|
||||||
fi
|
|
||||||
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
|
else
|
||||||
echo "wallet-core: pay path not confirmed in logcat (check $OUT_DIR/03-after-pay-uri.png)"
|
echo "withdraw wallet-core: NO"
|
||||||
|
if [ "$SMOKE_STRICT" = "1" ]; then
|
||||||
|
echo "FAIL: SMOKE_STRICT requires withdraw (prepareBank/accept/confirm) in logcat"
|
||||||
|
rc=11
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
if [ "$DO_PAY" = "1" ]; then
|
||||||
|
echo "pay URI: ${PAY_URI:-(none)}"
|
||||||
|
if [ -z "$PAY_URI" ]; then
|
||||||
|
echo "pay: no URI (template/API)"
|
||||||
|
if [ "$SMOKE_STRICT" = "1" ]; then
|
||||||
|
echo "FAIL: SMOKE_STRICT requires a pay URI when DO_PAY=1"
|
||||||
|
rc=12
|
||||||
|
fi
|
||||||
|
elif [ "$PAY_OK" = "1" ]; then
|
||||||
|
echo "pay wallet-core: YES"
|
||||||
|
else
|
||||||
|
echo "pay wallet-core: NO (intent may still have been delivered)"
|
||||||
|
if [ "$SMOKE_STRICT" = "1" ]; then
|
||||||
|
echo "FAIL: SMOKE_STRICT requires pay path activity in logcat"
|
||||||
|
[ "$rc" -eq 0 ] && rc=13
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if grep -qiE "isn't responding|isn.t responding|System UI isn" "$OUT_DIR/01-ui.xml" 2>/dev/null \
|
||||||
|
|| grep -qiE "isn't responding|not responding" "$OUT_DIR/logcat.txt" 2>/dev/null \
|
||||||
|
|| grep -rqiE "isn't responding" "$OUT_DIR/gui-withdraw" 2>/dev/null; then
|
||||||
|
echo "FAIL: System UI / app ANR"
|
||||||
|
rc=10
|
||||||
|
fi
|
||||||
echo "artifacts: $OUT_DIR/"
|
echo "artifacts: $OUT_DIR/"
|
||||||
ls -la "$OUT_DIR" | sed 's/^/ /'
|
ls -la "$OUT_DIR" | sed 's/^/ /'
|
||||||
echo
|
echo
|
||||||
echo "NOTE: Full unattended UI payment needs a responsive device/emulator (≥6–8 GiB host RAM recommended)."
|
echo "NOTE: Full unattended Abheben+Bezahlen needs responsive device (≥6–8 GiB host RAM)."
|
||||||
echo "This smoke proves: APK install + deep-link delivery on stack=$STACK (strict=$SMOKE_STRICT rc=$rc)."
|
echo "Smoke legs: withdraw=$( [ "$DO_WITHDRAW" = 1 ] && echo on || echo off) pay=$( [ "$DO_PAY" = 1 ] && echo on || echo off) rc=$rc"
|
||||||
exit "$rc"
|
exit "$rc"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue