Run more of the test suite in parallel #610
Labels
No labels
bug
duplicate
enhancement
help wanted
high priority
invalid
L
low priority
M
medium priority
needs refinement
optional
question
S
security
technical improvement
UX Improvement
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
local-it/mitgliederverwaltung#610
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Motivation
Every pipeline gate and every local
just ci-devruns the fast suite. On the 4-vCPU dev VM one runtakes about 4–5 minutes, and most of that time is serial. Two full runs on the #605 branch (2556 tests):
242.7 s total (37.5 s async, 205.2 s sync) and 246.5 s (36.2 s async, 210.2 s sync). Five runs in #598
measured 292–326 s, of which 249–274 s were sync. Under load (3 parallel pipeline issues) a run took
472 s (389 s sync). A pipeline run pays this many times: every
/tddsession end, every reviewiteration, and
/finalizebefore and after the rewrite.#533 removed the main reason many files were serial (FK deadlocks in concurrent
create_member,fixed with deferrable FKs), but the files were kept serial as a deferred decision.
Current state (main after #605)
async: false: 78 undertest/mv/**, 87 undertest/mv_web/**(51 of them in
test/mv_web/live/member_live/).test/mv_web/live/member_live/(index_custom_fields_display,index_field_visibility,index_groups_{accessibility,display,filter,integration,performance,sorting},show_groups_display), plustest/mv_web/live/user_live/form_test.exs.Logger.configure,Application.put_env,System.put_env). These must stay serial unless the state is isolated pertest.
member_live/index_test.exs(75),member_overview/date_filter_test.exs(49),member_overview/payment_aging_test.exs(36),membership/member_policies_test.exs(31),global_settings_live_test.exs(25).System.schedulers_online() * 8(config/test.exs:15); ExUnit runs with the defaultmax_cases(2 × schedulers,test/test_helper.exs).Known flake classes that more parallelism makes worse
Evidence log:
.pipeline/followups/flaky-tests.md(Gitea #598). Two classes are still open and bothoccur in tests that already run async, so flipping more files raises their rate:
suite run, never isolated:
member_export_controller_golden_test.exssetup (CustomField.create), twice (#600, #605)group_test.exs"delete group cascades …" (create_member), #605Process A waits for ShareLock on transaction X; blocked by process Band vice versa. A ShareLock on a transaction is a wait for another uncommitted insert: a
unique-index check (or an FK check) on a row the other test inserted in its sandbox
transaction. Sandbox transactions never commit, so the waiting test blocks until the other test
ends. If two tests insert two such rows in opposite order, Postgres detects the deadlock.
CustomFieldunique_name/
unique_slug,Groupunique_slug,Memberunique_email. The golden test creates groups"Board" / "Choir", fixed custom-field names and
anna@example.com.name: "Board"also appearsin 6 member_live test files, and
anna@example.comin 6 other test files.(
docker logs mv-<issue>-db-1) has the query details the error hint points to. Or reproduce itwith two async tests that insert the same two unique values in opposite order.
and inline
create_*calls (e.g."Board-#{System.unique_integer([:positive])}"). Golden testswhose expected output contains the fixed value either derive the value or stay serial (with a
one-line reason).
refute html =~ nameon the full rendered page). These matchrandom CSRF/session tokens, or rows that other async tests create. Seen in
index_groups_url_params_test.exsandimport_live_test.exs(the token contained "BOM"). Thetest-hardening issue fixes this class suite-wide. A file flipped here must not contain it: scope
the assertion to the element (
has_element?,assert_flash/3,assert_field_error/3) in thesame commit.
Resolved classes that stay rules for every flipped file: no
capture_logassertions in async files,because other processes' log lines get captured (#598, Class 2). No order assertions on reads
without an explicit sort (#598, Class 1).
Approach
per test in the files that already run async. Done when 5 seeded full-suite runs, one under CPU
load, show no 40P01. Every later flip depends on it.
just test-fast --slowest-modules 25(3 runs, different seeds) and record theper-module time of the serial files. Choose candidates by time saved, not by count. If the
measured gain for
test/mv/**is small, stop after this step and record the numbers in theissue.
test/mv/**in that order, one file per commit. For each file, prove isolation per theasync-safety checklist in
docs/test-performance-optimization.md: green with several seeds andunder CPU load, not one green run. Fix data assumptions that break under concurrency (global
counts, "no other members exist", ordered reads without a sort, fixed unique values).
into a small serial module and make the rest async. Isolate state per test where that is cheap
(e.g. pass settings explicitly instead of mutating the singleton).
use … async: false, sothe next reader does not have to rediscover it.
CODE_GUIDELINES.md§4 (next to the async/sandbox section): uniquevalues for unique identities in tests, the reason comment on every
async: false, and nocapture_login async files.Coordination with other issues
issue-test-hardening-and-guidelines.md): it touches the sametest/mv/**files (policies, fee and custom-field domain). Run the two one after the other, not inparallel. This issue goes first, so the hardening runs on the faster suite.
test/mv/**first. The 51 serial files intest/mv_web/live/member_live/change with #602(buttons/theme), U7 (search), U10 (list toolbars) and #549 (saved views). Flip them after those
issues, or as part of them; this issue does not touch
test/mv_web/live/**.global_settings_live.ex): make the settings state isolatable per section there, soits tests can run async.
Acceptance criteria
.pipeline/followups/flaky-tests.md,and fixed. Five seeded full-suite runs, one under CPU load, show no deadlock.
each, same host, seeds recorded.
listed in the evidence log, following the
.pipeline/followups/flaky-tests.mdpattern.async: falsefile has a one-line reason.capture_logassertions, and no fixedvalues under a unique identity.
CODE_GUIDELINES.md§4 has the rules from step 6.just ci-devandjust typecheckare green.Risks
docs/test-performance-optimization.md, plus seeded runs under load.deleting. The container log decides; do not flip files before step 1 is green.
the serial time becomes parallel. Step 2 decides whether the work is worth it.
Out of scope
MIX_TEST_PARTITIONacross machines); it does not help on a single VM.test/mv_web/live/**(see Coordination).