perf(tests): the sample projects publish once per family, not once per sample - #6722
Merged
Conversation
…r sample The 14 sample-project ITs were the same journey 14 times - clone a dirigiblelabs/* repo through the Git perspective, publishAll, verify - each paying its own Dirigible boot, Chrome session and publish cycle (1088s on the h2 leg, the biggest remaining block in the samples shard). SampleProjectsIT now clones a FAMILY of repos into one workspace, publishes once, and lets each subclass verify one sample per @test under AFTER_CLASS: TypeScriptSampleProjectsIT (8 samples) and JavaSampleProjectsIT (5 samples) replace 13 classes, so 13 boots become 2. SampleLibraryLocalNativeAppIT moves onto the new base but keeps its own instance - it spawns a real OS process. Every assertion is carried over unchanged. Two families rather than one class because sample-entity-decorators and sample-java-entity-decorators both own the SAMPLE_COUNTRY table and both CSVIM-seed it; the split keeps them in separate instances and needs no change to any sample repo. The preflight for the Java family came back clean - all 17 client classes sit in distinct demo.* packages with distinct simple names, so the shared javac batch and bean container have nothing to collide on. The one-time publish is a guarded @beforeeach, not a @BeforeAll on a @testinstance(PER_CLASS) class: PER_CLASS autowires the instance - booting the platform - before @BeforeAll runs, so IntegrationTest's cleaner then deleted the Dirigible folder under the running instance and the next sync pass reaped the platform's own registry (Definition deleted: /shell-ide/extensions/shell.extension), leaving the IDE with no perspectives. The guard is keyed by class, not a boolean: the field is shared by every subclass, and a flag would let the second family skip its own publish. Part of #6710.
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.
Item 1 of #6710: the sample-project ITs were the same journey 14 times - clone a
dirigiblelabs/*repo through the Git perspective,publishAll, verify - each paying its own Dirigible boot, Chrome session and publish cycle (1088s on the h2 leg of run 31679871168, the biggest remaining block in thesamplesshard).They now clone a family of repos into one workspace, publish once, and verify one sample per
@Testmethod: 13 boots become 2.SampleProjectsIT(replacesSampleProjectRepositoryIT) clones a list of repos, publishes once, force-syncs and waits for a stable synchronization - all in one@BeforeAllunder@TestInstance(PER_CLASS)(so the hook can use the injectedIDE) and@DirtiesContext(AFTER_CLASS)(so the family shares the boot).TypeScriptSampleProjectsIT- the 8 TS/JS decorator samples, 8 tests.JavaSampleProjectsIT- the 5 client-Java samples, 5 tests.SampleLibraryLocalNativeAppITmoves onto the new base but keeps its own instance: it spawns a real OS process (npm installon first run) and grants a role on the fly.Every assertion is carried over unchanged.
Why two families and not one class
The preflight #6710 asked for (no duplicate FQNs across the
sample-java-*repos, since the family shares onejavacbatch and oneClientClassLoader) came back clean - all 17 client classes sit in distinctdemo.*packages with distinct simple names, so no bean-name collision either.It surfaced a different collision the issue had not anticipated:
sample-entity-decoratorsandsample-java-entity-decoratorsboth own theSAMPLE_COUNTRYtable (identical.table,UNIQUEon three columns) and both CSVIM-seed it from their owncountries.csv. Publishing them side by side means two.tableartefacts claiming one name and two importers seeding it. Splitting along the TS/Java line - the alternative the issue offers - keeps them in separate instances and needs no change to any sample repo.Checked for the rest of the collision surface too: within each family the table names, listener destinations (
sample-listener-decorator/OrderListenervsjava-invoice-queue), websocket endpoints (order-wsvsjava-chat/java-ticker) and job crons are all distinct, andCountryController.tsis the only@Controllerin the TS family - which is why the exact-match OpenAPI assertion survives seven more samples sharing the instance.Verification
Both consolidated classes green locally, headless:
That is 13 sample verifications in ~200s of test time on 2 boots, against 1088s for the 14 per-sample classes on the h2 leg of run 31679871168. Two failures on the way here, both fixed and both worth knowing about:
@TestInstance(PER_CLASS)is incompatible with this test framework. The obvious shape for "clone and publish once" is a non-static@BeforeAll, which needs PER_CLASS to reach the injectedIDE. But PER_CLASS creates and autowires the test instance BEFORE@BeforeAllruns, so the Spring context - the whole platform - starts beforeIntegrationTest.cleanBeforeTestClassExecution()deletes the Dirigible folder. The next synchronization pass then reaps the platform's own registry:perspective-gitnot found against a blank page, nowhere near its cause. The publish is now a@BeforeEachguarded by a static, which keeps the cleaner ahead of the boot.websocketDecoratorgets a fresh Chrome whenever it is not the first method to run, and the sample's page served the login form instead. It now opens the home page first. Order-independence is a requirement of this design, not a detail - the base javadoc says so.Notes for the reader
LogsAsserters are created inside each test (an asserter only sees messages logged after it attaches) and every awaited message comes from a recurring cron or from a trigger the test itself fires.SampleLibraryLocalNativeAppIT's@BeforeAllthat raises the native-app ready timeout now runs after the base's clone-and-publish. That is soon enough: the artefact declares"mode": "lazy"and only aStartMode.ALWAYSapp is spawned by the bootstrap, the monitor job or the synchronizer - this one waits for the first proxied request, which the test method makes.@Tag("sample")stays on the base, so thesamplesCI shard selector (sample | camel) is unchanged.CLAUDE.mdnow documents the family model, the collision rule and the order-independence requirement; stale class names swept fromCLAUDE_FEATURES.md,engine-intent/engine-java/engine-native-appsCLAUDE.mdand two javadocs.Remaining #6710 items (camel ITs to HTTP-level, shard rebalance, PG-leg scope) are untouched.