3 Commits
Author SHA1 Message Date
Juan DenisandClaude Opus 5 3c24037b64 test(subprocess): one stub kit for subprocess seams
Plan 75 §G7. The suite's hand-rolled stubs were entrenching the very
duplication the plan removes: _FakeProc pasted byte-identical in four
modules, ~25 fake_run closures re-implementing argv dispatch, and zero
tests patching the wrappers — every stub targeted raw subprocess inside
one service module, so each new service test recreated the raw seam.

tests/subprocess_stub.py is that seam. Tests script argv → result; when
G1 moves services onto run_checked() the retarget happens here once
instead of in twelve files.

Two properties are deliberate:

- An unscripted command raises instead of inventing returncode=0. It is a
  BaseException for the same reason SbinPathError is — services wrap
  subprocess in `except Exception`, so an AssertionError would be eaten
  by exactly the handlers the kit exists to test.
- Stubbed execs are still sbin-guarded. Patching subprocess removes the
  §B2 runtime guard, so the kit re-applies it; popen_guard grows a public
  guard_argv() as the one door for that check.

Matching normalises away a sudo prefix and argv[0] absolutisation, so one
scripted rule matches on a root box, a sudo box and a dev box alike.

Mutation-checked: removing the guard call fails the guard test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 11:24:20 -04:00
Juan DenisandClaude Opus 5 9d570834aa perf(tests): build the Flask app once per session, not once per test
The `app` fixture called create_app('testing') for every one of 3173 tests,
registering 90+ blueprints each time. Measured on a fixed 199-test sample
(pytest --splits 16 --group 5 --durations=0):

    setup     144.9s   89.5%
    call        8.8s    5.4%
    teardown    8.2s    5.0%

95% of the suite's time was preparing to test; 5% was testing. The app is now
built once per process and shared.

Same 794-test slice, before and after — identical results, 2.66x faster:

    before   4 failed, 773 passed, 17 skipped   593.30s
    after    4 failed, 773 passed, 17 skipped   223.11s

(the 4 are pre-existing locally: serverkit-wordpress isn't checked out here.)

Sharing one app surfaces three things a per-test app hid, all handled in the
fixture rather than patched test by test:

1. create_app() is not a pure constructor — it SEEDS the bundled flagship
   extension rows as a boot side effect (test_cloudflare_extraction asserts
   they are "seeded on boot"). The per-test drop_all wipes them, and a shared
   app never re-boots, so every test after the first saw no flagship and the
   extension routes answered 503. seed_flagship_extensions() is now re-run
   after each create_all. The session fixture also boots twice on purpose:
   once to create the schema, once to seed into a schema that exists.

2. Config mutation now leaks where it used to die with the app (e.g.
   test_demo_deploys sets DEMO_DEPLOYS_ENABLED=False and never restores it),
   so config is snapshotted and restored around every test.

3. Structure mutation cannot be undone at all — Flask has no
   unregister_blueprint, and refuses setup methods once an app has served a
   request. Those tests opt out via `pytestmark = pytest.mark.fresh_app` and
   get a private app. Three groups needed it: 13 modules calling
   register_blueprint/add_url_rule directly, 11 that install plugins (
   plugin_service hot-loads their blueprints onto the live app), and
   test_audit_log which adds routes with @app.route.

Tests using the `wp_extension` fixture are detected from the fixture graph
instead of being marked, since that fixture mounts blueprints on whatever app
it is handed — miss one marker and the failure lands in an unrelated test much
later in the run.

Plan 64 Phase 1. Phase 2 (savepoint rollback instead of create_all/drop_all)
is NOT included: it currently takes the slice from 4 failures to 100 failures
and 201 errors, and needs its own round.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 02:59:14 -04:00
Juan DenisandClaude Fable 5 e7e2de486f feat(monitoring): on-demand server speed test card
Job-backed speed test (Ookla/speedtest-cli when present, pure-Python
fallback) with download/upload/latency surfaced on the Monitoring
overview; last result persisted in settings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 14:23:29 -04:00