Commit 891da0fb3d9 for woocommerce
commit 891da0fb3d9d3237ea4276cd1a888497f79240b4
Author: Vladimir Reznichenko <kalessil@gmail.com>
Date: Mon Apr 27 09:17:14 2026 +0200
[Performance] BFCM stress-test config finalization (#64412)
diff --git a/plugins/woocommerce/tests/performance/tests/bfcm.js b/plugins/woocommerce/tests/performance/tests/bfcm-infra-hammered.js
similarity index 60%
rename from plugins/woocommerce/tests/performance/tests/bfcm.js
rename to plugins/woocommerce/tests/performance/tests/bfcm-infra-hammered.js
index 3f3729d3b8c..800aaf22e6e 100644
--- a/plugins/woocommerce/tests/performance/tests/bfcm.js
+++ b/plugins/woocommerce/tests/performance/tests/bfcm-infra-hammered.js
@@ -9,24 +9,29 @@ import { checkoutCustomerLogin } from '../requests/shopper/checkout-customer-log
// This test runs at the environment's saturation ceiling — thresholds will fail by design.
// Use the following metrics to detect regressions (numbers go up) or improvements (numbers go down):
//
-// STABLE SIGNALS — not dominated by Apache spike timing; reliable across single runs:
-// - http_req_duration p(50) — baseline 101ms; fast-path latency; reflects requests completing before Apache queues up;
-// regressions surface here first; not materially affected by spike minutes.
-// - Store API checkout med — baseline 1.03s; most sensitive to checkout-path optimizations (DB writes, order creation);
-// p(90)/p(95) are capped at 60s during spike minutes — use median, not tail percentiles.
-// - update-customer med — baseline 66ms; p(90) baseline 2.65s; checkout address persistence path.
-// - Order Received p(90) — baseline 1.19s; downstream of checkout; sensitive to order creation overhead.
-// - order completion rate — baseline 73% ('body contains: order_id' check; 176/239 attempts); proportion of flows
-// that reach order received; more stable than http_req_failed when Apache varies run-to-run.
+// STABLE SIGNALS — low run-to-run variance (validated across 3-run sets); reliable within a single run:
+// - http_req_duration p(50) — baseline ~102ms (±13ms across 3 runs); fast-path latency; reflects requests
+// completing before Apache queues up; regressions surface here first.
+// - update-customer med — baseline ~68ms (±4ms across 3 runs); tightest signal available; checkout
+// address persistence path; not materially affected by spike minutes.
//
-// NOISY SIGNALS — dominated by which minute the Apache spike hits; compare trends across multiple runs, not single pairs:
-// - http_req_failed rate — baseline 4.05%; spikes when Apache worker pool exhausts; volatile run-to-run.
-// - dropped_iterations — baseline 278; K6 drops iterations when VU pool exhausts due to slow Apache; volatile.
-// - iteration_duration avg — baseline 52.26s; pulled up by spike minutes; use as trend indicator, not per-run comparison.
-// - Store API checkout avg — baseline 16.26s; dragged by 60s timeout outliers during spike minutes; median is more reliable.
+// MODERATELY STABLE — lower variance than noisy signals; compare 3+ runs for directional confidence:
+// - order completion rate — baseline ~73% ('body contains: order_id' check); proportion of flows that
+// reach order received; 8% run-to-run variance in baseline set; more stable
+// than http_req_failed but still sensitive to overall load conditions.
//
-// A PR that reduces DB queries or checkout overhead will move stable signals in the right direction even
-// if the test still "fails" thresholds — less failing is a measurable win. Baseline is as of April 2026.
+// NOISY SIGNALS — dominated by which minute the Apache spike hits; never compare single runs:
+// - Store API checkout med — 3x swings within baseline set alone (346ms–1.21s); spike timing determines
+// whether requests queue before/after median; use avg as trend only.
+// - Order Received p(90) — 10x swings (160ms–2.58s); spike-minute timing dominant.
+// - update-customer p(90) — 2–3x swings (2.94s–6.73s); tail dominated by queuing during spike minutes.
+// - http_req_failed rate — baseline 4–9% across runs; spikes when Apache worker pool exhausts; volatile.
+// - dropped_iterations — baseline ~310; K6 drops iterations when VU pool exhausts; volatile.
+// - iteration_duration avg — pulled up by spike minutes; use as trend indicator, not per-run comparison.
+// - Store API checkout avg — dragged by 60s timeout outliers during spike minutes; median no better.
+//
+// A PR that reduces DB queries or checkout overhead will move stable signals in the right direction even if the test
+// still "fails" thresholds — less failing is a measurable win. Baselines validated April 2026 across 3-run sets.
export const options = {
// Saturation profile (M4 Pro, wp-env defaults):
diff --git a/plugins/woocommerce/tests/performance/tests/bfcm-infra-holdingup.js b/plugins/woocommerce/tests/performance/tests/bfcm-infra-holdingup.js
new file mode 100644
index 00000000000..b50ae839db8
--- /dev/null
+++ b/plugins/woocommerce/tests/performance/tests/bfcm-infra-holdingup.js
@@ -0,0 +1,113 @@
+/**
+ * Internal dependencies
+ */
+import { cart } from '../requests/shopper/cart.js';
+import { checkoutGuest } from '../requests/shopper/checkout-guest.js';
+import { checkoutCustomerLogin } from '../requests/shopper/checkout-customer-login.js';
+
+// Sub-saturation checkout DB performance test.
+//
+// Purpose: measure PHP/DB latency on the checkout path (order saves, customer saves, etc.)
+// without Apache worker exhaustion masking the signal. At 0.3 checkout/s Apache workers
+// stay well below the spike zone (~10–20/150), so median and p(90) reflect actual
+// server-side processing time rather than queue wait time.
+//
+// Contrast with bfcm-infra-hammered.js, which runs at the saturation ceiling (0.8/s) where Apache
+// dominates and only p(50) / update-customer median are reliable signals.
+//
+// All signals below are stable at this load level (validated across 3-run sets, April 2026):
+//
+// - p(50) overall — baseline ~77ms (±1ms); reflects fast-path latency; minimal variation.
+// - Store API checkout med — baseline ~472ms (±67ms); most sensitive to order-path optimizations
+// (DB writes, order creation); stable here unlike at saturation.
+// - Store API checkout p(90) — baseline ~2.99s (±1.73s); noisier than median due to occasional
+// outliers (WP-cron, cache misses); directionally reliable across 3+ runs.
+// - update-customer med — baseline ~65ms (±1ms); tightest signal; checkout address persistence path.
+// - update-customer p(90) — baseline ~77ms (±5ms); reliable here (no Apache queuing to inflate tail).
+// - Order Received p(90) — baseline ~121ms (±7ms); downstream of checkout; stable.
+// - order completion rate — baseline 100%; any drop below 100% indicates a correctness regression.
+// - http_req_failed — baseline 0%; meaningful signal here (not spike noise as in hammered.js).
+// - dropped_iterations — baseline ~3; near-zero confirms sub-saturation; spike = VU config issue.
+//
+// Note: Store API checkout p(95) fails the 1000ms threshold in both baseline and less-writes sets
+// (range 2.5–4.8s) due to infrequent outlier requests. This threshold is aspirational; watch the
+// median and p(90) for directional signals, not p(95).
+//
+// Requires a clean Apache baseline — restart the WordPress container between runs:
+// bash plugins/woocommerce/tests/performance/utils/init-environment.sh
+//
+// Comparing runs: a single run is sufficient for directional confidence at this load level.
+// Run 2–3 times if you want variance bounds on noisy signals (checkout p(90)).
+
+export const options = {
+ // Sub-saturation profile (M4 Pro, wp-env defaults):
+ // - Total: 2/10s guest + 1/10s customer = 0.3 checkout/s.
+ // - Apache workers stay at ~10–20/150; no spike zone, no request queuing.
+ // - At this rate all iterations complete; dropped_iterations should be near zero.
+ // - See bfcm-infra-hammered.js for the saturation ceiling profile and its measurement limitations.
+ scenarios: {
+ // Guest checkout: 60% of checkouts.
+ checkout_guest: {
+ executor: 'ramping-arrival-rate',
+ exec: 'checkoutGuestFlow',
+ startRate: 1,
+ timeUnit: '10s',
+ preAllocatedVUs: 3,
+ maxVUs: 6,
+ stages: [
+ { duration: '4m', target: 2 }, // Ramp to peak.
+ { duration: '8m', target: 2 }, // Sustain peak.
+ { duration: '2m', target: 0 }, // Ramp down.
+ ],
+ },
+ // Authenticated checkout: 40% of checkouts.
+ checkout_customer: {
+ executor: 'ramping-arrival-rate',
+ exec: 'checkoutCustomerLoginFlow',
+ startRate: 1,
+ timeUnit: '10s',
+ preAllocatedVUs: 2,
+ maxVUs: 4,
+ stages: [
+ { duration: '4m', target: 1 }, // Ramp to peak.
+ { duration: '8m', target: 1 }, // Sustain peak.
+ { duration: '2m', target: 0 }, // Ramp down.
+ ],
+ },
+ },
+ thresholds: {
+ // Aggregate thresholds across all requests.
+ http_req_duration: [ 'p(50)<200', 'p(90)<500', 'p(95)<1000' ],
+ http_req_failed: [ 'rate<0.01' ],
+
+ // Per-request thresholds: cart workflow.
+ 'http_req_duration{name:Shopper - wc-ajax=add_to_cart}': [
+ 'p(95)<500',
+ ],
+ 'http_req_duration{name:Shopper - wc-ajax=get_refreshed_fragments}': [
+ 'p(95)<200',
+ ],
+ 'http_req_duration{name:Shopper - View Cart}': [ 'p(95)<500' ],
+
+ // Per-request thresholds: checkout workflow.
+ 'http_req_duration{name:Shopper - View Checkout}': [ 'p(95)<500' ],
+ 'http_req_duration{name:Shopper - Login to Checkout}': [ 'p(95)<500' ],
+ 'http_req_duration{name:Shopper - Store API update-customer}': [
+ 'p(95)<200',
+ ],
+ 'http_req_duration{name:Shopper - Store API checkout}': [
+ 'p(95)<1000',
+ ],
+ 'http_req_duration{name:Shopper - Order Received}': [ 'p(95)<500' ],
+ },
+};
+
+export function checkoutGuestFlow() {
+ cart();
+ checkoutGuest();
+}
+
+export function checkoutCustomerLoginFlow() {
+ cart();
+ checkoutCustomerLogin();
+}