Skip to content

ci: run the integration tests through failsafe and verify the shaded jar - #67

Open
LuciferYang wants to merge 5 commits into
lance-format:mainfrom
LuciferYang:ci/failsafe-integration-tests
Open

ci: run the integration tests through failsafe and verify the shaded jar#67
LuciferYang wants to merge 5 commits into
lance-format:mainfrom
LuciferYang:ci/failsafe-integration-tests

Conversation

@LuciferYang

@LuciferYang LuciferYang commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

What this does

The repo has five *ITCase classes and none of them had ever run. There is no maven-failsafe-plugin in the build, and *ITCase does not match surefire's default includes (*Test, *Tests, *TestCase), so mvn verify walked straight past them. #55 listed this as a follow-up; this is it.

Four changes:

  1. Wire maven-failsafe-plugin into the three jar modules so verify runs the ITs.
  2. Add LanceShadedJarITCase, for the reason in the next section.
  3. Set argLine so Arrow can allocate off-heap on JDK 17+, which is what turning the ITs on immediately exposed.
  4. In the workflow, rename the build step and widen the failure artifact so it carries the failsafe reports next to surefire's. The mvn command does not change: verify now covers the ITs, so the existing 8-job matrix picks them up as it stands.

Why failsafe has to target target/classes

maven-shade-plugin relocates org.apache.arrow to org.apache.flink.connector.lance.shaded.arrow at package, replacing the main artifact. failsafe defaults to that main artifact. The tests compile against plain Arrow, so running them against the shaded jar fails with NoSuchMethodError: the signatures moved.

target/classes                    -> toArrowSchema(RowType) : org.apache.arrow.vector.types.pojo.Schema
target/lance-flink-1.18-0.1.0.jar -> toArrowSchema(RowType) : org.apache.flink.connector.lance.shaded.arrow.vector.types.pojo.Schema

Hence <classesDirectory>${project.build.outputDirectory}</classesDirectory>. The cost is that the shaded jar, which is what users actually deploy, then has no automated check at all. That is what LanceShadedJarITCase covers: it loads the jar in its own classloader and asserts that no plain-Arrow class is bundled, and that the connector's public signatures reference the relocated packages.

Guarding against silent no-ops

Three ways a green build could have stopped proving the ITs ran, all closed here:

  • Listing any <includes> pattern replaces failsafe's whole default set, and failIfNoTests defaults to false, so a pattern matching nothing exits 0. The defaults are restated and failIfNoTests is on.
  • The shaded-jar check first probed a single class name. A per-package relocation carve-out, which is the usual fix when a JNI package breaks on being moved, leaves plain Arrow in the jar while that one class still resolves. It now walks every jar entry.
  • A missing jar was an assumeTrue, so it skipped. shade runs at package, before this phase, so if the build handed us a path the jar should be there. It asserts now.

failsafe hangs off the three jar modules rather than the root aggregator, since the root has no test classes of its own and failIfNoTests=true would fail it there.

Why one matrix rather than separate IT jobs

Giving the ITs their own jobs is the obvious shape and it does not pay off here, because a job in the existing matrix already does everything the ITs need. Here is a -DskipITs job, Flink 1.18 / JDK 17, by phase:

surefire:test               19:48:57
jar:jar                     19:49:05
shade:shade                 19:49:05    <- 280MB fat jar, built anyway
failsafe:integration-test   19:49:43    <- "Tests are skipped."

-DskipITs skips failsafe and nothing else. The reactor compile and the shade run either way, and failsafe's own 44 tests take 4.7 seconds. So a dedicated IT job would pay for a second full build to buy 4.7 seconds of coverage, and the overlap would grow with every unit test added.

Keeping them in the existing matrix also widens IT coverage from one JDK to all eight Flink x JDK combinations. The JDK axis is not idle for ITs: the MemoryUtil failure below reproduces on 17+ and only warns on 11. The eight jobs on this branch run 57 to 77 seconds each.

Test plan

mvn -am -pl lance-flink-<v> verify was run locally for every Flink x JDK pair the matrix covers, and all eight report 44 ITs and 186 unit tests:

JDK 11 JDK 17 JDK 21
1.18 44 44 not in matrix
1.19 44 44 44
1.20 44 44 44

44 = LanceSqlITCase 20 + LanceConnectorITCase 15 + LanceTimeTravelITCase 4 + LanceNamespaceCatalogITCase 3 + LanceShadedJarITCase 2. One of the time-travel cases is an opt-in export gated on $TT_EXPORT_DIR and reports as skipped, so a green run shows Skipped: 1. -DskipITs still works for a local unit-only run, verified on 1.18/JDK 17 and 1.20/JDK 21.

