release 1.26.0: --wallet-db harness flag, TESTPAYSAN quadlet, token-pay
This commit is contained in:
parent
f2ee435e6b
commit
39e5eccc25
13 changed files with 235 additions and 39 deletions
160
check_e2e.sh
160
check_e2e.sh
|
|
@ -8,8 +8,8 @@ source "$ROOT/lib.sh"
|
|||
# shellcheck source=metrics.sh
|
||||
source "$ROOT/metrics.sh"
|
||||
|
||||
: "${E2E_TIMEOUT:=180}" # Bank withdraw ladder + wirewatch lag needs room (was 55 — too tight)
|
||||
: "${E2E_PAY_SECS:=22}" # hard reserve for handle-uri + settle (do not starve pay)
|
||||
: "${E2E_TIMEOUT:=360}" # Bank withdraw + refresh/pay + shop sample + token-pay
|
||||
: "${E2E_PAY_SECS:=60}" # handle-uri + coin refresh; macOS perl SIGALRM kills at this cap
|
||||
: "${E2E_SETTLE_ROUNDS:=18}"
|
||||
: "${E2E_SETTLE_SLEEP:=3}"
|
||||
E2E_START=$(date +%s)
|
||||
|
|
@ -307,7 +307,7 @@ PAY_AMT=$(printf '%s' "$PAY_LIST" | awk '{print $1}')
|
|||
if [ "$E2E_VARIABLE" = "1" ]; then
|
||||
n_w=$(printf '%s' "$WITHDRAW_LIST" | wc -w | tr -d ' ')
|
||||
n_p=$(printf '%s' "$PAY_LIST" | wc -w | tr -d ' ')
|
||||
need=$(( 50 + n_w * 40 + n_p * 20 + 60 )) # + room for paivana pay
|
||||
need=$(( 80 + n_w * 50 + n_p * 50 + 180 )) # shop sample + token-pay + refresh room
|
||||
if [ "${E2E_TIMEOUT}" -lt "$need" ]; then
|
||||
E2E_TIMEOUT=$need
|
||||
fi
|
||||
|
|
@ -330,8 +330,9 @@ fi
|
|||
BANK_HOST=$(python3 -c 'from urllib.parse import urlparse; print(urlparse("'"$BANK_PUBLIC"'").hostname or "bank")' 2>/dev/null || echo bank)
|
||||
|
||||
SCRATCH=$(mktemp -d)
|
||||
WDB="$SCRATCH/wallet.sqlite3"
|
||||
WSOCK="$SCRATCH/wallet.sock"
|
||||
WDB=$(taler_mon_resolve_wallet_db "$SCRATCH/wallet.sqlite3") || exit 2
|
||||
# macOS AF_UNIX path cap ~104 bytes. Do not use $TMPDIR (/var/folders/...).
|
||||
WSOCK="/tmp/e2e-wcli-$$.sock"
|
||||
WSERVE_PID=""
|
||||
# Client/server wallet (advanced serve): long-lived shepherd without run-until-done.
|
||||
# Default on — wallet-cli only completes withdraw/pay while a serve process is up.
|
||||
|
|
@ -598,20 +599,26 @@ start_wallet_serve() {
|
|||
[ -n "${WALLET_CLI:-}" ] && [ -f "${WALLET_CLI}" ] || return 1
|
||||
stop_wallet_serve
|
||||
rm -f "$WSOCK"
|
||||
# helper shebang is /usr/bin/env python3 — macOS /usr/bin/python3 is 3.9 (FATAL).
|
||||
export PATH="/opt/homebrew/bin:/usr/local/bin:${HOME}/.local/bin:${PATH}"
|
||||
export PYTHON="${PYTHON:-$(command -v python3)}"
|
||||
# serve holds the DB open; clients use --wallet-connection only
|
||||
"$NODE_BIN" "$WALLET_CLI" --wallet-db="$WDB" --no-throttle --skip-defaults \
|
||||
advanced serve --unix-path "$WSOCK" \
|
||||
>"$SCRATCH/wallet-serve.log" 2>&1 &
|
||||
WSERVE_PID=$!
|
||||
local i
|
||||
for i in $(seq 1 40); do
|
||||
if [ -S "$WSOCK" ] && kill -0 "$WSERVE_PID" 2>/dev/null; then
|
||||
for i in $(seq 1 80); do
|
||||
if kill -0 "$WSERVE_PID" 2>/dev/null && { [ -S "$WSOCK" ] || grep -q "serving at" "$SCRATCH/wallet-serve.log" 2>/dev/null; }; then
|
||||
ok "wallet serve" "pid=$WSERVE_PID sock=$WSOCK (no run-until-done)"
|
||||
return 0
|
||||
fi
|
||||
if ! kill -0 "$WSERVE_PID" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 0.15
|
||||
done
|
||||
warn "wallet serve" "socket not ready — falling back to one-shot CLI (coins may stay pending)"
|
||||
warn "wallet serve" "socket not ready — $(head -c 180 "$SCRATCH/wallet-serve.log" 2>/dev/null | tr '\n' ' ')"
|
||||
stop_wallet_serve
|
||||
return 1
|
||||
}
|
||||
|
|
@ -658,20 +665,10 @@ wcli() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Pay must not be starved: use reserved seconds even if global budget is tight
|
||||
# Pay must not be starved: always keep the reserved handle-uri cap
|
||||
# (leftover e2e budget used to shrink this to 12–14s → SIGALRM mid-pay).
|
||||
wcli_pay() {
|
||||
local cap=$E2E_PAY_SECS
|
||||
local left
|
||||
left=$(e2e_left)
|
||||
left=$(printf '%s' "$left" | awk '/^[0-9]+$/{print; exit} {for(i=1;i<=NF;i++) if($i+0==$i){print $i; exit}}')
|
||||
if [ -n "$left" ] && [ "$left" -gt "$cap" ] 2>/dev/null; then
|
||||
cap=$E2E_PAY_SECS
|
||||
elif [ -n "$left" ] && [ "$left" -ge 8 ] 2>/dev/null; then
|
||||
cap=$left
|
||||
else
|
||||
# still try once with floor 12s so Alarm clock is not the blocker
|
||||
cap=12
|
||||
fi
|
||||
info "pay wallet cap" "${cap}s"
|
||||
if [ -n "${WSERVE_PID:-}" ] && [ -S "${WSOCK:-}" ]; then
|
||||
_wcli_exec "$cap" --wallet-connection="$WSOCK" --no-throttle "$@"
|
||||
|
|
@ -1717,12 +1714,135 @@ else
|
|||
info "paivana summary" "${PAIVANA_REPORT:-?} · instance ${E2E_PAIVANA_INSTANCE}"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Loyalty-token pays (generic). TESTPAYSAN default = stage token-order API.
|
||||
# Override: E2E_TOKEN_ORDER_URL E2E_TOKEN_PRODUCT E2E_TOKEN_PAID_N E2E_TOKEN_FREE_N
|
||||
# ---------------------------------------------------------------------------
|
||||
if [ "${CUR:-}" = "TESTPAYSAN" ] && [ -z "${E2E_TOKEN_ENABLE:-}" ]; then
|
||||
E2E_TOKEN_ENABLE=1
|
||||
fi
|
||||
: "${E2E_TOKEN_ORDER_URL:=https://stage.monnaie.lefrancpaysan.ch/shops/api/kiosque-order}"
|
||||
: "${E2E_TOKEN_PRODUCT:=prod_banana}"
|
||||
: "${E2E_TOKEN_PAID_N:=2}"
|
||||
: "${E2E_TOKEN_FREE_N:=1}"
|
||||
TOKEN_OK=0
|
||||
TOKEN_OK_N=0
|
||||
TOKEN_FAIL_N=0
|
||||
TOKEN_REPORT=""
|
||||
|
||||
e2e_one_token_order() {
|
||||
local product="$1" choice="$2" tag="$3"
|
||||
local body create_f payuri oid otok inst
|
||||
body=$(python3 -c 'import json,sys; print(json.dumps({"product_id":sys.argv[1]}))' "$product")
|
||||
create_f="$SCRATCH/token-$tag.json"
|
||||
curl -skS -m 20 -o "$create_f" -X POST \
|
||||
-H 'Content-Type: application/json' -d "$body" \
|
||||
"$E2E_TOKEN_ORDER_URL" 2>"$SCRATCH/token-$tag.err" || true
|
||||
oid=$(python3 -c 'import json,sys
|
||||
try:
|
||||
d=json.load(open(sys.argv[1])); print(d.get("order_id") or "")
|
||||
except Exception: print("")' "$create_f" 2>/dev/null || true)
|
||||
otok=$(python3 -c 'import json,sys
|
||||
try:
|
||||
d=json.load(open(sys.argv[1])); print(d.get("token") or "")
|
||||
except Exception: print("")' "$create_f" 2>/dev/null || true)
|
||||
payuri=$(python3 -c 'import json,sys
|
||||
try:
|
||||
d=json.load(open(sys.argv[1])); print((d.get("taler_pay_uri") or "").replace(":443",""))
|
||||
except Exception: print("")' "$create_f" 2>/dev/null || true)
|
||||
if [ -z "$oid" ] || [ -z "$payuri" ]; then
|
||||
warn "token-pay $tag" "order POST failed — $(head -c 120 "$create_f" 2>/dev/null | tr '\n' ' ')"
|
||||
return 1
|
||||
fi
|
||||
info "token-pay $tag" "order $oid choice=$choice product=$product"
|
||||
if ! wcli_pay handle-uri --yes --non-interactive --choice-index="$choice" "$payuri" \
|
||||
>"$SCRATCH/token-pay-$tag.out" 2>&1; then
|
||||
warn "token-pay $tag" "handle-uri failed — $(tail -c 140 "$SCRATCH/token-pay-$tag.out" | tr '\n' ' ')"
|
||||
return 1
|
||||
fi
|
||||
# wallet-cli can print Payment expired/failed and still exit 0
|
||||
if grep -qiE 'Payment expired|Payment failed|Payment aborted|insufficient balance' \
|
||||
"$SCRATCH/token-pay-$tag.out" 2>/dev/null; then
|
||||
warn "token-pay $tag" "handle-uri not paid — $(tail -c 140 "$SCRATCH/token-pay-$tag.out" | tr '\n' ' ')"
|
||||
return 1
|
||||
fi
|
||||
inst="${E2E_TOKEN_INSTANCE:-kiosque-banane}"
|
||||
local r
|
||||
for r in 1 2 3 4 5 6 8 10 12 15 18 20; do
|
||||
if [ -n "$otok" ]; then
|
||||
curl -skS -m 8 -o "$SCRATCH/token-st-$tag.json" \
|
||||
"${MERCHANT_PUBLIC}/instances/${inst}/orders/$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=""))' "$oid")?token=$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=""))' "$otok")" \
|
||||
2>/dev/null || true
|
||||
if python3 -c 'import json,sys
|
||||
try:
|
||||
d=json.load(open(sys.argv[1]))
|
||||
st=str(d.get("order_status") or d.get("status") or "").lower()
|
||||
if d.get("paid") is True or st=="paid":
|
||||
raise SystemExit(0)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except SystemExit:
|
||||
raise
|
||||
except Exception:
|
||||
pass
|
||||
raise SystemExit(1)
|
||||
' "$SCRATCH/token-st-$tag.json" 2>/dev/null \
|
||||
|| grep -qE '"paid"[[:space:]]*:[[:space:]]*true|"order_status"[[:space:]]*:[[:space:]]*"paid"' \
|
||||
"$SCRATCH/token-st-$tag.json" 2>/dev/null; then
|
||||
ok "token-pay $tag" "paid choice=$choice oid=$oid"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
warn "token-pay $tag" "not settled for order $oid — $(head -c 80 "$SCRATCH/token-st-$tag.json" 2>/dev/null | tr '\n' ' ')"
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ "${E2E_TOKEN_ENABLE}" = "1" ]; then
|
||||
set_group token
|
||||
section "e2e · token pays (public order API)"
|
||||
info "token-pay" "POST $E2E_TOKEN_ORDER_URL product=$E2E_TOKEN_PRODUCT paid_n=$E2E_TOKEN_PAID_N free_n=$E2E_TOKEN_FREE_N"
|
||||
_ti=1
|
||||
while [ "$_ti" -le "$E2E_TOKEN_PAID_N" ]; do
|
||||
if e2e_one_token_order "$E2E_TOKEN_PRODUCT" 0 "paid${_ti}"; then
|
||||
TOKEN_OK_N=$((TOKEN_OK_N + 1))
|
||||
TOKEN_REPORT="${TOKEN_REPORT:+$TOKEN_REPORT }paid${_ti}=OK"
|
||||
else
|
||||
TOKEN_FAIL_N=$((TOKEN_FAIL_N + 1))
|
||||
TOKEN_REPORT="${TOKEN_REPORT:+$TOKEN_REPORT }paid${_ti}=FAIL"
|
||||
fi
|
||||
_ti=$((_ti + 1))
|
||||
done
|
||||
_ti=1
|
||||
while [ "$_ti" -le "$E2E_TOKEN_FREE_N" ]; do
|
||||
if e2e_one_token_order "$E2E_TOKEN_PRODUCT" 1 "free${_ti}"; then
|
||||
TOKEN_OK_N=$((TOKEN_OK_N + 1))
|
||||
TOKEN_REPORT="${TOKEN_REPORT:+$TOKEN_REPORT }free${_ti}=OK"
|
||||
else
|
||||
TOKEN_FAIL_N=$((TOKEN_FAIL_N + 1))
|
||||
TOKEN_REPORT="${TOKEN_REPORT:+$TOKEN_REPORT }free${_ti}=FAIL"
|
||||
fi
|
||||
_ti=$((_ti + 1))
|
||||
done
|
||||
unset _ti
|
||||
if [ "$TOKEN_FAIL_N" = "0" ] && [ "$TOKEN_OK_N" -gt 0 ]; then
|
||||
TOKEN_OK=1
|
||||
PAY_OK=1
|
||||
PAY_OK_N=$((PAY_OK_N + TOKEN_OK_N))
|
||||
ok "token-pay summary" "$TOKEN_REPORT"
|
||||
else
|
||||
warn "token-pay summary" "$TOKEN_REPORT"
|
||||
fi
|
||||
fi
|
||||
|
||||
set_group report
|
||||
section "e2e · report"
|
||||
info "user" "$USER"
|
||||
info "Bank withdraws" "$WITHDRAW_REPORT"
|
||||
info "payments" "$PAY_REPORT"
|
||||
info "shop" "${SHOP_REPORT:-(n/a)}"
|
||||
info "token-pay" "${TOKEN_REPORT:-(n/a)}"
|
||||
info "paivana" "${PAIVANA_REPORT:-(n/a)}"
|
||||
info "final balance" "$(fmt_bal "$SCRATCH/bal-live.out" 2>/dev/null || echo "(n/a)")"
|
||||
info "scratch" "$SCRATCH"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue