taler-monitoring: e2e public template pays by product name
This commit is contained in:
parent
4dae7c082f
commit
250d4ad75b
1 changed files with 201 additions and 15 deletions
|
|
@ -775,26 +775,35 @@ else:
|
|||
return 1
|
||||
}
|
||||
|
||||
# One variable payment amount
|
||||
# One payment: e2e_one_pay AMOUNT [SUMMARY] [TAG]
|
||||
# SUMMARY defaults to "monitoring pay $AMOUNT"; TAG defaults from amount.
|
||||
e2e_one_pay() {
|
||||
PAY_AMT="$1"
|
||||
local tag
|
||||
local PAY_SUM="${2:-monitoring pay ${PAY_AMT}}"
|
||||
local tag="${3:-}"
|
||||
if [ -z "$tag" ]; then
|
||||
tag=$(printf '%s' "$PAY_AMT" | tr '.:' '__')
|
||||
section "e2e · pay $PAY_AMT"
|
||||
e2e_over && { warn "pay" "budget exhausted — skip $PAY_AMT"; return 1; }
|
||||
fi
|
||||
# shell-safe tag for files
|
||||
tag=$(printf '%s' "$tag" | tr -c 'A-Za-z0-9._-' '_')
|
||||
section "e2e · pay $PAY_AMT · $PAY_SUM"
|
||||
e2e_over && { warn "pay" "budget exhausted — skip $PAY_AMT ($PAY_SUM)"; return 1; }
|
||||
if [ -z "${MPW:-}" ]; then
|
||||
warn "pay $PAY_AMT" "no merchant token"
|
||||
return 1
|
||||
fi
|
||||
AUTH="Authorization: Bearer secret-token:${MPW}"
|
||||
# JSON-escape summary for curl -d
|
||||
local SUM_JSON
|
||||
SUM_JSON=$(python3 -c 'import json,sys; print(json.dumps(sys.argv[1]))' "$PAY_SUM" 2>/dev/null || printf '"%s"' "$PAY_SUM")
|
||||
curl -skS -m 15 -o "$SCRATCH/ord-$tag.json" -X POST \
|
||||
-H "$AUTH" -H 'Content-Type: application/json' \
|
||||
-d "{\"order\":{\"summary\":\"monitoring pay ${PAY_AMT}\",\"amount\":\"${PAY_AMT}\",\"fulfillment_message\":\"ok\"},\"create_token\":true}" \
|
||||
-d "{\"order\":{\"summary\":${SUM_JSON},\"amount\":\"${PAY_AMT}\",\"fulfillment_message\":\"ok\"},\"create_token\":true}" \
|
||||
"${MERCHANT_PUBLIC}/instances/${INST}/private/orders" 2>"$SCRATCH/ord-$tag.err" || true
|
||||
if ! grep -q order_id "$SCRATCH/ord-$tag.json" 2>/dev/null; then
|
||||
if [ "$E2E_REMOTE" != "1" ] && koopa_ssh_ok; then
|
||||
koopa_ssh_run 20 \
|
||||
"curl -skS -m 12 -X POST -H 'Authorization: Bearer secret-token:${MPW}' -H 'Content-Type: application/json' -d '{\"order\":{\"summary\":\"monitoring pay\",\"amount\":\"${PAY_AMT}\",\"fulfillment_message\":\"ok\"},\"create_token\":true}' 'https://127.0.0.1:9010/instances/${INST}/private/orders'" \
|
||||
"curl -skS -m 12 -X POST -H 'Authorization: Bearer secret-token:${MPW}' -H 'Content-Type: application/json' -d '{\"order\":{\"summary\":${SUM_JSON},\"amount\":\"${PAY_AMT}\",\"fulfillment_message\":\"ok\"},\"create_token\":true}' 'https://127.0.0.1:9010/instances/${INST}/private/orders'" \
|
||||
>"$SCRATCH/ord-$tag.json" 2>"$SCRATCH/ord-$tag.err" || true
|
||||
fi
|
||||
fi
|
||||
|
|
@ -810,12 +819,12 @@ except Exception:
|
|||
' "$SCRATCH/ord-$tag.json" 2>/dev/null || true)
|
||||
if [ -z "$OID" ]; then
|
||||
if is_auth_kyc_body "$SCRATCH/ord-$tag.json"; then
|
||||
e2e_abort_auth "merchant-order" "merchant auth/KYC on pay $PAY_AMT"
|
||||
e2e_abort_auth "merchant-order" "merchant auth/KYC on pay $PAY_AMT ($PAY_SUM)"
|
||||
fi
|
||||
warn "pay $PAY_AMT" "order create failed — $(head -c 80 "$SCRATCH/ord-$tag.json" | tr '\n' ' ')"
|
||||
warn "pay $PAY_AMT ($PAY_SUM)" "order create failed — $(head -c 80 "$SCRATCH/ord-$tag.json" | tr '\n' ' ')"
|
||||
return 1
|
||||
fi
|
||||
ok "merchant order $OID ($PAY_AMT)"
|
||||
ok "merchant order $OID ($PAY_AMT · $PAY_SUM)"
|
||||
curl -skS -m 12 -o "$SCRATCH/ord-det-$tag.json" -H "$AUTH" \
|
||||
"${MERCHANT_PUBLIC}/instances/${INST}/private/orders/${OID}" 2>/dev/null || true
|
||||
PAYURI=$(python3 -c 'import json,sys
|
||||
|
|
@ -826,15 +835,18 @@ except Exception: print("")
|
|||
MH=$(python3 -c 'from urllib.parse import urlparse; print(urlparse("'"$MERCHANT_PUBLIC"'").hostname or "taler.hacktivism.ch")' 2>/dev/null || echo "taler.hacktivism.ch")
|
||||
PAYURI="taler://pay/${MH}/instances/${INST}/${OID}/?c=${OTOK}"
|
||||
fi
|
||||
# normalize default HTTPS port (wallets accept both)
|
||||
PAYURI=$(printf '%s' "$PAYURI" | sed 's/:443\//\//g; s/:443?/?/g')
|
||||
if [ -z "$PAYURI" ]; then
|
||||
warn "pay $PAY_AMT" "no pay URI for $OID"
|
||||
warn "pay $PAY_AMT ($PAY_SUM)" "no pay URI for $OID"
|
||||
return 1
|
||||
fi
|
||||
ok "taler_pay_uri ready ($tag)"
|
||||
if ! wcli_pay handle-uri --yes "$PAYURI" >"$SCRATCH/pay-$tag.out" 2>&1; then
|
||||
warn "pay $PAY_AMT" "handle-uri failed — $(tail -c 100 "$SCRATCH/pay-$tag.out" | tr '\n' ' ')"
|
||||
warn "pay $PAY_AMT ($PAY_SUM)" "handle-uri failed — $(tail -c 100 "$SCRATCH/pay-$tag.out" | tr '\n' ' ')"
|
||||
return 1
|
||||
fi
|
||||
ok "wallet handle pay $PAY_AMT"
|
||||
ok "wallet handle pay $PAY_AMT ($PAY_SUM)"
|
||||
local r
|
||||
for r in 1 2 3; do
|
||||
wcli_pay run-until-done >"$SCRATCH/pay-run-$tag.out" 2>&1 || true
|
||||
|
|
@ -847,11 +859,130 @@ except Exception: print("")
|
|||
d=json.load(open(sys.argv[1]))
|
||||
sys.exit(0 if d.get("paid") is True or str(d.get("order_status","")).lower()=="paid" else 1)
|
||||
' "$SCRATCH/ord-paid-$tag.json" 2>/dev/null; then
|
||||
ok "payment settled $PAY_AMT (order $OID)"
|
||||
ok "payment settled $PAY_AMT ($PAY_SUM · order $OID)"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
warn "pay $PAY_AMT" "not settled for order $OID"
|
||||
warn "pay $PAY_AMT ($PAY_SUM)" "not settled for order $OID"
|
||||
return 1
|
||||
}
|
||||
|
||||
# GOA shop samples from merchant landing (taler.hacktivism.ch/intro/)
|
||||
# id|product_name|amount — keep in sync with configs/merchant-landing/index.html
|
||||
# Landing QR encodes taler://pay-template/…/{id}; popup creates live pay via public POST templates/{id}.
|
||||
: "${E2E_SHOP_PRODUCTS:=orbit-sticker|Orbit sticker pack|GOA:2
|
||||
nebula-coffee|Nebula coffee|GOA:5
|
||||
voidwave-playlist|Voidwave playlist|GOA:8
|
||||
comet-cap|Comet cap|GOA:15
|
||||
shuttle-pass|Shuttle day pass|GOA:25
|
||||
beacon-badge|Beacon badge|GOA:3
|
||||
relay-pin|Relay pin|GOA:4
|
||||
eclipse-shades|Eclipse shades|GOA:12
|
||||
star-chart|Star chart print|GOA:7
|
||||
rainbow-pill|Rainbow pill (sample/joke)|GOA:4.2
|
||||
blue-or-red-pill|Blue or red pill (sample/joke)|GOA:1.5}"
|
||||
|
||||
# Settlement payto shown on landing shop popup (static)
|
||||
: "${E2E_SHOP_PAYTO:=payto://x-taler-bank/bank.hacktivism.ch/goa-demo-cp4zqk?receiver-name=GOA%20Demo%20Shop%20cp4zqk}"
|
||||
|
||||
# Pay one shop product the way the public landing does:
|
||||
# POST /instances/{inst}/templates/{id} body {} → order_id+token → taler_pay_uri
|
||||
# Also checks pay-template URI shape (what qrencode PNGs encode).
|
||||
# Usage: e2e_one_pay_public_template PRODUCT_ID PRODUCT_NAME AMOUNT
|
||||
e2e_one_pay_public_template() {
|
||||
local pid="$1"
|
||||
local pname="${2:-$1}"
|
||||
local pamt="$3"
|
||||
local tag
|
||||
tag=$(printf 'shop_%s' "$pid" | tr -c 'A-Za-z0-9._-' '_')
|
||||
section "e2e · shop product · $pname ($pid) · $pamt"
|
||||
e2e_over && { warn "shop $pname" "budget exhausted — skip"; return 1; }
|
||||
|
||||
local MH
|
||||
MH=$(python3 -c 'from urllib.parse import urlparse; print(urlparse("'"$MERCHANT_PUBLIC"'").hostname or "taler.hacktivism.ch")' 2>/dev/null || echo "taler.hacktivism.ch")
|
||||
local TPL_URI="taler://pay-template/${MH}/instances/${INST}/${pid}"
|
||||
local TPL_HTTPS="${MERCHANT_PUBLIC}/instances/${INST}/templates/$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=""))' "$pid")"
|
||||
info "shop $pname" "pay-template URI $TPL_URI"
|
||||
info "shop $pname" "public template POST $TPL_HTTPS"
|
||||
info "shop $pname" "settlement payto $E2E_SHOP_PAYTO"
|
||||
|
||||
# Public create (no merchant secret) — same as shop-pay.js
|
||||
curl -skS -m 15 -o "$SCRATCH/tpl-$tag.json" -X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{}' \
|
||||
"$TPL_HTTPS" 2>"$SCRATCH/tpl-$tag.err" || true
|
||||
if ! grep -q order_id "$SCRATCH/tpl-$tag.json" 2>/dev/null; then
|
||||
if [ "$E2E_REMOTE" != "1" ] && koopa_ssh_ok; then
|
||||
koopa_ssh_run 20 \
|
||||
"curl -skS -m 12 -X POST -H 'Content-Type: application/json' -d '{}' 'https://127.0.0.1:9010/instances/${INST}/templates/${pid}'" \
|
||||
>"$SCRATCH/tpl-$tag.json" 2>"$SCRATCH/tpl-$tag.err" || true
|
||||
fi
|
||||
fi
|
||||
OID=$(python3 -c 'import json,re,sys;t=open(sys.argv[1]).read()
|
||||
try: print(json.loads(t).get("order_id") or "")
|
||||
except Exception:
|
||||
m=re.search(r"\"order_id\"\s*:\s*\"([^\"]+)\"",t); print(m.group(1) if m else "")
|
||||
' "$SCRATCH/tpl-$tag.json" 2>/dev/null || true)
|
||||
OTOK=$(python3 -c 'import json,re,sys;t=open(sys.argv[1]).read()
|
||||
try: print(json.loads(t).get("token") or "")
|
||||
except Exception:
|
||||
m=re.search(r"\"token\"\s*:\s*\"([^\"]+)\"",t); print(m.group(1) if m else "")
|
||||
' "$SCRATCH/tpl-$tag.json" 2>/dev/null || true)
|
||||
if [ -z "$OID" ] || [ -z "$OTOK" ]; then
|
||||
warn "shop $pname ($pid)" "public template POST failed — $(head -c 100 "$SCRATCH/tpl-$tag.json" 2>/dev/null | tr '\n' ' ')"
|
||||
return 1
|
||||
fi
|
||||
ok "shop $pname" "public order $OID (template $pid)"
|
||||
|
||||
local statusUrl="${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")"
|
||||
curl -skS -m 12 -o "$SCRATCH/tpl-st-$tag.json" "$statusUrl" 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 "")
|
||||
except Exception: print("")
|
||||
' "$SCRATCH/tpl-st-$tag.json" 2>/dev/null || true)
|
||||
if [ -z "$PAYURI" ]; then
|
||||
PAYURI="taler://pay/${MH}/instances/${INST}/${OID}/?c=${OTOK}"
|
||||
fi
|
||||
PAYURI=$(printf '%s' "$PAYURI" | sed 's/:443\//\//g; s/:443?/?/g')
|
||||
if ! printf '%s' "$PAYURI" | grep -q '^taler://pay/'; then
|
||||
warn "shop $pname ($pid)" "bad pay URI: $PAYURI"
|
||||
return 1
|
||||
fi
|
||||
ok "shop $pname" "taler_pay_uri $PAYURI"
|
||||
|
||||
if ! wcli_pay handle-uri --yes "$PAYURI" >"$SCRATCH/pay-$tag.out" 2>&1; then
|
||||
warn "shop $pname ($pid)" "handle-uri failed — $(tail -c 120 "$SCRATCH/pay-$tag.out" | tr '\n' ' ')"
|
||||
return 1
|
||||
fi
|
||||
ok "shop $pname" "wallet accepted pay URI"
|
||||
|
||||
local r AUTH=""
|
||||
if [ -n "${MPW:-}" ]; then
|
||||
AUTH="Authorization: Bearer secret-token:${MPW}"
|
||||
fi
|
||||
for r in 1 2 3; do
|
||||
wcli_pay run-until-done >"$SCRATCH/pay-run-$tag.out" 2>&1 || true
|
||||
wcli_pay transactions >"$SCRATCH/tx-$tag.out" 2>&1 || true
|
||||
if [ -n "$AUTH" ]; then
|
||||
curl -skS -m 8 -o "$SCRATCH/ord-paid-$tag.json" -H "$AUTH" \
|
||||
"${MERCHANT_PUBLIC}/instances/${INST}/private/orders/${OID}" 2>/dev/null || true
|
||||
if python3 -c 'import json,sys
|
||||
d=json.load(open(sys.argv[1]))
|
||||
sys.exit(0 if d.get("paid") is True or str(d.get("order_status","")).lower()=="paid" else 1)
|
||||
' "$SCRATCH/ord-paid-$tag.json" 2>/dev/null; then
|
||||
ok "shop $pname" "payment settled ($pamt · order $OID)"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
if grep -qiE 'payment|paid|Payment' "$SCRATCH/tx-$tag.out" 2>/dev/null \
|
||||
|| grep -qiE 'done|paid|success|Payment' "$SCRATCH/pay-$tag.out" 2>/dev/null; then
|
||||
ok "shop $pname" "payment settled via wallet tx ($pamt · order $OID)"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
warn "shop $pname ($pid)" "not settled for order $OID"
|
||||
return 1
|
||||
}
|
||||
|
||||
|
|
@ -974,10 +1105,65 @@ if [ "$PAY_OK" != "1" ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
section "e2e · GOA shop products (merchant landing catalog)"
|
||||
# ---------------------------------------------------------------------------
|
||||
# Public template POST + wallet pay — product id|name|amount (landing QR = pay-template).
|
||||
SHOP_OK=0
|
||||
SHOP_OK_N=0
|
||||
SHOP_FAIL_N=0
|
||||
SHOP_SKIP_N=0
|
||||
SHOP_REPORT=""
|
||||
if [ "$E2E_REMOTE" = "1" ] || [ "${CUR:-}" != "GOA" ]; then
|
||||
info "goa-shop" "SKIPPED (remote or non-GOA currency)"
|
||||
else
|
||||
info "goa-shop" "public template pays for each sample (id · product name · amount)"
|
||||
info "goa-shop payto" "$E2E_SHOP_PAYTO"
|
||||
while IFS= read -r line; do
|
||||
[ -z "$line" ] && continue
|
||||
case "$line" in \#*) continue ;; esac
|
||||
e2e_over && { warn "goa-shop" "time budget low — stopping product pays"; break; }
|
||||
pid=$(printf '%s' "$line" | cut -d'|' -f1)
|
||||
pname=$(printf '%s' "$line" | cut -d'|' -f2)
|
||||
pamt=$(printf '%s' "$line" | cut -d'|' -f3)
|
||||
[ -z "$pid" ] || [ -z "$pamt" ] && continue
|
||||
[ -z "$pname" ] && pname="$pid"
|
||||
av_now=$(wallet_avail_num)
|
||||
pay_n=$(python3 -c 'import sys; print(float(sys.argv[1].split(":",1)[-1]))' "$pamt" 2>/dev/null || echo 0)
|
||||
if ! python3 -c "import sys; sys.exit(0 if float(sys.argv[1]) + 1e-12 >= float(sys.argv[2]) else 1)" "$av_now" "$pay_n" 2>/dev/null; then
|
||||
warn "goa-shop $pname ($pid)" "skip — insufficient avail ${CUR}:${av_now} (need ${pay_n})"
|
||||
SHOP_SKIP_N=$((SHOP_SKIP_N + 1))
|
||||
SHOP_REPORT="${SHOP_REPORT}${SHOP_REPORT:+ }${pname}=SKIP(bal)"
|
||||
continue
|
||||
fi
|
||||
set +e
|
||||
e2e_one_pay_public_template "$pid" "$pname" "$pamt"
|
||||
pc=$?
|
||||
set -e
|
||||
if [ "$pc" = "0" ]; then
|
||||
SHOP_OK=1
|
||||
SHOP_OK_N=$((SHOP_OK_N + 1))
|
||||
PAY_OK=1
|
||||
PAY_OK_N=$((PAY_OK_N + 1))
|
||||
SHOP_REPORT="${SHOP_REPORT}${SHOP_REPORT:+ }${pname}=OK"
|
||||
else
|
||||
SHOP_FAIL_N=$((SHOP_FAIL_N + 1))
|
||||
SHOP_REPORT="${SHOP_REPORT}${SHOP_REPORT:+ }${pname}=FAIL"
|
||||
fi
|
||||
done <<EOF
|
||||
$E2E_SHOP_PRODUCTS
|
||||
EOF
|
||||
info "goa-shop summary" "$SHOP_REPORT (ok=$SHOP_OK_N fail=$SHOP_FAIL_N skip=$SHOP_SKIP_N)"
|
||||
if [ "$SHOP_OK" != "1" ] && [ "$SHOP_FAIL_N" -gt 0 ]; then
|
||||
warn "goa-shop" "no sample product payment succeeded ($SHOP_REPORT)"
|
||||
fi
|
||||
fi
|
||||
|
||||
section "e2e · report"
|
||||
info "user" "$USER"
|
||||
info "ATM withdraws" "$WITHDRAW_REPORT"
|
||||
info "payments" "$PAY_REPORT"
|
||||
info "goa-shop" "${SHOP_REPORT:-(n/a)}"
|
||||
info "final balance" "$(fmt_bal "$SCRATCH/bal-live.out" 2>/dev/null || echo "(n/a)")"
|
||||
info "scratch" "$SCRATCH"
|
||||
# Success if we had coins and at least one pay, OR coins + only pay skips (nothing affordable)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue