lhotari opened a new issue, #26011: URL: https://github.com/apache/pulsar/issues/26011
### Search before reporting - [x] I searched in the [issues](https://github.com/apache/pulsar/issues) and found nothing similar. ### Motivation The Gradle build (PIP-463, #25398) ported Maven's `test-jar` pattern as-is: `pulsar.java-conventions.gradle.kts` registers a `testJar` task (classifier `tests`) packaging the **entire `test` source set output**, plus a consumable `testJar` configuration, for **every** Java module. Cross-module test dependencies are declared with the legacy notation: ```kotlin testImplementation(project(path = ":pulsar-broker-common", configuration = "testJar")) ``` Producers consumed this way: `pulsar-broker-common`, `managed-ledger`, `pulsar-metadata`, `pulsar-package-management:pulsar-package-core`, `pulsar-broker`. Consumers: `pulsar-broker`, `pulsar-proxy`, `pulsar-metadata`, `pulsar-testclient`, `pulsar-broker-auth-sasl`, `pulsar-client-tools-test`, `pulsar-opentelemetry`, `bouncy-castle/bcfips-include-test`, `tests/integration`. This was noticed while working on Maven publishing for the Gradle build. Problems with the current approach: 1. **No separation between test infrastructure and test classes.** Consumers only need shared infrastructure (e.g. `MockedPulsarServiceBaseTest`, `MockedBookKeeperTestCase`, test utilities), but the jar ships every test class in the producer module. The actual test classes pollute consumers' test classpaths and keep infrastructure and test cases structurally entangled. 2. **Legacy, non-variant-aware dependency wiring.** `project(path = ..., configuration = "testJar")` bypasses Gradle's variant-aware resolution. The `testJar` configuration carries no attributes and `extendsFrom(testImplementation, testRuntimeOnly)`, leaking the producer's *entire* test dependency graph to consumers with no api/implementation separation. 3. **Poor incremental build and caching behavior.** The consumer's test compile classpath depends on the producer's full test jar, so *any* test-class change in the producer module invalidates compilation and test execution in all dependent modules — e.g. editing a single `pulsar-broker` test invalidates `pulsar-proxy`, `pulsar-testclient`, `pulsar-broker-auth-sasl`, etc. With test fixtures, only changes to the fixtures source set propagate. 4. **No sound publishing story.** A classifier jar shares the main artifact's POM, so its (test-scoped) dependencies are not represented in published metadata. `java-test-fixtures` models fixtures as a proper variant with Gradle Module Metadata and `testFixturesApi`/`testFixturesImplementation` dependency declarations — and the variant can also be cleanly excluded from publication where we don't want to publish it. 5. **Applied globally but needed in five modules.** Every module pays for a `testJar` task and configuration that almost none of them need. Gradle's recommended solution for exactly this is the [`java-test-fixtures` plugin](https://docs.gradle.org/current/userguide/java_testing.html#sec:java_test_fixtures). ### Solution 1. Apply `java-test-fixtures` to the five producer modules (directly or via a small opt-in convention plugin). 2. In each producer, move the shared test infrastructure (mock/base classes, test utilities) from `src/test/java` to `src/testFixtures/java`, declaring its dependencies with `testFixturesApi` / `testFixturesImplementation`. Test classes themselves stay in `src/test/java` and are no longer exposed. 3. Switch consumers to the idiomatic notation: ```kotlin testImplementation(testFixtures(project(":pulsar-broker-common"))) ``` 4. Remove the generic `testJar` task and configuration from `pulsar.java-conventions.gradle.kts`. 5. Decide the publishing policy for fixtures: by default skip the `testFixturesApiElements`/`testFixturesRuntimeElements` variants from the publication (matching today's behavior, where the test jar is not published), and only publish fixtures for modules where external consumers genuinely need them. The migration can be done incrementally, one producer module (plus its consumers) per PR, keeping the `testJar` mechanism in place until the last consumer is migrated. ### Alternatives - **Keep the test-jar port but add variant attributes to the `testJar` configuration.** Fixes the variant-resolution wart but none of the structural problems (no infra/test separation, leaked test dependency graph, invalidation cascade, no publishable metadata). - **Extract test infrastructure into dedicated `*-test-utils` modules.** Works, but adds module sprawl and inter-module ceremony; `java-test-fixtures` provides the same separation inside the owning module with first-class Gradle and IDE support. ### Anything else? The old Maven build attached `test-jar` artifacts via `maven-jar-plugin`, so `tests`-classifier jars for these modules were historically published to Maven Central. The Gradle publish conventions currently don't publish the test jar at all, so the fixtures variant-skipping default would not be a regression relative to the Gradle build — but whether any external consumers still rely on the previously published `tests` jars is worth checking when deciding the publishing policy in step 5. ### Are you willing to submit a PR? - [x] I'm willing to submit a PR! -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
