release 1.24.0: zero-pay phase (stage.my default, TESTPAYSAN templates)
This commit is contained in:
parent
a1275e6e45
commit
ee99f0de99
9 changed files with 526 additions and 2 deletions
472
check_zero_pay.sh
Executable file
472
check_zero_pay.sh
Executable file
|
|
@ -0,0 +1,472 @@
|
|||
#!/usr/bin/env bash
|
||||
# Phase zero-pay: public-template pays (CHF:0 stickers / TESTPAYSAN shop).
|
||||
# Same path as e2e_one_pay_public_template. Never run-until-done.
|
||||
# Wrapper: pay_talersticker_zero.sh (COUNT default 100).
|
||||
#
|
||||
# Env: COUNT (phase default 1) GAP_S PARALLEL MERCHANT INST TEMPLATE AMOUNT
|
||||
# EXCHANGE ZERO_PAY_POST=amount|empty HANDLE_SECS SETTLE_TRIES SETTLE_SLEEP
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
ROOT=$(cd "$(dirname "$0")" && pwd)
|
||||
# shellcheck source=lib.sh
|
||||
source "$ROOT/lib.sh"
|
||||
# shellcheck source=metrics.sh
|
||||
source "$ROOT/metrics.sh"
|
||||
set_area zero-pay
|
||||
|
||||
# Homebrew python3 (>=3.11) must beat /usr/bin/python3 3.9 — taler-helper-sqlite3.
|
||||
export PATH="/opt/homebrew/bin:${HOME}/.local/bin:/usr/local/bin:/usr/bin:/bin:${PATH:-}"
|
||||
|
||||
die() { echo "ERROR: $*" >&2; fail "zero-pay" "$*" 2>/dev/null || true; exit 1; }
|
||||
|
||||
COUNT="${COUNT:-${ZERO_PAY_COUNT:-1}}"
|
||||
GAP_S="${GAP_S:-0}"
|
||||
PARALLEL="${PARALLEL:-1}"
|
||||
MERCHANT="${MERCHANT:-${MERCHANT_PUBLIC:-https://stage.my.taler-ops.ch}}"
|
||||
MERCHANT="${MERCHANT%/}"
|
||||
CUR="${EXPECT_CURRENCY:-${CUR:-}}"
|
||||
if [ "$CUR" = "TESTPAYSAN" ]; then
|
||||
INST="${INST:-${ZERO_PAY_INST:-jardin-du-creux}}"
|
||||
TEMPLATE="${TEMPLATE:-${ZERO_PAY_TEMPLATE:-oeufs-6}}"
|
||||
AMOUNT="${AMOUNT:-${ZERO_PAY_AMOUNT:-TESTPAYSAN:5}}"
|
||||
EXCHANGE="${EXCHANGE:-${EXCHANGE_PUBLIC:-https://stage.exchange.lefrancpaysan.ch/}}"
|
||||
ZERO_PAY_POST="${ZERO_PAY_POST:-empty}"
|
||||
else
|
||||
INST="${INST:-${ZERO_PAY_INST:-admin}}"
|
||||
TEMPLATE="${TEMPLATE:-${ZERO_PAY_TEMPLATE:-stickers}}"
|
||||
AMOUNT="${AMOUNT:-${ZERO_PAY_AMOUNT:-CHF:0}}"
|
||||
EXCHANGE="${EXCHANGE:-${EXCHANGE_PUBLIC:-https://exchange.stage.taler-ops.ch/}}"
|
||||
ZERO_PAY_POST="${ZERO_PAY_POST:-amount}"
|
||||
fi
|
||||
EXCHANGE="${EXCHANGE%/}/"
|
||||
HANDLE_SECS="${HANDLE_SECS:-25}"
|
||||
SETTLE_TRIES="${SETTLE_TRIES:-40}"
|
||||
SETTLE_SLEEP="${SETTLE_SLEEP:-0.15}"
|
||||
case "$GAP_S" in
|
||||
''|*[!0-9.]*|*.*.*) die "GAP_S must be a non-negative number (got $GAP_S)" ;;
|
||||
esac
|
||||
case "$COUNT" in
|
||||
''|*[!0-9]*) die "COUNT must be a positive integer (got $COUNT)" ;;
|
||||
esac
|
||||
[ "$COUNT" -ge 1 ] || die "COUNT must be >= 1"
|
||||
case "$PARALLEL" in
|
||||
all|ALL) PARALLEL="$COUNT" ;;
|
||||
''|*[!0-9]*) die "PARALLEL must be a positive integer or all (got $PARALLEL)" ;;
|
||||
esac
|
||||
[ "$PARALLEL" -ge 1 ] || die "PARALLEL must be >= 1"
|
||||
if [ "$PARALLEL" -gt "$COUNT" ]; then
|
||||
PARALLEL="$COUNT"
|
||||
fi
|
||||
|
||||
OUTDIR="${OUTDIR:-/tmp/talersticker-zero-$(date +%Y%m%d-%H%M%S)}"
|
||||
mkdir -p "$OUTDIR"
|
||||
TSV="$OUTDIR/results.tsv"
|
||||
LOG="$OUTDIR/run.log"
|
||||
SCRATCH="$OUTDIR/scratch"
|
||||
mkdir -p "$SCRATCH"
|
||||
SERVE_PIDFILE="$OUTDIR/serve.pids"
|
||||
|
||||
if [ -z "${TALER_MON_STATE:-}" ]; then
|
||||
exec > >(tee -a "$LOG") 2>&1
|
||||
fi
|
||||
|
||||
now_ms() { python3 -c 'import time; print(int(time.time()*1000))'; }
|
||||
|
||||
slot_db() { echo "$OUTDIR/wallet-$1.sqlite3"; }
|
||||
slot_sock() { echo "$OUTDIR/wallet-$1.sock"; }
|
||||
slot_log() { echo "$OUTDIR/wallet-serve-$1.log"; }
|
||||
|
||||
stop_wallet_serve() {
|
||||
if [ -f "$SERVE_PIDFILE" ]; then
|
||||
while read -r pid; do
|
||||
[ -n "$pid" ] || continue
|
||||
kill "$pid" 2>/dev/null || true
|
||||
wait "$pid" 2>/dev/null || true
|
||||
done <"$SERVE_PIDFILE"
|
||||
rm -f "$SERVE_PIDFILE"
|
||||
fi
|
||||
rm -f "$OUTDIR"/wallet-*.sock 2>/dev/null || true
|
||||
}
|
||||
trap 'stop_wallet_serve' EXIT
|
||||
|
||||
_wcli_exec() {
|
||||
local cap="$1"
|
||||
shift
|
||||
local -a cmd
|
||||
cmd=( "$NODE_BIN" "$WALLET_CLI" "$@" )
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout -k 2 "$cap" "${cmd[@]}"
|
||||
elif command -v gtimeout >/dev/null 2>&1; then
|
||||
gtimeout --kill-after=2 "$cap" "${cmd[@]}"
|
||||
else
|
||||
perl -e 'alarm shift; exec @ARGV' "$cap" "${cmd[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
wcli_slot() {
|
||||
local slot="$1"
|
||||
local cap="$2"
|
||||
shift 2
|
||||
local sock db
|
||||
sock=$(slot_sock "$slot")
|
||||
db=$(slot_db "$slot")
|
||||
if [ -S "$sock" ]; then
|
||||
_wcli_exec "$cap" --wallet-connection="$sock" --no-throttle "$@"
|
||||
else
|
||||
_wcli_exec "$cap" --wallet-db="$db" --no-throttle --skip-defaults "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
start_wallet_slot() {
|
||||
local slot="$1"
|
||||
local sock db log
|
||||
sock=$(slot_sock "$slot")
|
||||
db=$(slot_db "$slot")
|
||||
log=$(slot_log "$slot")
|
||||
rm -f "$sock"
|
||||
"$NODE_BIN" "$WALLET_CLI" --wallet-db="$db" --no-throttle --skip-defaults \
|
||||
advanced serve --unix-path "$sock" \
|
||||
>"$log" 2>&1 &
|
||||
local pid=$!
|
||||
echo "$pid" >>"$SERVE_PIDFILE"
|
||||
local i
|
||||
for i in $(seq 1 50); do
|
||||
if [ -S "$sock" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
info "wallet serve slot=$slot pid=$pid"
|
||||
return 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
echo "WARN: wallet serve slot=$slot socket not ready"
|
||||
return 1
|
||||
}
|
||||
|
||||
find_wallet_cli() {
|
||||
if [ -n "${WALLET_CLI:-}" ] && [ -f "$WALLET_CLI" ]; then
|
||||
printf '%s\n' "$WALLET_CLI"
|
||||
return 0
|
||||
fi
|
||||
local c
|
||||
for c in \
|
||||
"${HOME}/src/llm-qwythos/taler/taler-typescript-core/packages/taler-wallet-cli/bin/taler-wallet-cli.mjs" \
|
||||
"${HOME}/src/taler/taler-typescript-core/packages/taler-wallet-cli/bin/taler-wallet-cli.mjs" \
|
||||
"${HOME}/.local/bin/taler-wallet-cli.mjs" \
|
||||
"${HOME}/src/llm-qwythos/taler/taler-typescript-core/packages/taler-wallet-cli/dist/taler-wallet-cli-bundled.cjs"
|
||||
do
|
||||
[ -f "$c" ] && { printf '%s\n' "$c"; return 0; }
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
NODE_BIN=$(command -v node) || die "node not found"
|
||||
python3 - <<'PY' || die "python3 >= 3.11 required (taler-helper-sqlite3)"
|
||||
import sys
|
||||
raise SystemExit(0 if sys.version_info >= (3, 11) else 1)
|
||||
PY
|
||||
command -v taler-helper-sqlite3 >/dev/null || die "taler-helper-sqlite3 not on PATH"
|
||||
WALLET_CLI=$(find_wallet_cli) || die "taler-wallet-cli .mjs not found (set WALLET_CLI=)"
|
||||
|
||||
json_get() {
|
||||
python3 -c 'import json,sys
|
||||
p,k=sys.argv[1],sys.argv[2]
|
||||
try:
|
||||
d=json.load(open(p))
|
||||
v=d
|
||||
for part in k.split("."):
|
||||
if isinstance(v, dict):
|
||||
v=v.get(part)
|
||||
else:
|
||||
v=None
|
||||
break
|
||||
print("" if v is None else v)
|
||||
except Exception:
|
||||
print("")
|
||||
' "$@"
|
||||
}
|
||||
|
||||
create_template_order() {
|
||||
local summary="$1" out="$2"
|
||||
local body url
|
||||
if [ "${ZERO_PAY_POST}" = "empty" ]; then
|
||||
body='{}'
|
||||
else
|
||||
body=$(python3 -c 'import json,sys; print(json.dumps({"amount":sys.argv[1],"summary":sys.argv[2]}))' "$AMOUNT" "$summary")
|
||||
fi
|
||||
url="${MERCHANT}/instances/${INST}/templates/${TEMPLATE}"
|
||||
if [ "$INST" = "admin" ] || [ "$INST" = "default" ] || [ -z "$INST" ]; then
|
||||
url="${MERCHANT}/templates/${TEMPLATE}"
|
||||
fi
|
||||
curl -sS -m 20 -X POST -H "Content-Type: application/json" -d "$body" "$url" >"$out"
|
||||
}
|
||||
|
||||
order_public() {
|
||||
local oid="$1" tok="$2" out="$3"
|
||||
local qoid qtok base
|
||||
qoid=$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=""))' "$oid")
|
||||
qtok=$(python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1], safe=""))' "$tok")
|
||||
if [ "$INST" = "admin" ] || [ "$INST" = "default" ] || [ -z "$INST" ]; then
|
||||
base="${MERCHANT}/orders/${qoid}?token=${qtok}"
|
||||
else
|
||||
base="${MERCHANT}/instances/${INST}/orders/${qoid}?token=${qtok}"
|
||||
fi
|
||||
curl -sS -m 12 "$base" >"$out"
|
||||
}
|
||||
|
||||
order_is_paid() {
|
||||
python3 -c 'import json,sys
|
||||
try:
|
||||
d=json.load(open(sys.argv[1]))
|
||||
except Exception:
|
||||
raise SystemExit(1)
|
||||
if d.get("paid") is True or str(d.get("order_status","")).lower()=="paid":
|
||||
raise SystemExit(0)
|
||||
if "refunded" in d or "refund_amount" in d:
|
||||
raise SystemExit(0)
|
||||
raise SystemExit(1)
|
||||
' "$1"
|
||||
}
|
||||
|
||||
wallet_handle_done() {
|
||||
grep -q "Finished with status .done." "$1" 2>/dev/null
|
||||
}
|
||||
|
||||
write_row() {
|
||||
# n oid create handle settle total status payuri
|
||||
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$@"
|
||||
}
|
||||
|
||||
# One payment. Args: n slot. Always writes scratch/row.N.tsv and scratch/msg.N.txt.
|
||||
do_one_pay() {
|
||||
local n="$1" slot="$2"
|
||||
local tag
|
||||
tag=$(printf '%03d' "$n")
|
||||
local nonce summary create_f status_f pay_f row_f msg_f
|
||||
nonce="${n}-$(date +%s)-$RANDOM"
|
||||
summary="taler-monitoring zero-pay #${n} ${nonce}"
|
||||
create_f="$SCRATCH/ord-$tag.json"
|
||||
status_f="$SCRATCH/st-$tag.json"
|
||||
pay_f="$SCRATCH/pay-$tag.out"
|
||||
row_f="$SCRATCH/row.$n.tsv"
|
||||
msg_f="$SCRATCH/msg.$n.txt"
|
||||
|
||||
local t0 t1 t_create t_h0 t_h1 t_s0 t_s1
|
||||
local create_ms handle_ms settle_ms total_ms
|
||||
local oid tok payuri hint hc status
|
||||
local settled merchant_paid i fail_tail
|
||||
|
||||
t0=$(now_ms)
|
||||
if ! create_template_order "$summary" "$create_f"; then
|
||||
t1=$(now_ms)
|
||||
create_ms=$((t1-t0))
|
||||
write_row "$n" "" "$create_ms" "" "" "$create_ms" "CREATE_HTTP_FAIL" "" >"$row_f"
|
||||
echo "[$tag] CREATE_HTTP_FAIL ${create_ms}ms slot=$slot" >"$msg_f"
|
||||
return 0
|
||||
fi
|
||||
oid=$(json_get "$create_f" order_id)
|
||||
tok=$(json_get "$create_f" token)
|
||||
t_create=$(now_ms)
|
||||
create_ms=$((t_create-t0))
|
||||
if [ -z "$oid" ] || [ -z "$tok" ]; then
|
||||
hint=$(json_get "$create_f" hint)
|
||||
write_row "$n" "" "$create_ms" "" "" "$create_ms" "CREATE_FAIL" "" >"$row_f"
|
||||
echo "[$tag] CREATE_FAIL ${create_ms}ms hint=${hint} slot=$slot" >"$msg_f"
|
||||
return 0
|
||||
fi
|
||||
|
||||
order_public "$oid" "$tok" "$status_f" || true
|
||||
payuri=$(json_get "$status_f" taler_pay_uri)
|
||||
if [ -z "$payuri" ]; then
|
||||
local mh
|
||||
mh=$(python3 -c 'from urllib.parse import urlparse; print(urlparse("'"$MERCHANT"'").hostname or "")')
|
||||
payuri="taler://pay/${mh}/instances/${INST}/${oid}/?c=${tok}"
|
||||
fi
|
||||
payuri=$(printf '%s' "$payuri" | sed 's/:443\//\//g; s/:443?/?/g')
|
||||
|
||||
t_h0=$(now_ms)
|
||||
set +e
|
||||
wcli_slot "$slot" "$HANDLE_SECS" handle-uri --yes --non-interactive "$payuri" >"$pay_f" 2>&1
|
||||
hc=$?
|
||||
set -e
|
||||
t_h1=$(now_ms)
|
||||
handle_ms=$((t_h1-t_h0))
|
||||
if grep -q "Payment failed" "$pay_f" 2>/dev/null; then
|
||||
hc=1
|
||||
fi
|
||||
|
||||
settled=0
|
||||
merchant_paid=0
|
||||
t_s0=$(now_ms)
|
||||
i=1
|
||||
while [ "$i" -le "$SETTLE_TRIES" ]; do
|
||||
order_public "$oid" "$tok" "$status_f" || true
|
||||
if order_is_paid "$status_f"; then
|
||||
merchant_paid=1
|
||||
settled=1
|
||||
break
|
||||
fi
|
||||
if wallet_handle_done "$pay_f"; then
|
||||
settled=1
|
||||
fi
|
||||
if [ "$settled" = "1" ] && [ "$i" -ge 3 ]; then
|
||||
break
|
||||
fi
|
||||
sleep "$SETTLE_SLEEP"
|
||||
i=$((i+1))
|
||||
done
|
||||
t_s1=$(now_ms)
|
||||
settle_ms=$((t_s1-t_s0))
|
||||
total_ms=$((t_s1-t0))
|
||||
|
||||
if [ "$merchant_paid" = "1" ] || [ "$settled" = "1" ]; then
|
||||
status=PAID
|
||||
elif [ "$hc" = "0" ]; then
|
||||
status=HANDLE_OK_UNSETTLED
|
||||
else
|
||||
status=HANDLE_FAIL
|
||||
fi
|
||||
write_row "$n" "$oid" "$create_ms" "$handle_ms" "$settle_ms" "$total_ms" "$status" "$payuri" >"$row_f"
|
||||
echo "[$tag] $status oid=$oid create=${create_ms}ms handle=${handle_ms}ms settle=${settle_ms}ms total=${total_ms}ms slot=$slot" >"$msg_f"
|
||||
if [ "$status" != "PAID" ]; then
|
||||
fail_tail=$(tail -c 180 "$pay_f" | tr '\n' ' ')
|
||||
echo " handle-exit=${hc} tail=${fail_tail}" >>"$msg_f"
|
||||
fi
|
||||
}
|
||||
|
||||
prep_slot_exchange() {
|
||||
local slot="$1"
|
||||
wcli_slot "$slot" 40 exchanges add "$EXCHANGE" >"$OUTDIR/exchanges-add-$slot.out" 2>&1 || true
|
||||
wcli_slot "$slot" 40 exchanges tos "$EXCHANGE" >"$OUTDIR/exchanges-tos-$slot.out" 2>&1 || true
|
||||
wcli_slot "$slot" 40 exchanges accept-tos "$EXCHANGE" >"$OUTDIR/exchanges-accept-tos-$slot.out" 2>&1 || true
|
||||
}
|
||||
|
||||
section "zero-pay · ${AMOUNT} x ${COUNT} · ${INST}/${TEMPLATE}"
|
||||
info "merchant $MERCHANT"
|
||||
info "instance $INST"
|
||||
info "template $TEMPLATE amount=$AMOUNT"
|
||||
info "wallet $WALLET_CLI"
|
||||
info "python $(command -v python3) $(python3 -c 'import sys; print(".".join(map(str,sys.version_info[:3])))')"
|
||||
info "helper $(command -v taler-helper-sqlite3)"
|
||||
info "outdir $OUTDIR"
|
||||
info "gap ${GAP_S}s between blocks (not in total_ms)"
|
||||
info "parallel $PARALLEL per block (own wallet serve per slot)"
|
||||
if [ "$PARALLEL" -gt 20 ]; then
|
||||
echo "WARN: PARALLEL=$PARALLEL starts that many wallet-cli node processes"
|
||||
fi
|
||||
|
||||
wcli_slot 0 25 version >"$OUTDIR/wallet-version.txt" 2>&1 || true
|
||||
info "wallet-cli $(head -1 "$OUTDIR/wallet-version.txt" 2>/dev/null || echo '?')"
|
||||
|
||||
: >"$SERVE_PIDFILE"
|
||||
slot=0
|
||||
while [ "$slot" -lt "$PARALLEL" ]; do
|
||||
start_wallet_slot "$slot" || true
|
||||
prep_slot_exchange "$slot"
|
||||
slot=$((slot+1))
|
||||
done
|
||||
|
||||
wcli_slot 0 20 balance >"$OUTDIR/balance-before.txt" 2>&1 || true
|
||||
info "balance before: $(tr '\n' ' ' < "$OUTDIR/balance-before.txt" | tail -c 200)"
|
||||
|
||||
printf 'n\torder_id\tcreate_ms\thandle_ms\tsettle_ms\ttotal_ms\tstatus\tpay_uri\n' >"$TSV"
|
||||
|
||||
ok_n=0
|
||||
fail_n=0
|
||||
RUN_START_MS=$(now_ms)
|
||||
|
||||
n=1
|
||||
while [ "$n" -le "$COUNT" ]; do
|
||||
block_end=$((n + PARALLEL - 1))
|
||||
if [ "$block_end" -gt "$COUNT" ]; then
|
||||
block_end="$COUNT"
|
||||
fi
|
||||
slot=0
|
||||
k="$n"
|
||||
pay_pids=""
|
||||
while [ "$k" -le "$block_end" ]; do
|
||||
do_one_pay "$k" "$slot" &
|
||||
pay_pids="$pay_pids $!"
|
||||
slot=$((slot+1))
|
||||
k=$((k+1))
|
||||
done
|
||||
set +e
|
||||
for pid in $pay_pids; do
|
||||
wait "$pid"
|
||||
done
|
||||
set -e
|
||||
k="$n"
|
||||
while [ "$k" -le "$block_end" ]; do
|
||||
if [ -f "$SCRATCH/msg.$k.txt" ]; then
|
||||
cat "$SCRATCH/msg.$k.txt"
|
||||
else
|
||||
echo "[$(printf '%03d' "$k")] MISSING (worker died)"
|
||||
fi
|
||||
if [ -f "$SCRATCH/row.$k.tsv" ]; then
|
||||
cat "$SCRATCH/row.$k.tsv" >>"$TSV"
|
||||
else
|
||||
write_row "$k" "" "" "" "" "" "WORKER_DIED" "" >>"$TSV"
|
||||
fi
|
||||
k=$((k+1))
|
||||
done
|
||||
n=$((block_end + 1))
|
||||
if [ "$n" -le "$COUNT" ]; then
|
||||
case "$GAP_S" in
|
||||
0|0.0|0.00) ;;
|
||||
*) sleep "$GAP_S" ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
|
||||
RUN_END_MS=$(now_ms)
|
||||
wall_ms=$((RUN_END_MS-RUN_START_MS))
|
||||
|
||||
ok_n=$(awk -F'\t' 'NR>1 && $7=="PAID" {c++} END {print c+0}' "$TSV")
|
||||
fail_n=$((COUNT - ok_n))
|
||||
|
||||
section "zero-pay · summary"
|
||||
info "ok=$ok_n fail=$fail_n count=$COUNT parallel=$PARALLEL gap_s=$GAP_S wall_ms=$wall_ms out=$TSV"
|
||||
python3 - "$TSV" "$ok_n" "$fail_n" "$COUNT" "$wall_ms" "$OUTDIR/summary.txt" "$GAP_S" "$PARALLEL" <<'PY'
|
||||
import sys
|
||||
tsv, ok, fail, count, wall, outp, gap_s, parallel = sys.argv[1:]
|
||||
ok, fail, count, wall = int(ok), int(fail), int(count), int(wall)
|
||||
rows=[]
|
||||
with open(tsv) as f:
|
||||
next(f)
|
||||
for line in f:
|
||||
p=line.rstrip('\n').split('\t')
|
||||
if len(p)<7: continue
|
||||
rows.append(p)
|
||||
paid=[r for r in rows if r[6]=='PAID']
|
||||
def nums(idx, rs):
|
||||
xs=[int(r[idx]) for r in rs if r[idx].isdigit()]
|
||||
return xs
|
||||
def fmt(xs):
|
||||
if not xs: return "n/a"
|
||||
xs=sorted(xs)
|
||||
med=xs[len(xs)//2]
|
||||
return "n=%d min=%d med=%d max=%d mean=%.1f" % (len(xs), xs[0], med, xs[-1], sum(xs)/len(xs))
|
||||
lines=[]
|
||||
lines.append("ok=%d fail=%d count=%d parallel=%s wall_ms=%d wall_s=%.1f gap_s=%s" % (
|
||||
ok, fail, count, parallel, wall, wall/1000.0, gap_s))
|
||||
lines.append("create_ms " + fmt(nums(2, paid)))
|
||||
lines.append("handle_ms " + fmt(nums(3, paid)))
|
||||
lines.append("settle_ms " + fmt(nums(4, paid)))
|
||||
lines.append("total_ms " + fmt(nums(5, paid)))
|
||||
if paid:
|
||||
lines.append("first_paid_oid=%s last_paid_oid=%s" % (paid[0][1], paid[-1][1]))
|
||||
text="\n".join(lines)+"\n"
|
||||
open(outp,"w").write(text)
|
||||
print(text)
|
||||
PY
|
||||
|
||||
wcli_slot 0 20 balance >"$OUTDIR/balance-after.txt" 2>&1 || true
|
||||
info "balance after: $(tr '\n' ' ' < "$OUTDIR/balance-after.txt" | tail -c 200)"
|
||||
|
||||
if [ "$ok_n" -lt "$COUNT" ]; then
|
||||
fail "zero-pay" "ok=$ok_n fail=$fail_n count=$COUNT out=$TSV"
|
||||
summary
|
||||
exit 1
|
||||
fi
|
||||
ok "zero-pay" "ok=$ok_n count=$COUNT wall_ms=$wall_ms out=$TSV"
|
||||
summary
|
||||
exit 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue