Run the dormant JUnit 4 tests and let test failures fail CI - #85
Conversation
Add junit-vintage-engine so the JUnit Platform provider picks up the nine JUnit 4 test classes, and drop maven.test.failure.ignore from the ci-test profile so a failing test fails the Build workflow. Replace the wall-clock assertion in TopRecordsAlgorithmTest with a deterministic comparator-invocation count, which the now-fatal failures require. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The complexity test no longer measures wall-clock time, and the class has grown well past the 15 test methods the document claimed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Self-review rubricScored adversarially against the diff and command output on head Universal items
Repo-specific items
FindingsThree observations are recorded here rather than as inline comments, since they concern lines outside this PR's diff hunks.
Documentation accuracy check (Phase 7)The first pass found that Merge recommendation
This review was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener). |
Summary
Three coupled test-infrastructure defects are fixed together, because fixing any one alone would leave the suite in a worse state than it is now.
junit-vintage-engineis added as a test-scoped dependency. Nine of the twelve test classes are written against JUnit 4, butjunit-jupiter-engineon the classpath causes Surefire to select the JUnit Platform provider, which only discovers JUnit 4 tests when the vintage engine is present. The suite goes from 47 tests to 125; no production code change was required for the 78 newly-executed tests to pass.maven.test.failure.ignoreis removed from theci-testprofile. GitHub Actions setsCI=true, so that profile activates on everymvn --batch-mode clean verifyrun inbuild.yml, and a failing unit test was reported but did not fail the job. The profile's optional-dependency overrides are left untouched, so its stated purpose is preserved. The opt-inoffline-testprofile is deliberately left as is.TopRecordsAlgorithmTestis made deterministic. Wall-clock ratios were being asserted, which measure JIT warm-up and GC rather than algorithmic complexity; the test was observed failing onmainat the start of this session. Comparator invocations are now counted instead, via aCountingScorablewhosegetScore()increments a shared counter. This mattered for ordering: enabling fatal test failures while a flaky assertion remained would have made CI unreliable rather than trustworthy.Ordering note: the flake fix is a prerequisite for the CI change, and the CI change is what gives the newly-enabled tests any value — hence one PR rather than three.
Verification
Both directions were confirmed empirically rather than by reasoning.
Flake fix (#81) — the assertion catches a quadratic implementation.
Collections.sortwas temporarily replaced with a selection sort:Measured comparison counts for the real implementation are
533 / 3841 / 8699 / 19386at n =100 / 500 / 1000 / 2000— roughly 85% ofn·log2(n). The absolute bound was therefore widened to2·n·log2(n)so that a future JDK sort implementation cannot cause a false failure, while a quadratic implementation (4950 at n=100 against a bound of 1329) is still caught decisively. A growth-ratio assertion is retained as a second, tighter check.Vintage engine (#80) and fatal failures (#84). A temporary failing assertion was added to
LeaderboardEntryTest(a JUnit 4 class) andCI=true mvn -B testwas run against both states:pom.xmlstashed)Tests run: 47, Failures: 0— BUILD SUCCESS; the sentinel never executedTests run: 126, Failures: 1— BUILD FAILURE onSENTINEL-JUNIT4-EXECUTEDThe sentinel was reverted;
CI=true mvn -B -o clean teston the committed tree reportsTests run: 125, Failures: 0, Errors: 0, Skipped: 0.help:active-profileswas re-run underCI=trueto confirm theci-testprofile still activates after the edit.Test plan
mvn -B -o clean test— 125 tests, greenCI=true mvn -B -o clean test— 125 tests, green (the profile that previously masked failures is now active and fatal)testGetTopRecords_ComplexityValidationfail; reverting restores greenSimple CIremains meaningful:TopRecordsAlgorithm.javaitself is unmodified, so that workflow's standalone assertions still exercise the same code pathNotes for the reviewer
pom.xmlis on this loop's do-not-auto-merge list, since dependency changes affect the shaded release artifact. The added dependency is test-scoped, so no change to the shipped JAR is expected, but the merge is left to a human.duration < 100for 1000 records,duration < 500for 5000). Their margins are roughly two orders of magnitude, so they were left alone rather than expanding this PR's scope; they are worth revisiting if they ever flake now that failures are fatal.pom.xmlcontains pre-existing duplicate declarations (gson,slf4j-simple,junit,mockito-coreeach declared twice, andmockito.versiondefined twice). These were left untouched to keep the diff scoped; a follow-up issue has been filed.Deferred this cycle
Every other open issue is deferred, with reasons: #82 (CONTRIBUTING.md points at a non-existent
developbranch) is unrelated to test infrastructure and is left for a docs-scoped cycle; #47/#77 (Discord webhooks) is an in-flight draft PR being iterated between the repository owner and another agent, so it was not adopted or closed; #54, #45, #43, #41, #40, #39 are feature work exceeding a polish-sized PR; #13 is a question, not a work item.Closes #80
Closes #81
Closes #84
This PR description was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).