Skip to content

build: per-module test execution via tycho-build extension (PoC)#1346

Draft
joaodinissf wants to merge 5 commits into
dsldevkit:masterfrom
joaodinissf:experiment/tycho-build-per-module-tests
Draft

build: per-module test execution via tycho-build extension (PoC)#1346
joaodinissf wants to merge 5 commits into
dsldevkit:masterfrom
joaodinissf:experiment/tycho-build-per-module-tests

Conversation

@joaodinissf
Copy link
Copy Markdown
Collaborator

@joaodinissf joaodinissf commented May 16, 2026

Note

Stacked on #1283. The bottom commit is #1283 (build: enable UI tests on macOS via Tycho profile + JRE docs). This PR contains 3 additional commits on top. CI failures here until #1283 lands are expected; rebase onto master once #1283 merges.

Summary

Proof of concept demonstrating that per-module Maven test execution is viable for this codebase via two changes:

  1. Register tycho-build as a Maven core extension so -am walks OSGi Require-Bundle / Import-Package dependencies (Maven natively only walks <dependency> blocks, which are empty for Tycho bundles).
  2. Add an opt-in property gate (ddk.skipPerModuleTests, default true) for per-module surefire blocks, so that opting modules in does not double-execute tests already discovered by the aggregator in com.avaloq.tools.ddk.xtext.test.

The PoC pilots the pattern on com.avaloq.tools.ddk.xtext.export.test (smallest blast radius). After this lands, the same shape can be applied to other *.test modules on demand.

Commits

  1. build: add tycho-build extension.mvn/extensions.xml + .mvn/maven.config. Version sourced from ${tycho.version} to keep a single source of truth.
  2. build: add ddk.skipPerModuleTests property — declares the property in ddk-parent. No behaviour change yet.
  3. build: opt xtext.export.test into per-module test execution — adds full tycho-surefire-plugin + target-platform-configuration to the bundle, gated by the property. <testClass> points at ExportTestSuite. Mirrors xtext.test's surefire block, with one extra argLine flag (-Dorg.osgi.framework.system.packages.extra=jdk.incubator.vector) needed on macOS for org.eclipse.help.base to resolve.

Verification (run on this branch, JDK 21, macOS aarch64)

# Scenario Command Result
B Cold sanity (tycho-build extension) find . -name target -type d -exec rm -rf {} + ; mvn -pl :check.core -am -DskipTests clean verify ✅ Reactor expanded from 1 project (without extension) to 12 projects (with extension), BUILD SUCCESS cold
C Focused dev — standalone tests with override mvn verify -pl :xtext.export.test -am -Dddk.skipPerModuleTests=false ✅ Reactor 17 projects; Tests run: 14, Failures: 0; 21.2s wall clock
D Default behaviour — gate skips standalone mvn verify -pl :xtext.export.test -am (default property=true) [INFO] Skipping tests logged; export.test packaged in 1.0s (vs 7.0s when tests ran)
E Full-reactor double-execution proof mvn verify -Dddk.skipPerModuleTests=false (full 60-project reactor) 371 tests run (357 aggregator + 14 standalone), two distinct surefire summaries, exit code 0, 1m30s total wall clock

Empirical findings worth highlighting

  • Wall-clock is fast. Full reactor with property flipped (every dependency built + aggregator + standalone) completes in 1m30s on an M-series Mac. The aggregator alone consumes 1m05s of that. The 30-minute timeout in AGENTS.md reflects pessimism, not measured behaviour.
  • Double-execution is exactly as predicted. Two surefire summaries land in the log: Tests run: 14 (standalone) and Tests run: 357 (aggregator). 357 matches the baseline test count on master (CI run on d6897f240). The 14 extra are the export tests running a second time as standalone — confirming the gate's intent.
  • Cost of opt-in (when enabled): an extra ~7 seconds of test execution + Eclipse runtime startup for export.test. Trivial. Most of the standalone runtime cost is amortized into reactor build steps that happen anyway.
  • The PoC is gated on build: enable UI tests on macOS via Tycho profile + JRE docs #1283. Without build: enable UI tests on macOS via Tycho profile + JRE docs #1283's macosx Maven profile, the standalone test runtime fetches SWT-win32 (target environments default to win32/win32/x86_64), which can't load on macOS → ClassNotFoundException: org.eclipse.swt.SWTError. With build: enable UI tests on macOS via Tycho profile + JRE docs #1283's macosx profile (sets osgi.os=macosx, osgi.ws=cocoa, osgi.arch=aarch64 and appends -XstartOnFirstThread), the issue resolves cleanly. Documented as the stack dependency above.
  • The Lucene/jdk.incubator.vector cascade affects Maven surefire too, not just .launch files. Same root cause as the existing open work; same fix (-Dorg.osgi.framework.system.packages.extra=jdk.incubator.vector). The aggregator likely has the same latent issue on macOS but no one runs it via plain mvn verify on Mac normally — CI is Linux, which doesn't trigger it. A broader fix is open as a follow-up.
  • Required environment for standalone Mac runs: JAVA_HOME pointing to JDK 21 (project's BREE — openjdk@21 on Homebrew; the default openjdk is 25 and has separate sun.misc.Unsafe issues), and WORKSPACE=$(pwd) (needed by the logback config path in ddk-parent).

Usage

CI (unchanged):

mvn verify -f ./ddk-parent/pom.xml

Focused dev iteration on export tests only:

export WORKSPACE=\$(pwd)
mvn verify -pl :com.avaloq.tools.ddk.xtext.export.test -am \\
           -Dddk.skipPerModuleTests=false -f ./ddk-parent/pom.xml

Known limitation

tycho-build is incompatible with mvnd — the embedded Takari SmartBuilder collides with tycho-build's dependency graph (DependencyGraph ClassCastException across ClassRealms, independent of -b flag). Use plain mvn for -am workflows; mvnd remains usable for full-reactor builds without -am.

Test plan

  • CI runs mvn verify (default property) and aggregator tests pass without regression (357 tests, same as master baseline). Validates Scenario D under full CI load.
  • CI runs mvn verify -pl :com.avaloq.tools.ddk.xtext.export.test -am -Dddk.skipPerModuleTests=false and 14 export tests pass standalone. Validates Scenario C on Linux.
  • Once green: rebase onto master after build: enable UI tests on macOS via Tycho profile + JRE docs #1283 merges; verify both scenarios still pass.

Left by Claude at João's request.

joaodinissf and others added 5 commits May 16, 2026 23:05
Add a `macosx` Maven profile in ddk-parent/pom.xml, activated on
family=mac, that sets the OSGi target environment
(macosx/cocoa/aarch64) and appends -XstartOnFirstThread to
test.javaOptions. SWT on Cocoa requires the Display to be created on
the main thread; without the flag, UI tests fail with "SWTException:
Invalid thread access".

The same flag is needed when developers run UI test launches from
Eclipse on macOS, but -XstartOnFirstThread is rejected as an
"Unrecognized VM option" by the JVM on Windows and Linux. Eclipse's
own .launch files (e.g. in eclipse-platform/eclipse.platform) omit
it entirely and rely on the launching JRE's default VM arguments to
add it on macOS. Adopt the same pattern: document the one-time
per-JRE setup in AGENTS.md instead of hardcoding the flag in
cross-platform .launch files.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Register `org.eclipse.tycho:tycho-build` as a Maven core extension via
`.mvn/extensions.xml`. With this extension active, Maven's `--also-make`
(`-am`) flag walks Tycho's OSGi requirements (`Require-Bundle`,
`Import-Package`, target definitions) when computing the reactor —
without it, only Maven `<dependency>` blocks are considered, which is
nearly empty for this codebase since dependencies are declared in
`MANIFEST.MF`.

Empirical effect from `mvn -pl :com.avaloq.tools.ddk.check.core -am`:
without the extension the reactor contains 1 project (the requested one)
and the build either fails cold or succeeds only when stale `target/`
jars happen to satisfy resolution; with the extension the reactor
expands to 11 upstream bundles and succeeds cold.

The version is sourced from `.mvn/maven.config` (`-Dtycho.version=5.0.2`)
rather than hardcoded in `extensions.xml`, so both files draw from the
same property. The parent POM's `<tycho.version>` should be kept in
sync; an enforcement check is left for a follow-up.

Known limitation: `mvnd` is incompatible with this extension — the
embedded Takari SmartBuilder collides with tycho-build's dependency
graph implementation (ClassCastException across ClassRealms). Use plain
`mvn` for `-am` workflows; `mvnd` remains usable for full-reactor
builds without `-am`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduce `ddk.skipPerModuleTests` (default `true`) to gate optional
per-module tycho-surefire execution. With the default value no behaviour
changes — the aggregator in `com.avaloq.tools.ddk.xtext.test` remains
the sole point of test execution and no test runs twice.

This commit only declares the property; it has no consumer yet. A
follow-up commit opts the first module in by binding its surefire
`<skip>` to this property.

Rationale: hardcoding `<skip>false</skip>` per-module would double-
execute tests on default `mvn verify` runs, because the aggregator's
JUnit `@Suite` discovers the same `*TestSuite` classes via its
`Require-Bundle` aggregation. Gating the standalone surefire on a
property defaulting to `true` keeps CI behaviour unchanged and lets
developers opt in with one CLI flag for focused iteration.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a full tycho-surefire-plugin and target-platform-configuration to
`com.avaloq.tools.ddk.xtext.export.test` so its tests can run standalone
via:

  mvn verify -pl :com.avaloq.tools.ddk.xtext.export.test -am \
             -Dddk.skipPerModuleTests=false -f ./ddk-parent/pom.xml

Default `mvn verify` is unchanged: the surefire `<skip>` is bound to
`${ddk.skipPerModuleTests}` which defaults to `true`. The aggregator in
`com.avaloq.tools.ddk.xtext.test` remains the sole executor of the
export tests on CI and full-reactor dev runs, preventing any double-
execution.

Configuration mirrors `xtext.test`'s surefire block (UI harness, IDE
workbench application, JVM args, target-platform extras for xtext.sdk,
pde, help, rcp, equinox.event) with two differences:

  1. `<testClass>` points to `ExportTestSuite` rather than `AllTests`,
     so the standalone run covers only the export tests.

  2. `argLine` additionally exports `jdk.incubator.vector` via
     `-Dorg.osgi.framework.system.packages.extra` so that
     `org.eclipse.help.base` (transitive on Lucene 9.12) resolves on
     macOS with Adoptium/Temurin JDKs.

Pilot module — the pattern can be extended to other `*.test` bundles by
copying this configuration and pointing `<testClass>` at the
corresponding `*TestSuite` class.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@joaodinissf joaodinissf changed the title build: per-module test execution via tycho-build extension (PoC, stacked on #1283) build: per-module test execution via tycho-build extension (PoC) May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant