taler-monitoring: shop e2e uses catalog list and random pick of two

The GOA shop e2e path used to walk every product template every run, which
was slow and often hit balance or time budgets after the first few pays.

Keep the full catalog in E2E_SHOP_PRODUCTS (id|name|amount, synced with the
merchant landing). Each e2e run shuffles that list and pays only
E2E_SHOP_PICK_N products (default 2). Shop pays pin instance goa-shop for
public template POSTs; settlement payto matches the landing shop popup.

Docs in README.md and TESTS.md describe the pick behaviour and env overrides.
This commit is contained in:
Hernâni Marques 2026-07-10 20:28:15 +02:00
parent c7f86dd3da
commit 04bafc84a6
No known key found for this signature in database
3 changed files with 83 additions and 44 deletions

View file

@ -61,9 +61,10 @@ Other domains: never SSH. Optional **e2e** aborts cleanly on login/KYC.
# customize:
E2E_WITHDRAW_VALUES="20 50 100" E2E_PAY_VALUES="0.05 1 5" ./taler-monitoring.sh e2e
E2E_VARIABLE=0 WITHDRAW_AMT=GOA:50 PAY_AMT=GOA:1 ./taler-monitoring.sh e2e # single fixed
# GOA shop catalog (local hacktivism): public template POST + wallet pay per product
# GOA shop catalog (local hacktivism): full list in E2E_SHOP_PRODUCTS; each run
# shuffles and pays E2E_SHOP_PICK_N products (default 2).
# E2E_SHOP_PRODUCTS lines: id|Product name|GOA:amount
# E2E_SHOP_PRODUCTS=$'orbit-sticker|Orbit sticker pack|GOA:2\nnebula-coffee|Nebula coffee|GOA:5'
# E2E_SHOP_PICK_N=2
# (landing QR = taler://pay-template/…/{id}; popup = live taler://pay after POST templates/{id})
# remote secrets:
# E2E_BANK_ADMIN_PASS=… E2E_MERCHANT_TOKEN=…

View file

@ -132,12 +132,13 @@ Without SSH (`SKIP_SSH=1` or remote domain): still runs outside-in repo checks;
| e2e-003 | mode / currency info |
| e2e-004… | secrets, reachability gates |
| e2e-… | account, credit, withdraw, confirm, coins, order, pay ladder |
| e2e-… | **GOA shop products** by **product name** (public template POST → `taler://pay`, pay-template URI, payto) |
| e2e-… | **GOA shop products** — full catalog list; **random pick of 2** (override `E2E_SHOP_PICK_N`) |
| e2e-… | balances, dig on failure |
Shop product pays use instance `goa-demo-cp4zqk` (default) and `E2E_SHOP_PRODUCTS`
(`id|Product name|amount` lines). Flow matches the landing popup (public POST
`/templates/{id}`, not private orders). Report labels use the product name.
Shop product pays use instance `goa-shop` (default) and catalog `E2E_SHOP_PRODUCTS`
(`id|Product name|amount` lines). Each e2e run **shuffles** the catalog and pays
only `E2E_SHOP_PICK_N` products (**default 2**). Flow matches the landing popup
(public POST `/templates/{id}`, not private orders). Report labels use product name.
Blockers keep the same ID prefix: `[BLOCKER] e2e-0NN step: message`.

View file

@ -867,9 +867,10 @@ sys.exit(0 if d.get("paid") is True or str(d.get("order_status","")).lower()=="p
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}.
# GOA shop catalog (full list) — keep in sync with configs/merchant-landing/index.html
# id|product_name|amount
# Landing QR = taler://pay-template/…/{id}; popup = public POST templates/{id}.
# E2E does not pay every product every run: shuffle + pick E2E_SHOP_PICK_N (default 2).
: "${E2E_SHOP_PRODUCTS:=orbit-sticker|Orbit sticker pack|GOA:2
nebula-coffee|Nebula coffee|GOA:5
voidwave-playlist|Voidwave playlist|GOA:8
@ -881,9 +882,12 @@ 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}"
: "${E2E_SHOP_PICK_N:=2}"
# Public templates live on goa-shop (landing shop-pay.js); not the e2e default demo instance.
: "${E2E_SHOP_INSTANCE:=goa-shop}"
# 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}"
: "${E2E_SHOP_PAYTO:=payto://x-taler-bank/bank.hacktivism.ch/goa-shop?receiver-name=GOA%20Shop}"
# Pay one shop product the way the public landing does:
# POST /instances/{inst}/templates/{id} body {} → order_id+token → taler_pay_uri
@ -1108,7 +1112,7 @@ fi
# ---------------------------------------------------------------------------
section "e2e · GOA shop products (merchant landing catalog)"
# ---------------------------------------------------------------------------
# Public template POST + wallet pay — product id|name|amount (landing QR = pay-template).
# Public template POST + wallet pay — full catalog list, random pick of N products.
SHOP_OK=0
SHOP_OK_N=0
SHOP_FAIL_N=0
@ -1117,45 +1121,78 @@ 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"
# Build catalog array from E2E_SHOP_PRODUCTS (id|name|amount lines)
SHOP_CATALOG=()
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
SHOP_CATALOG+=("$line")
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)"
SHOP_CAT_N=${#SHOP_CATALOG[@]}
PICK_N="${E2E_SHOP_PICK_N:-2}"
case "$PICK_N" in ''|*[!0-9]*) PICK_N=2 ;; esac
if [ "$PICK_N" -lt 1 ]; then PICK_N=1; fi
if [ "$SHOP_CAT_N" -eq 0 ]; then
warn "goa-shop" "empty E2E_SHOP_PRODUCTS catalog"
else
if [ "$PICK_N" -gt "$SHOP_CAT_N" ]; then PICK_N=$SHOP_CAT_N; fi
# Shuffle catalog, take first PICK_N (portable: python)
SHOP_PICKED=$(
printf '%s\n' "${SHOP_CATALOG[@]}" | python3 -c "
import random, sys
lines = [ln.strip() for ln in sys.stdin if ln.strip()]
n = min(int(sys.argv[1]), len(lines))
random.shuffle(lines)
print('\n'.join(lines[:n]))
" "$PICK_N"
)
info "goa-shop" "catalog ${SHOP_CAT_N} products · random pick ${PICK_N} · instance ${E2E_SHOP_INSTANCE}"
info "goa-shop payto" "$E2E_SHOP_PAYTO"
info "goa-shop pick" "$(printf '%s\n' "$SHOP_PICKED" | cut -d'|' -f1,2 | tr '\n' '; ' | sed 's/; $//')"
# e2e_one_pay_public_template uses global INST — temporarily pin shop instance
_E2E_INST_SAVE="$INST"
INST="${E2E_SHOP_INSTANCE}"
while IFS= read -r line; do
[ -z "$line" ] && continue
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
$SHOP_PICKED
EOF
INST="$_E2E_INST_SAVE"
unset _E2E_INST_SAVE
info "goa-shop summary" "$SHOP_REPORT (ok=$SHOP_OK_N fail=$SHOP_FAIL_N skip=$SHOP_SKIP_N · pick $PICK_N/$SHOP_CAT_N)"
if [ "$SHOP_OK" != "1" ] && [ "$SHOP_FAIL_N" -gt 0 ]; then
warn "goa-shop" "no sample product payment succeeded ($SHOP_REPORT)"
fi
fi
fi