Repository navigation
Clone integration test databases from a migrated template and run them in parallel - #44
Merged
Merged
Conversation
added 5 commits
October 13, 2026 12:24
Tests that need the current schema now clone a template database migrated once per migration set instead of running every migration per test. Tests about migrations keep migrating an empty database. Databases and login roles a test creates are dropped when it ends unless WEAVE_TEST_KEEP_DATABASES=1 or WEAVE_TEST_RESOURCE_MANIFEST asks to keep them. Add pytest-xdist for parallel runs and document the fast path.
Importing retain_resource from conftest resolved to whichever conftest pytest imported last, so a bare pytest run picked the live AI conftest and the four tests that create their own roles failed with ImportError.
One failing DROP used to skip the remaining drops for that test. Each drop now runs on its own, and the teardown warning names every database and role left behind.
A template build dropped every other weave_b1_template_* database, so two checkouts with different schemas on one server broke each other's clones. A process now records in the template's comment when it last used it, and a build drops only templates nobody is connected to and nobody has used for 6 hours. The template name also hashes the module that defines migrate() and the Alembic version, so a change there that alters the schema builds a new template.
…ettings are optional The first test of a run builds the template only when it is missing, and turning off durability made no measurable difference. Also document which templates a build drops.
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes
The PostgreSQL integration suite spent most of its time preparing databases, not testing. Every test created a
database, ran all 30 migrations on it, created its login roles, and kept them all on the server. This change
keeps the same per-test isolation and removes that cost:
migration_settings, and everything built on it:settings,access_db,authenticated_client, …) cloneweave_b1_template_<hash>withCREATE DATABASE … TEMPLATE …(about 45 ms). The template is migrated once by the realmigrate(), whichalso runs
check_schema. Its name is a hash of the migration files, the schema version, the defaultoperations policy the migrations record, the module that defines
migrate()and the Alembic version, sochanging any of them builds a new template. A session advisory lock lets one worker build it while the
others wait. It is marked
IS_TEMPLATE true ALLOW_CONNECTIONS falseonly after a complete migration, so afailed build is never cloned.
A migration failure while building it is reported as itself, not as an unavailable backend.
then at most every 10 minutes). A build drops another
weave_b1_template_*only when nobody is connected toit and nobody has used it for 6 hours, so checkouts with different migrations can share one server.
Templates without that comment, built before this change, count as unused.
DROP DATABASE … WITH (FORCE)first, so no role keeps a privilege, thenDROP ROLE).WEAVE_TEST_KEEP_DATABASES=1keeps them.When
WEAVE_TEST_RESOURCE_MANIFESTis set, each resource is recorded exactly as before and kept, so themanifest still lists resources that exist. Every drop is attempted even when one fails, and one warning
names all the databases and roles left behind. The roles that three tests create themselves are now
recorded too (
test_incident_migration,test_schedule_migration, and the external database ofconnectors/test_postgresql). Tests record what they create through aretainfixture instead offrom conftest import retain_resource, which resolved to the live AI conftest under a barepytest. Thetemplate stays on the server between runs; it holds no test data.
pytest-xdistjoins thedevgroup (the worker lockfiles record the root project's groups,so they change by one line each). Fixtures were already worker-safe (uuid4 names, one
database per test); the template build is the only shared step and it is locked.
drops, the environment variables and the parallel command, and says the durability settings are optional
because they made no measurable difference.
scripts/check.pystill runs the integration stage serially; it gets the template and cleanup speed-upwithout any change to the gate.
How migrations stay covered
empty_settingsis unchanged(
test_bootschema rejection,test_accessaudit forward migration,test_emailmigration RLS,test_incident_migration,test_schedule_migration).test_explicit_migration_is_idempotentnow uses a newfresh_migration_settingsfixture, which runsmigrate()on an empty database inside the test before running it a second time, as it did before.migrate()with its schema check, once per migration set.Timings
Measured on the
colima-weave-testsVM (4 CPUs, 8 GiB, PostgreSQL 17) with only PostgreSQL configured.Another project's PostgreSQL shared the VM and used up to one full CPU during several runs, so single runs
vary by about 20%.
Subset of 106 tests (
test_access,test_boot,test_human_files,test_human_tasks,test_leases,test_runs):main, serial-n 4-n 8Whole suite (676 tests collected):
main, serial-n 2 --dist loadfile-n 4 --dist loadfile-n 4 --dist load-n 8 --dist loadfileOn
mainthe serial run never finished cleanly here: after about 560 retained databases (15 GB of data, 50kfiles per checkpoint) the server crashed with a segmentation fault during a test's migration and the next 57
tests failed with "the database system is in recovery mode". Those 9 test files were rerun on a fresh server
(463 s) to complete the baseline.
Turning off
fsync,synchronous_commitandfull_page_writesmade no measurable difference once databasesare cloned and dropped (
-n 4 --dist loadfile: 355 s on a default server, 383 s on a tuned one).Verification
mainbaseline: 614 passed, 4 failed, 57 errors, 1 skipped on both. The 57errors and 2 of the failures need backends this run did not configure (Kafka, Keycloak, built images, the
release receipt).
test_concurrent_publication_and_lost_responsefails onmainand on this branch alike.test_resolution_receipt_revision_and_auditfailed,
test_two_replicas_join_oncepassed). Both are concurrent mutations of one project that expect thefirst transaction to finish inside the 250 ms
lock_timeoutof the project admission lock; a slower holdergives the other request
429 WV-OPERATION-CAPACITY. Run alone, both fail now and then onmaintoo(
test_business_failure_and_sibling_complete_concurrently[failure]: 1 of 5 on each).-n 4, two to three tests of that same group fail per run(
test_business_failure_and_sibling_complete_concurrently[failure],test_resolution_receipt_revision_and_audit,test_timeout_races_signal_once,test_timely_signal_survives_sibling_suspension_until_recovery_or_overall_timeout[mixed_signal_overall]):more CPU contention makes the 250 ms window easier to miss. No failure comes from shared database state.
This is why the gate stays serial.
test_due_expiry_wins_concurrent_completion(429 instead of 409 whentest_human_tasks.pyruns beforetest_human_files.py) passed 3 of 3 runs in that order on this branch and 2 of 2 onmain; it belongs to thesame timing group and did not fail in any parallel run.
WEAVE_TEST_KEEP_DATABASES=1andWEAVE_TEST_RESOURCE_MANIFESTwere checked to keep databases and roles, andthe manifest records the roles of the migration tests.
make check(all stages),ruff check,ruff format --checkandmypypass. Final whole-suite run with-n 4 --dist loadfile: 612 passed, 6 failed, 57 errors, 1 skipped in 426 s; the two extra failures arethe timing tests named above.
test_template_cleanup,test_resource_cleanup,test_boot,test_incident_migration,test_schedule_migration,test_email,test_access,providers/test_teams, and thetest_operationstest that creates its own login): 61 passedin 78 s. Then, with a marked template without a use comment and a recently used one seeded and the current
template dropped,
-n 4 --dist loadfileovertest_template_cleanup,test_resource_cleanup,test_boot,test_access,test_runs,test_leases,test_human_tasks,test_incident_migration,test_schedule_migration,test_operationsandtest_email: 124 passed in 74 s. The DDL log showed onetemplate build, the unmarked template dropped and the recently used one kept; no test database or role
was left.
pytest --collect-only tests/integrationcollects 679 tests;pytest --collect-only testsreports no ImportError (its 8 "import file mismatch" errors come from test files sharing a basename and
happen on
maintoo).make check,ruff check,ruff format --checkandmypypass.connectors/test_postgresql.pyfixture, which needs a release receipt for its port.