Skip to content

test(java): add Pinot connector E2E coverage - #3922

Open
goutamadwant wants to merge 2 commits into
apache:masterfrom
goutamadwant:java-pinot-e2e-2598
Open

test(java): add Pinot connector E2E coverage#3922
goutamadwant wants to merge 2 commits into
apache:masterfrom
goutamadwant:java-pinot-e2e-2598

Conversation

@goutamadwant

@goutamadwant goutamadwant commented Aug 19, 2026

Copy link
Copy Markdown

Which issue does this PR address?

Closes #2598

Rationale

The Pinot connector needs repeatable, Gradle-integrated end-to-end coverage for its documented ingestion workflow.

What changed?

Before, Pinot connector E2E coverage lived in a manual shell script with fixed ports, fixed sleeps, and a mutable Pinot image. The workflow was not part of Gradle and could report table creation success even when Pinot rejected the connector.

The shell workflow is now a JUnit and Testcontainers suite that verifies JSON field mapping and 10-message batch ingestion. Local runs use an always-pulled VSR-capable Iggy image, while CI uses the branch-built external server through Testcontainers host-port forwarding and an in-memory Pinot table configuration.

Gradle tracks the deployment configuration and external-server settings as test inputs, and Java CI publishes the Pinot XML results in its test summary. The shaded plugin keeps its relocated Netty dependency, while bounded polling and service-log diagnostics make failures actionable.

Local Execution

  • Passed: ./gradlew :iggy-connector-pinot:check --no-daemon --no-build-cache --rerun-tasks
  • Passed: ./gradlew check -x test --no-daemon --no-build-cache --rerun-tasks
  • Passed against a branch-built server: USE_EXTERNAL_SERVER=true ./gradlew test --no-daemon --no-build-cache --rerun-tasks
  • Pre-commit hooks ran on the changed files and passed.

AI Usage

Codex was used to understand the existing repo and codebase.

@github-actions

Copy link
Copy Markdown

Thanks for the PR. It is labeled S-waiting-on-review and queued for review.

Slash commands (own line, regular comment) move it around the queue:

  • /ready - back to S-waiting-on-review after addressing feedback
  • /author - flip to S-waiting-on-author while you finish changes
  • /request-review @user-or-team - request a reviewer

See CONTRIBUTING.md for details.

@github-actions github-actions Bot added the S-waiting-on-review PR is waiting on a reviewer label Aug 19, 2026
class IggyPinotIntegrationTest {

// The Java SDK speaks VSR, so use the same VSR-capable image as its integration tests.
private static final DockerImageName IGGY_IMAGE = DockerImageName.parse("apache/iggy:edge");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a USE_EXTERNAL_SERVER switch here, mirroring BaseIntegrationTest? In CI we want this suite to run against the iggy-server built from the current branch (the same way the SDK tests do), so the E2E actually validates the code under review. The apache/iggy:edge container should stay only as the developer-convenience path for local runs.

One thing to solve for the external mode: the Pinot containers resolve the server via the iggy network alias and deployment/table.json hardcodes stream.iggy.host: "iggy" / port 8090. With an external server on the host, the containers need a route to it (e.g. host.docker.internal / host-gateway extra host mapped to the iggy alias, or templating the host/port into the table config before POSTing it).

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

@Testcontainers

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Testcontainers is decorative here: there are no @Container fields, so the extension manages nothing - lifecycle is entirely manual in @BeforeAll/@AfterAll. Either remove the annotation or add @Container annotations to let the extension manage the containers. Note that the @Container route will be harder to keep once the external-server env switch is introduced, since some containers would then start conditionally, which doesn't fit the annotation-driven lifecycle well.

lastResponse = "HTTP " + response.statusCode() + ": " + response.body();
if (response.statusCode() >= 200 && response.statusCode() < 300) {
JsonNode json = OBJECT_MAPPER.readTree(response.body());
if (hasExceptionCode(json, 150)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: 150 is Pinot's SQL parsing error code. pinot-spi is already on the test classpath, so QueryErrorCode.SQL_PARSING.getId() (or a named constant) would document the intent.

finalizedBy("assemblePlugin")
}

tasks.named<Test>("test") {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test task doesn't declare deployment/ as an input, so editing schema.json / table.json and rerunning test can report UP-TO-DATE with stale results. Suggest adding:

inputs.dir(layout.projectDirectory.dir("deployment"))

from(configurations.runtimeClasspath)
tasks.shadowJar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
filesMatching("META-INF/services/**") {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the filesMatching("META-INF/services/**") { duplicatesStrategy = INCLUDE } block is dead config - mergeServiceFiles() installs a transformer that takes service descriptors out of the normal copy path entirely, so the top-level EXCLUDE never sees them.

@mmodzelewski

Copy link
Copy Markdown
Member

@goutamadwant Thanks for the contribution! This is a solid replacement for the shell workflow.

.github/actions/java-gradle/pre-merge/action.yml copies test results and feeds the Test Summary only from java-sdk and the Flink connector. The new Pinot E2E results won't appear in the summary (a failure still fails the build, but without the report). Worth adding external-processors/iggy-connector-pinot/build/test-results to the copy step and the summary paths.

@github-actions github-actions Bot added S-waiting-on-author PR is waiting on author response and removed S-waiting-on-review PR is waiting on a reviewer labels Aug 19, 2026
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.67%. Comparing base (e71e3c6) to head (c0afb62).
⚠️ Report is 6 commits behind head on master.

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3922      +/-   ##
============================================
- Coverage     83.67%   83.67%   -0.01%     
  Complexity     1358     1358              
============================================
  Files          1212     1212              
  Lines        165138   166191    +1053     
  Branches     132612   133790    +1178     
============================================
+ Hits         138181   139059     +878     
- Misses        23308    23354      +46     
- Partials       3649     3778     +129     
Components Coverage Δ
Rust Core 84.49% <0.00%> (+0.05%) ⬆️
Java SDK 66.67% <ø> (ø)
C# SDK 74.97% <ø> (-1.12%) ⬇️
Python SDK 90.00% <ø> (ø)
PHP SDK 84.48% <ø> (ø)
Node SDK 95.94% <ø> (+0.09%) ⬆️
Go SDK 68.32% <ø> (ø)
see 82 files with indirect coverage changes
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

S-waiting-on-author PR is waiting on author response

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add e2e tests for Apache Pinot connector

2 participants