E2E-functional-tests: Maven functional tests exercise real Maven Native Image builds

August 26, 2026 · View on GitHub

Maven end-to-end coverage lives under native-maven-plugin/src/functionalTest/. These tests run sample projects, generated projects, or issue reproducers through an isolated Maven executor, seed a local Maven repository with plugin and support artifacts, and verify the behavior users see from the Maven plugin. They provide executable evidence for the focused Maven functional specs under docs/functional/, §AR-maven-plugin, and the shared product contract in §root/FS-plugin-common.

1. Full local suite

Run the full Maven plugin functional suite locally with:

./gradlew :native-maven-plugin:functionalTest

This suite publishes the plugin and support artifacts to the local test repository, then runs Maven sample or reproducer projects as external builds. That shape is intentional: it catches descriptor, goal, lifecycle, repository, and command-line behavior that unit tests cannot see.

2. Single functional test class

Run one Maven functional test class with:

./gradlew :native-maven-plugin:functionalTest \
  --tests org.graalvm.buildtools.maven.JavaApplicationFunctionalTest

For tests that require process isolation while debugging, use the documented -DnoTestIsolation flag from the repository developer guide. Use Maven debug output from the functional test when the goal configuration, lifecycle phase, or generated command line is the failure surface.

3. Scenario Coverage

3.1 Lifecycle native builds

JavaApplicationFunctionalTest, JavaLibraryFunctionalTest, and profile-based sample builds verify compile-no-fork bound to lifecycle phases such as package. This protects §FS-goal-surface.1, §FS-goal-surface.4, and §FS-native-builds.

3.2 Direct goal usage

JavaApplicationFunctionalTest and related functional tests verify direct goal usage such as native:compile, native:write-args-file, and support goals. This protects §FS-goal-surface.1, §FS-goal-surface.3, and §FS-native-builds.8.

3.3 Native tests

JavaApplicationWithTestsFunctionalTest, MavenTestExecutionFunctionalTests, JUnitFunctionalTests, and issues/ModuleWithoutSourcesFunctionalTest verify native:test, skip flags, no-test behavior, runtime arguments, launcher selection, and reactor modules without source artifacts. This protects §FS-goal-surface.2, §FS-native-tests, and §root/FS-native-tests.

3.4 Resources

JavaApplicationWithResourcesFunctionalTest verifies main and test resource configuration generation and resource propagation into native builds. This protects §FS-native-builds.4 and §FS-resources-and-metadata.1.

3.5 Reachability metadata

MetadataRepositoryFunctionalTest, OfficialMetadataRepositoryFunctionalTest, and issues/ExcludeDependenciesFunctionalTest with reproducers/issue-612 verify official and local metadata repositories, exclusions, forced versions, archives, URLs, and missing metadata reports. This protects §FS-resources-and-metadata.2, §FS-resources-and-metadata.3, and §common/FS-common-libraries.5.

3.6 Tracing agent

JavaApplicationWithAgentFunctionalTest verifies -Dagent=true, standard/direct/conditional modes, disabled stages, merge behavior, and native:metadata-copy. This protects §FS-tracing-agent and §common/FS-common-libraries.3.

3.6.1 Shared reactor destination

issues/MetadataCopyReactorFunctionalTest with reproducers/issue-650 verifies deterministic replacement and merge behavior when sequential reactor modules share one metadata destination. It also verifies that replacement removes metadata types absent from the later module and that a failed native-image-configure invocation leaves the destination unchanged without staging output. This protects §FS-tracing-agent.4.1.

3.7 Maven integration

SBOMFunctionalTest, JavaApplicationWithTestsFunctionalTest, issues/JavaAppWithTestsAndParentPomFunctionalTest with reproducers/issue-144, and issues/ModuleWithoutSourcesFunctionalTest with reproducers/issue-727 verify shaded JARs, custom packaging, SBOM behavior, parent POM merging, issue reproducers, and local repository seeding. This protects §FS-native-builds.6, §FS-config-model.3, and §AR-maven-plugin.6.

3.8 Layer artifacts

LayeredApplicationFunctionalTest verifies that a reactor producer creates and attaches a nil layer artifact, a consumer resolves it outside the Java classpath, and the application image consumes the layer, executes, and produces the expected output. This protects §FS-goal-surface.6, §FS-native-builds.3, and §FS-config-model.7. The class is the executable evidence for module, package, explicit-path, and all selection, plus main, native-test, and shared-library layer consumption. Layer-consumption scenarios that exercise all selection, explicit paths, native tests, shared libraries are skipped on GraalVM 25.0.x because Native Image can fail after -H:LayerUse loads a valid layer.

When adding behavior that a user can observe through a Maven goal, plugin parameter, generated file, lifecycle binding, or Native Image invocation, add or update a functional test in the closest scenario family.

4. Local repository setup

Functional tests seed a local Maven repository before executing sample or reproducer builds. This keeps tests independent from external publication and protects the Maven-specific architecture in §AR-maven-plugin.6.

The local repository is part of the test contract: tests should resolve the plugin exactly as a sample project would, rather than reaching into compiled classes directly.

Online prepareMavenLocalRepo builds a replacement seed in staging and publishes it only after Maven succeeds. Its seed-state manifest keys the prepared seeding project, Maven settings, embedder classpath, goals, flags, supplied version/system-property values, the explicit Java 17 launcher, and seed schema. The fresh staging repository follows Maven's normal remote snapshot policy rather than requesting unconditional snapshot updates. The manifest inventories every stable repository file by relative path and content hash; transient locks, temporary downloads, and resolver-status files are excluded.

Repository-internal Maven executions use the Gradle toolchain-provided Java 17 launcher regardless of the runtime that launched Gradle or the separately selected functional-test JVM. Ordinary execution captures Maven's routine streams, omits Maven error stacks, and reports one actionable Gradle failure. A dependency-resolution failure identifies the first unresolved artifact and repository, sanitizing repository URLs by removing credentials, query values, and fragments; an unclassified failure reports the final meaningful Maven error. Gradle --info replays the captured Maven output and enables Maven error detail, while Gradle --debug additionally enables Maven debug output. Descriptor generation uses an isolated task-local Maven repository and clears failed-transfer markers before execution so stale negative cache entries cannot require snapshot refreshes. These launcher and effective argument inputs participate in seed validity.

Offline descriptor and functional-test prerequisites validate that manifest without invoking Maven or modifying the repository. Validation requires the current input key and the complete inventoried file set with matching hashes. Missing, stale, truncated, or corrupted state fails with: The seeded Maven repository is missing or stale; run prepareMavenLocalRepo online. A failed online refresh or offline validation must leave the previous repository unchanged. Offline functional tests copy the validated seed and current common publication repository into their isolated local repository and invoke Maven offline, so they neither alter the seed nor contact remote repositories.

5. CI coverage

test-native-maven-plugin.yml runs generated Maven functional-test matrices, Maven plugin inspections, and GraalVM dev-build functional tests on pull requests. The CI workflow is specified by §root/AR-repository-ci.1.4.

The CI matrix is the merge gate. Local runs should reproduce the failing class or reproducer first, then broaden to the full suite before pushing behavior changes that affect goals, Maven parameter binding, Native Image invocation, metadata, resources, SBOM behavior, or native tests.