Both new checks were reverse-verified by breaking what they watch:

  • Comment out shade's <relocations> and LanceShadedJarITCase goes red (1 failure, 1 error).
  • Add <exclude>org.apache.arrow.memory.**</exclude> to the relocation and the jar-walk assertion fails, listing the leaked org/apache/arrow/memory/*.class entries. The single-class probe stayed green on this one, which is why it was replaced.
  • Point -Dfailsafe.includes at a pattern matching nothing and the build fails, where before failIfNoTests it exited 0.

What the ITs found

LanceTimeTravelITCase, which came in with #56, errored on three of its four cases as soon as failsafe started running it:

Failed to initialize MemoryUtil. You must start Java with
  --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED

It writes real Arrow vectors, and Arrow reaches java.nio.Buffer.address by reflection. JDK 17 blocks that outright, so MemoryUtil's static initializer throws and the tests fail with NoClassDefFoundError. JDK 11 only prints an illegal-reflective-access warning, which is part of why this went unnoticed: nothing was running the class on any JDK.

Fixed by setting argLine as a root property. Arrow's own poms carry the same flag for their test runs. Keeping it a property rather than putting it inside surefire's <configuration> is what keeps jacoco working, since prepare-agent appends its -javaagent to argLine instead of replacing it. The build log confirms both survive:

argLine set to -javaagent:.../org.jacoco.agent-0.8.14-runtime.jar=destfile=... --add-opens=java.base/java.nio=ALL-UNNAMED

@github-actions github-actions Bot added the ci CI/CD related changes label Aug 13, 2026
@LuciferYang

Copy link
Copy Markdown
Contributor Author

cc @fightBoxing

@LuciferYang
LuciferYang marked this pull request as draft August 14, 2026 03:30
@LuciferYang
LuciferYang marked this pull request as ready for review August 14, 2026 03:45
@LuciferYang
LuciferYang marked this pull request as draft August 14, 2026 03:45
The three existing *ITCase classes had never run: no failsafe plugin was
configured, and the names do not match surefire's default includes. Wire
failsafe in and split the workflow so the unit-test matrix skips ITs while a
narrower matrix runs them.

failsafe has to target target/classes. shade replaces the main artifact at
package time with a jar in which org.apache.arrow is relocated, and the tests
are compiled against the plain Arrow packages, so running against the main
artifact fails with NoSuchMethodError. That leaves the shaded jar itself
unverified, hence LanceShadedJarITCase, which loads the jar in its own
classloader and asserts the relocation held.
Three ways a green build could stop proving the integration tests ran:

- Listing an <includes> pattern replaces failsafe's whole default set, and
  failIfNoTests defaults to false, so a pattern matching nothing exits 0.
  Restate the defaults and turn failIfNoTests on. The root aggregator has no
  test classes of its own, so failsafe now hangs off the three jar modules
  rather than the parent, which also stops it leaving a stray report dir there.
- The shaded-jar check probed one class name. A per-package relocation carve-out
  (the usual fix when a JNI package breaks on being moved) leaves plain Arrow in
  the jar while that one class still resolves. Walk every jar entry instead.
  Verified: adding <exclude>org.apache.arrow.memory.**</exclude> to the
  relocation turns this red, where the single-class probe stayed green.
- A missing jar was an assumeTrue, so it skipped. shade runs at package, before
  this phase, so if the build handed us the path the jar should be there. Assert.
LanceTimeTravelITCase (added by lance-format#56) writes real Arrow vectors, which reaches
java.nio.Buffer.address by reflection. JDK 17 blocks that, so MemoryUtil's static
initializer throws and three of its four cases error out with NoClassDefFoundError.
JDK 11 only prints an illegal-reflective-access warning, which is why nothing
noticed until failsafe started running *ITCase at all.

Arrow's own poms carry the same add-opens for their test runs. Setting argLine as a
property rather than inside surefire's config keeps jacoco working: prepare-agent
appends its -javaagent to argLine instead of replacing it.
A separate IT job pays for a full build to buy 5 seconds of coverage. The
unit-matrix job already compiles the reactor and shades the fat jar; -DskipITs
only skips failsafe itself, which the CI log timestamps at 4.7s of an 86s job.
So the two job types did the same work and diverged only at the end, and the
duplication would grow with every unit test added.

Dropping the split also widens IT coverage from 1.18/1.19/1.20 on JDK 17 to all
eight Flink x JDK combinations, and the JDK axis is not idle here: the MemoryUtil
add-opens failure this branch fixes reproduces on 17+ and only warns on 11.
The rest of the tree comments in English, including the Java files merged most
recently. Also replaces an em dash in the LanceShadedJarITCase javadoc so the
file stays ASCII.
@LuciferYang
LuciferYang force-pushed the ci/failsafe-integration-tests branch from f69d66f to e5d0330 Compare August 17, 2026 17:13
@LuciferYang
LuciferYang marked this pull request as ready for review August 18, 2026 00:03
@LuciferYang

Copy link
Copy Markdown
Contributor Author

cc @fightBoxing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci CI/CD related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant