Replaced mollie
All checks were successful
Deploy / build-deploy (push) Successful in 3m47s

This commit is contained in:
Jorijn van der Graaf 2026-08-20 20:15:47 +02:00
commit df91762271
29 changed files with 3079 additions and 838 deletions

View file

@ -127,7 +127,7 @@ void OpenShopLifecycle(TestServer& srv) {
// picked one must survive all the way into the ledger. The ledger is the
// assertion that matters: it is what the reconciler later reads to decide
// WHICH provider may confirm the order, so a choice that renders but is
// not stored would mean crypto orders being asked about at Mollie.
// not stored would mean crypto orders being asked about at the bank.
srv.BodyHas("/shop/fp6-pmos", "name=\"pay\"", "the form offers a payment choice");
srv.BodyHas("/shop/fp6-pmos", "value=\"crypto\"", "crypto is one of the choices");
srv.BodyHas("/shop/fp6-pmos", "value=\"bank\" checked", "bank is the pre-selected choice");
@ -815,6 +815,39 @@ void RejectedFormEcho(TestServer& srv) {
}
}
// ── one rail down ─────────────────────────────────────────────────────
//
// The regression guard for a real outage: on 2026-08-20 the bank provider
// closed the shop's account, the operator correctly dropped the credential,
// and the form went on rendering a PRE-SELECTED "Bank or card" option that
// checkout could then only answer with a 503 — the majority of buyers walking
// into a wall. The crypto slot had always been rendered conditionally; the
// bank slot never was, because until that day it had never been absent.
//
// Its own server, because a rail roster is fixed at startup. Donations are
// what this asserts against: they are open in BOTH shop states, so this runs
// whatever fp6-pmos's status is.
void OneRailDown(const char* binary) {
ServerOptions options;
options.extraArgs = { "--rail=off", "--crypto-rail=fake-crypto" };
TestServer srv(binary, 8221, options);
srv.BodyHas("/shop/donation", "name=\"pay\"",
"with one rail down the form still names the choice it has");
srv.BodyHas("/shop/donation", "value=\"crypto\" checked",
"the surviving rail is pre-selected, so a plain submit is payable");
srv.BodyLacks("/shop/donation", "value=\"bank\"",
"the dead rail is not offered at all");
// The proof that the rendering and the handler agree: submitting the form
// exactly as rendered — no pay field touched — must create an order rather
// than be refused. An absent `pay` resolves to the BANK rail by design, so
// this is what would fail if the fieldset ever stopped pre-selecting.
const auto created = srv.Post("/shop/donation", "amount=5&pay=crypto");
Check(created.status == "303",
"a donation on the surviving rail goes through");
}
} // namespace
int main(int argc, char** argv) {
@ -838,5 +871,7 @@ int main(int argc, char** argv) {
RejectedFormEcho(srv);
}
OneRailDown(argv[1]);
return Finish();
}