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]

Reply via email to