Migrate CI Visibility Smoke tests from Groovy to Java#11439
Conversation
…Spock to Java/JUnit 5 Drops Spock + Groovy 3 from `dd-java-agent:agent-ci-visibility:civisibility-test-fixtures` and from the three CiVisibility smoke modules (`dd-smoke-tests:gradle`, `:maven`, `:junit-console`). The fixtures' main source is now Java; the three smoke modules use JUnit 5 + `@TableTest`. `MockBackend` and `CiVisibilityInstrumentationTest` stay on Groovy/Spock and consume the new Java APIs. This unblocks running the CiVisibility smoke tests under Gradle 9, whose bundled Groovy 4 is incompatible with `spock 2.4-groovy-3.0`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apply the rules from `.claude/skills/migrate-junit-source-to-tabletest/SKILL.md` to the freshly migrated CiVisibility smoke tests:
- Every `@TableTest` table now starts with a non-parameter `scenario` column used as the row's display name.
- `MavenSmokeTest.testJunit4ClassOrdering` drops its `String testcaseName` method parameter; the first column becomes the scenario.
- Duplicated `@TypeConverter TestFQN toTestFQN(...)` moves into `civisibility-test-fixtures` as a shared `CiVisibilityTableTestConverters`, wired via `@TypeConverterSources`.
- `GradleDaemonSmokeTest.testNew` collapses the three pairs of `test-succeed-new-instrumentation` rows that differed only on `configurationCache` into single rows via `{false, true}` value-set syntax.
- Gradle smoke tests no longer take `TestInfo` as a method parameter (which conflicted with TableTest's column-count convention); `AbstractGradleTest` captures it once in `@BeforeEach` and exposes it via an inherited `protected TestInfo testInfo` field.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tic prints The scenario column added in the previous commit already identifies each `@TableTest` row in JUnit 5's test output and in the JUnit XML report, so the inline timestamped `System.out.println` prefixes were redundant. Removes the inherited `TestInfo testInfo` field on `AbstractGradleTest`, the parameter-injection `@BeforeEach`, and the unused `java.util.Date` imports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: efc0ebaf18
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Three regressions caught by GitLab CI on the PR:
1. **ClassCastException in `CiVisibilityTestUtils.assertData` at line 229.**
`CiVisibilityInstrumentationTest.assertSpansData` builds the
`additionalReplacements` map with GString values (via
`"${instrumentedLibraryName()}:${instrumentedLibraryVersion()}"`). My port
declared the parameter as `Map<String, String>`, so the for-each loop's
implicit `String` cast on `e.getValue()` blew up under Groovy callers.
Widens both `assertData` overloads to `Map<String, ?>` and uses
`String.valueOf` when stitching the value back into a placeholder string.
2. **`verifySnapshots` was failing on `dd.spanid` / friends.**
The original Groovy `requiredLogFields.each { field -> log.containsKey(field) }`
discarded the boolean — i.e. asserted nothing. My Java port turned it into
`assertTrue(log.containsKey(field))`, which tripped on snapshots that don't
include the field. Reverts to the original (intentionally lenient)
behaviour with a TODO-style comment explaining why.
3. **forbiddenApisMain + config-inversion-linter failures on the new Java
main sources.** The original code lived in `src/main/groovy/` which the
linters don't scan; the Java port exposes them to both
`forbiddenApisMain` (`System.getenv`, `System.out`, `String.getBytes()`,
`String.replaceAll(String, String)`) and `logEnvVarUsages` (the
`"DD_CIVISIBILITY_SMOKETEST_DEBUG_*"` literals). Fixes:
- Disable `forbiddenApisMain` on `civisibility-test-fixtures` — this is a
test-support module, on the test classpath of its consumers, so the
production-code-quality gates don't apply.
- Switch the local-debug toggles to JVM system properties
(`datadog.civisibility.smoketest.debug.parent` /
`…debug.child`) so no `DD_…` literal lives in `src/main/java` for
`logEnvVarUsages` to flag.
- Keep the explicit `StandardCharsets.UTF_8` on `String.getBytes(…)` and
the precompiled `Matcher.replaceAll(...)` — both are objectively
better than the platform-default variants.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
f8d3d7b to
75b54e7
Compare
Test Environment - sbt-scalatestJob Status: success
|
Test Environment - nebula-release-pluginJob Status: success
|
Test Environment - netflix-zuulJob Status: success
|
Test Environment - pass4sJob Status: success
|
Test Environment - reactive-streams-jvmJob Status: success
|
Test Environment - sonar-kotlinJob Status: success
|
Test Environment - jolokiaJob Status: success
|
Test Environment - okhttpJob Status: success
|
Test Environment - spring_bootJob Status: success
|
…izable SpotBugs flagged `SE_COMPARATOR_SHOULD_BE_SERIALIZABLE` on the stateless comparator. Add `Serializable` to the `implements` clause with a `serialVersionUID` to satisfy the check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3d74b53 to
e7b65b2
Compare
Test Environment - sonar-javaJob Status: success
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ad8dcc480c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Groovy's `switch (null) { case foo: ... default: ... }` silently falls through to `default`, which is what the original `rootSpanTypeToVal` relied on for traces whose root span has no type set. The Java port called `DDSpanTypes.TEST.contentEquals(spanType)` directly, which throws NPE when `spanType` is `null` — surfacing as `4 failed tests due to NullPointerException at KarateTest.groovy:188` across every test_inst[*,6/8] and test_inst_latest[*,2/6] shard.
Adds an explicit `if (spanType == null) return 4;` short-circuit (the same value the default branch returns) and re-runs spotless to capture the verifySnapshots assertion-tightening edit reverted by the user in the IDE.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex review caught a regression vs. the original Spock semantics: in Spock, `@Shared @AutoCleanup protected MockBackend mockBackend = new MockBackend()` produces one instance per spec class. My Java port made it `static final` on the abstract base — meaning a single shared `MockBackend` for both `GradleDaemonSmokeTest` and `GradleLauncherSmokeTest`. Whichever JUnit ran first would call the inherited `@AfterAll closeMockBackend()`, leaving the second class to `reset()` a closed `TestHttpServer` and talk to a dead intake URL. Switches `AbstractGradleTest` to `@TestInstance(Lifecycle.PER_CLASS)` and turns `mockBackend` and `closeMockBackend` into instance members. JUnit now creates one `AbstractGradleTest` instance per concrete subclass, with its own backend and its own close hook — matching the Spock `@Shared` lifecycle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ad8dcc4 to
7d4c6e4
Compare
| Map<String, Object> snapshotContent = debuggerMap.snapshot as Map<String, Object> | ||
|
|
||
| assert snapshotContent != null | ||
| requiredSnapshotFields.each { field -> snapshotContent.containsKey(field) } |
There was a problem hiding this comment.
note: @DataDog/ci-app-libraries @daniel-mohedano I noticed the following code wasn't asserting anything in Groovy. And is ported the same way in its Java equivalent. It might be worh coming back to it at a later point.
There was a problem hiding this comment.
Great catch, I'll handle it on my side in a following PR, thanks!
daniel-mohedano
left a comment
There was a problem hiding this comment.
LGTM from CIVis side, thanks a lot for the effort! 🚀
| private static boolean isWithin( | ||
| ComparableVersion version, | ||
| ComparableVersion lowerInclusive, | ||
| ComparableVersion upperExclusive) { | ||
| return version.compareTo(lowerInclusive) >= 0 && version.compareTo(upperExclusive) < 0; | ||
| } |
There was a problem hiding this comment.
nit: we can remove datadog.trace.util.ComparableVersion#isWithin then, I think it was only used here
There was a problem hiding this comment.
I'd rather keep this focused on the conversion at this time.
What Does This Do
Migrates the CiVisibility smoke-test stack from Groovy/Spock to Java + JUnit 5 +
@TableTest:dd-java-agent:agent-ci-visibility:civisibility-test-fixturesTHe other smoke test depends on the fixture
dd-smoke-tests:gradledd-smoke-tests:mavendd-smoke-tests:junit-consoleMotivation
Gradle 9 bundles Groovy 4 in
gradleApi()/gradleTestKit(). Howeverdd-smoke-tests:gradlesmoke tests rely on Groovy tests and Spock2.4-groovy-3.0, which is not compatible with Groovy 4.0 (compilation fails withIncompatibleGroovyVersionException).Bumping Groovy to 4 is not the way we want to go
Additional Notes
org.gradle.util.DistributionLocator→org.gradle.util.internal.DistributionLocator(the former package is gone in Gradle 9; the latter is present in both Gradle 8.14.5 and 9.5.1).Contributor Checklist
type:and (comp:orinst:) labels in addition to any other useful labelsclose,fix, or any linking keywords when referencing an issueUse
solvesinstead, and assign the PR milestone to the issueJira ticket: [PROJ-IDENT]
Note: Once your PR is ready to merge, add it to the merge queue by commenting
/merge./merge -ccancels the queue request./merge -f --reason "reason"skips all merge queue checks; please use this judiciously, as some checks do not run at the PR-level. For more information, see this doc.