diff --git a/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy b/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy index e433a69efc8..b19e9583df9 100644 --- a/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy +++ b/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy @@ -16,6 +16,7 @@ import freemarker.core.InvalidReferenceException import freemarker.template.Template import freemarker.template.TemplateException import freemarker.template.TemplateExceptionHandler +import groovy.transform.CompileStatic import org.opentest4j.AssertionFailedError import org.skyscreamer.jsonassert.JSONAssert import org.skyscreamer.jsonassert.JSONCompareMode @@ -367,6 +368,7 @@ abstract class CiVisibilityTestUtils { return compiledPaths } + @CompileStatic // Workaround for Groovy 4 to not produce false-positive FindBugs warning `UPM_UNCALLED_PRIVATE_METHOD`. private static DynamicPath path(String rawPath, boolean unique = true) { return new DynamicPath(rawPath, JsonPath.compile(rawPath), unique) } diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/taint/HashCodeTest.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/taint/HashCodeTest.groovy index 86e300108e4..668a1c91806 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/taint/HashCodeTest.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/taint/HashCodeTest.groovy @@ -1,6 +1,7 @@ package com.datadog.iast.taint import datadog.trace.test.util.DDSpecification +import groovy.transform.CompileStatic import spock.lang.IgnoreIf import spock.lang.Shared @@ -51,6 +52,7 @@ class HashCodeTest extends DDSpecification { } } + @CompileStatic // Workaround to avoid NPE in Groovy 4 `org.codehaus.groovy.vmplugin.v8.IndyInterface.fromCache()` method. private static List genHashCodes(final int n) { (1..n).collect { System.identityHashCode(Double.toString(Math.random())) diff --git a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/taint/ObjectGen.groovy b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/taint/ObjectGen.groovy index a08038be898..99e85e66735 100644 --- a/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/taint/ObjectGen.groovy +++ b/dd-java-agent/agent-iast/src/test/groovy/com/datadog/iast/taint/ObjectGen.groovy @@ -2,9 +2,12 @@ package com.datadog.iast.taint import static TaintedMap.POSITIVE_MASK +import groovy.transform.CompileStatic + /** * Generate objects to test {@link TaintedMap}. */ +@CompileStatic // Workaround to avoid java.lang.AbstractMethodError with Groovy 4. class ObjectGen { final int capacity @@ -36,7 +39,8 @@ class ObjectGen { } } - def genBucket(int nObjects, Closure isValid) { + // Have to return specific type to avoid java.lang.AbstractMethodError with Groovy 4. + List genBucket(int nObjects, Closure isValid) { assert nObjects > 0 while (true) { for (int i = 0; i < capacity; i++) { diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy index d683006de7e..973189f3001 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/ddwaf/WAFModuleSpecification.groovy @@ -787,8 +787,8 @@ class WAFModuleSpecification extends DDSpecification { stackTrace.language == 'java' stackTrace.message == 'Exploit detected' stackTrace.frames.size() >= 1 - stackTrace.frames[0].class_name == 'org.codehaus.groovy.runtime.callsite.CallSiteArray' - stackTrace.frames[0].function == 'defaultCall' + stackTrace.frames[0].class_name == 'org.codehaus.groovy.vmplugin.v8.IndyInterface' // With Groovy 3 it was 'org.codehaus.groovy.runtime.callsite.CallSiteArray' + stackTrace.frames[0].function == 'fromCache' // With Groovy 3 it was 'defaultCall' } void 'redaction with default settings'() { diff --git a/dd-java-agent/instrumentation/aerospike-4.0/build.gradle b/dd-java-agent/instrumentation/aerospike-4.0/build.gradle index f38182ab4bd..089a0d085d2 100644 --- a/dd-java-agent/instrumentation/aerospike-4.0/build.gradle +++ b/dd-java-agent/instrumentation/aerospike-4.0/build.gradle @@ -39,3 +39,5 @@ dependencies { tasks.withType(Test).configureEach { usesService(testcontainersLimit) } + +configureGroovyCompiler(21, "compileLatestDepTestGroovy", "compileLatestDepForkedTestGroovy") diff --git a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/CompletableFutureTest.groovy b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/CompletableFutureTest.groovy index 022ac7e169a..cd4626964a7 100644 --- a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/CompletableFutureTest.groovy +++ b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/CompletableFutureTest.groovy @@ -127,7 +127,7 @@ class CompletableFutureTest extends InstrumentationSpecification { // The parent and the child spans can finish out of order since they run // on different threads concurrently trace(2) { - def pIndex = span(0).isRootSpan() ? 0 : 1 + def pIndex = span(0).checkRootSpan() ? 0 : 1 def cIndex = 1 - pIndex basicSpan(it, pIndex, "parent") basicSpan(it, cIndex, "child", span(pIndex)) diff --git a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/CrossedContextTest.groovy b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/CrossedContextTest.groovy index 66ee256edb4..323bb2f5c53 100644 --- a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/CrossedContextTest.groovy +++ b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/CrossedContextTest.groovy @@ -60,7 +60,7 @@ class CrossedContextTest extends InstrumentationSpecification { then: for (List trace : TEST_WRITER) { assert trace.size() == 2 - DDSpan parent = trace.find({ it.isRootSpan() }) + DDSpan parent = trace.find({ it.checkRootSpan() }) assert null != parent DDSpan child = trace.find({ it.getParentId() == parent.getSpanId() }) assert null != child @@ -121,7 +121,7 @@ class CrossedContextTest extends InstrumentationSpecification { then: for (List trace : TEST_WRITER) { assert trace.size() == 2 - DDSpan parent = trace.find({ it.isRootSpan() }) + DDSpan parent = trace.find({ it.checkRootSpan() }) assert null != parent DDSpan child = trace.find({ it.getParentId() == parent.getSpanId() }) assert null != child diff --git a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/executor/RecursiveThreadPoolPropagationTest.groovy b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/executor/RecursiveThreadPoolPropagationTest.groovy index 957bf8cb1da..e50a9fb5209 100644 --- a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/executor/RecursiveThreadPoolPropagationTest.groovy +++ b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/test/groovy/executor/RecursiveThreadPoolPropagationTest.groovy @@ -346,7 +346,7 @@ class RecursiveThreadPoolPropagationTest extends InstrumentationSpecification { List trace = TEST_WRITER.get(0) assert trace.size() == depth for (DDSpan span : sortByDepth(trace)) { - orphanCount += span.isRootSpan() ? 1 : 0 + orphanCount += span.checkRootSpan() ? 1 : 0 assert String.valueOf(i++) == span.getOperationName() } assert orphanCount == 1 diff --git a/dd-java-agent/instrumentation/java/java-nio-1.8/src/test/groovy/DirectAllocationTrackingTest.groovy b/dd-java-agent/instrumentation/java/java-nio-1.8/src/test/groovy/DirectAllocationTrackingTest.groovy index f73585a46e6..1583d6c9555 100644 --- a/dd-java-agent/instrumentation/java/java-nio-1.8/src/test/groovy/DirectAllocationTrackingTest.groovy +++ b/dd-java-agent/instrumentation/java/java-nio-1.8/src/test/groovy/DirectAllocationTrackingTest.groovy @@ -53,12 +53,12 @@ class DirectAllocationTrackingTest extends InstrumentationSpecification { def sample = directAllocations.find({ it.getEventType().name.equals("datadog.DirectAllocationSample")}) sample.getLong("allocated") == 20 sample.getString("source") == "MMAP" - sample.getString("allocatingClass") == "org.codehaus.groovy.runtime.callsite.PlainObjectMetaMethodSite" + sample.getString("allocatingClass") == "org.codehaus.groovy.vmplugin.v8.IndyInterface" // With Groovy 3 it was "org.codehaus.groovy.runtime.callsite.PlainObjectMetaMethodSite" sample.getLong("spanId") == expectedSpanId.get() def total = directAllocations.find({ it.getEventType().name.equals("datadog.DirectAllocationTotal")}) total.getLong("allocated") == 20 total.getString("source") == "MMAP" - total.getString("allocatingClass") == "org.codehaus.groovy.runtime.callsite.PlainObjectMetaMethodSite" + total.getString("allocatingClass") == "org.codehaus.groovy.vmplugin.v8.IndyInterface" // With Groovy 3 it was "org.codehaus.groovy.runtime.callsite.PlainObjectMetaMethodSite" cleanup: recording.close() @@ -80,12 +80,12 @@ class DirectAllocationTrackingTest extends InstrumentationSpecification { def sample = directAllocations.find({ it.getEventType().name.equals("datadog.DirectAllocationSample")}) sample.getLong("allocated") == 10 sample.getString("source") == "ALLOCATE_DIRECT" - sample.getString("allocatingClass") == "java_nio_ByteBuffer\$allocateDirect" + sample.getString("allocatingClass") == "org.codehaus.groovy.vmplugin.v8.IndyInterface" // With Groovy 3 it was "java_nio_ByteBuffer\$allocateDirect" sample.getLong("spanId") == expectedSpanId.get() def total = directAllocations.find({ it.getEventType().name.equals("datadog.DirectAllocationTotal")}) total.getLong("allocated") == 10 total.getString("source") == "ALLOCATE_DIRECT" - total.getString("allocatingClass") == "java_nio_ByteBuffer\$allocateDirect" + total.getString("allocatingClass") == "org.codehaus.groovy.vmplugin.v8.IndyInterface"// With Groovy 3 it was "java_nio_ByteBuffer\$allocateDirect" cleanup: recording.close() diff --git a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-10.0/build.gradle b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-10.0/build.gradle index 00ddd8c272a..2084a6c6c32 100644 --- a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-10.0/build.gradle +++ b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-10.0/build.gradle @@ -32,6 +32,13 @@ tasks.named("compileMain_java11Java", JavaCompile) { configureCompiler(it, 11, JavaVersion.VERSION_1_8) } +configureGroovyCompiler(11, + "compileTestGroovy", + "compileJetty11TestGroovy", + "compileLatestDepTestGroovy", + "compileJetty10LatestDepTestGroovy" + ) + dependencies { main_java11CompileOnly group: 'org.eclipse.jetty', name: 'jetty-client', version: '10.0.0' main_java11Implementation(project(':dd-java-agent:instrumentation:jetty:jetty-client:jetty-client-common')) { diff --git a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-12.0/build.gradle b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-12.0/build.gradle index bcb1bd91020..1b3a39c9ce7 100644 --- a/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-12.0/build.gradle +++ b/dd-java-agent/instrumentation/jetty/jetty-client/jetty-client-12.0/build.gradle @@ -20,6 +20,8 @@ tasks.named("compileMain_java17Java", JavaCompile) { configureCompiler(it, 17, JavaVersion.VERSION_17) } +configureGroovyCompiler(17, "compileTestGroovy", "compileLatestDepTestGroovy") + configurations.matching { it.name.startsWith('test') || it.name.startsWith('latestDepTest') }.configureEach { it.resolutionStrategy { force group: 'org.slf4j', name: 'slf4j-api', version: libs.versions.slf4j.get() diff --git a/dd-java-agent/instrumentation/junit/junit-5.3/build.gradle b/dd-java-agent/instrumentation/junit/junit-5.3/build.gradle index 327e8a58a39..5aa2a391523 100644 --- a/dd-java-agent/instrumentation/junit/junit-5.3/build.gradle +++ b/dd-java-agent/instrumentation/junit/junit-5.3/build.gradle @@ -85,3 +85,5 @@ tasks.named("latestDepTest", Test) { minJavaVersion = JavaVersion.VERSION_17 } } + +configureGroovyCompiler(17, "compileLatestDepTestGroovy") diff --git a/dd-java-agent/instrumentation/junit/junit-5.3/junit-5.8/build.gradle b/dd-java-agent/instrumentation/junit/junit-5.3/junit-5.8/build.gradle index 13f25bcf03d..7975fbdcd78 100644 --- a/dd-java-agent/instrumentation/junit/junit-5.3/junit-5.8/build.gradle +++ b/dd-java-agent/instrumentation/junit/junit-5.3/junit-5.8/build.gradle @@ -77,3 +77,5 @@ tasks.named("latestDepTest", Test) { minJavaVersion = JavaVersion.VERSION_17 } } + +configureGroovyCompiler(17, "compileLatestDepTestGroovy") diff --git a/dd-java-agent/instrumentation/junit/junit-5.3/spock-junit-5/build.gradle b/dd-java-agent/instrumentation/junit/junit-5.3/spock-junit-5/build.gradle index bb607475451..59d258d2958 100644 --- a/dd-java-agent/instrumentation/junit/junit-5.3/spock-junit-5/build.gradle +++ b/dd-java-agent/instrumentation/junit/junit-5.3/spock-junit-5/build.gradle @@ -32,6 +32,12 @@ dependencies { latestDepTestImplementation group: 'org.spockframework', name: 'spock-core', version: '2.+' } +configurations { + testImplementation { + exclude group: 'org.apache.groovy' + } +} + configurations.matching({ it.name.startsWith('test') }).configureEach({ it.resolutionStrategy { force group: 'org.junit.platform', name: 'junit-platform-launcher', version: libs.versions.junit.platform.get() diff --git a/dd-java-agent/instrumentation/kafka/kafka-clients-0.11/build.gradle b/dd-java-agent/instrumentation/kafka/kafka-clients-0.11/build.gradle index f32f4c0c6ad..d2e304dc8a4 100644 --- a/dd-java-agent/instrumentation/kafka/kafka-clients-0.11/build.gradle +++ b/dd-java-agent/instrumentation/kafka/kafka-clients-0.11/build.gradle @@ -24,7 +24,7 @@ dependencies { compileOnly group: 'org.apache.kafka', name: 'kafka-clients', version: '0.11.0.0' implementation project(':dd-java-agent:instrumentation:kafka:kafka-common') - testImplementation libs.spock.junit4 // This module still needs Spock with JUnit4. + testImplementation(libs.spock.junit4) // This module still needs Spock with JUnit4. testImplementation group: 'org.apache.kafka', name: 'kafka-clients', version: '0.11.0.0' testImplementation group: 'org.springframework.kafka', name: 'spring-kafka', version: '1.3.3.RELEASE' testImplementation group: 'org.springframework.kafka', name: 'spring-kafka-test', version: '1.3.3.RELEASE' diff --git a/dd-java-agent/instrumentation/kotlin-coroutines-1.3/src/latestDepTest/kotlin/KotlinCoroutineTests.kt b/dd-java-agent/instrumentation/kotlin-coroutines-1.3/src/latestDepTest/kotlin/KotlinCoroutineTests.kt index 77be265ed46..671acfe08f2 100644 --- a/dd-java-agent/instrumentation/kotlin-coroutines-1.3/src/latestDepTest/kotlin/KotlinCoroutineTests.kt +++ b/dd-java-agent/instrumentation/kotlin-coroutines-1.3/src/latestDepTest/kotlin/KotlinCoroutineTests.kt @@ -2,33 +2,43 @@ import datadog.trace.api.Trace import datadog.trace.instrumentation.kotlin.coroutines.CoreKotlinCoroutineTests import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.FlowCollector +import kotlinx.coroutines.flow.channelFlow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.single import kotlinx.coroutines.launch import kotlinx.coroutines.withTimeout +// Workaround for Groovy 4 breaking Kotlin SAM conversion for FlowCollector +private suspend inline fun Flow.forEach(crossinline action: suspend (T) -> Unit) = collect(object : FlowCollector { + override suspend fun emit(value: T) = action(value) +}) + class KotlinCoroutineTests(dispatcher: CoroutineDispatcher) : CoreKotlinCoroutineTests(dispatcher) { @Trace fun tracedAcrossFlows(withModifiedContext: Boolean): Int = runTest { - val producer = flow { - repeat(3) { - tracedChild("produce_$it") - if (withModifiedContext) { - withTimeout(100) { - emit(it) - } - } else { + // Use channelFlow when emitting from modified context (withTimeout) as regular flow doesn't allow it + val producer: Flow = if (withModifiedContext) { + channelFlow { + repeat(3) { + tracedChild("produce_$it") + withTimeout(100) { send(it) } + } + } + } else { + flow { + repeat(3) { + tracedChild("produce_$it") emit(it) } } }.flowOn(jobName("producer")) launch(jobName("consumer")) { - producer.collect { - tracedChild("consume_$it") - } + producer.forEach { tracedChild("consume_$it") } } 7 diff --git a/dd-java-agent/instrumentation/liberty/liberty-23.0/build.gradle b/dd-java-agent/instrumentation/liberty/liberty-23.0/build.gradle index f90c9eed237..7422a67fdda 100644 --- a/dd-java-agent/instrumentation/liberty/liberty-23.0/build.gradle +++ b/dd-java-agent/instrumentation/liberty/liberty-23.0/build.gradle @@ -65,7 +65,6 @@ dependencies { configurations.named("testRuntimeOnly") { exclude group: 'ch.qos.logback', module: 'logback-classic' - exclude group: 'org.codehaus.groovy', module: 'groovy-servlet' } configurations.named("webappRuntimeClasspath") { exclude group: 'ch.qos.logback', module: 'logback-classic' diff --git a/dd-java-agent/instrumentation/ratpack-1.5/build.gradle b/dd-java-agent/instrumentation/ratpack-1.5/build.gradle index e6572cbe135..719ca7ebe35 100644 --- a/dd-java-agent/instrumentation/ratpack-1.5/build.gradle +++ b/dd-java-agent/instrumentation/ratpack-1.5/build.gradle @@ -17,8 +17,12 @@ dependencies { compileOnly group: 'io.ratpack', name: 'ratpack-core', version: '1.5.0' testImplementation project(':dd-java-agent:instrumentation:netty:netty-4.1') - testImplementation group: 'io.ratpack', name: 'ratpack-groovy-test', version: '1.5.0' + testImplementation(group: 'io.ratpack', name: 'ratpack-groovy-test', version: '1.5.0') { + exclude group: 'org.codehaus.groovy' + } testImplementation 'com.sun.activation:jakarta.activation:1.2.2' testImplementation project(':dd-java-agent:appsec:appsec-test-fixtures') - latestDepTestImplementation group: 'io.ratpack', name: 'ratpack-groovy-test', version: '1.+' + latestDepTestImplementation(group: 'io.ratpack', name: 'ratpack-groovy-test', version: '1.+') { + exclude group: 'org.codehaus.groovy' + } } diff --git a/dd-java-agent/instrumentation/spring/spring-boot-1.3/build.gradle b/dd-java-agent/instrumentation/spring/spring-boot-1.3/build.gradle index 26dd765c94b..ba97aabefed 100644 --- a/dd-java-agent/instrumentation/spring/spring-boot-1.3/build.gradle +++ b/dd-java-agent/instrumentation/spring/spring-boot-1.3/build.gradle @@ -25,7 +25,7 @@ addTestSuiteExtendingForDir("boot2LatestDepForkedTest", "boot2LatestDepTest", "t addTestSuiteExtendingForDir("boot3ForkedTest", "boot3Test", "test") addTestSuiteExtendingForDir("latestDepForkedTest", "latestDepTest", "test") -configureGroovyCompiler(17, "compileLatestDepTestGroovy", "compileBoot3TestGroovy") +configureGroovyCompiler(17, "compileLatestDepTestGroovy", "compileBoot3TestGroovy", "compileBoot3ForkedTestGroovy", "compileLatestDepForkedTestGroovy") dependencies { implementation project(':dd-java-agent:instrumentation:span-origin') diff --git a/dd-java-agent/instrumentation/undertow/undertow-2.2/build.gradle b/dd-java-agent/instrumentation/undertow/undertow-2.2/build.gradle index f69efe8561e..c29bad0bae5 100644 --- a/dd-java-agent/instrumentation/undertow/undertow-2.2/build.gradle +++ b/dd-java-agent/instrumentation/undertow/undertow-2.2/build.gradle @@ -58,3 +58,4 @@ tasks.named("latestDepForkedTest", Test) { } } +configureGroovyCompiler(11, "compileLatestDepTestGroovy", "compileLatestDepForkedTestGroovy") diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/server/http/TestHttpServer.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/server/http/TestHttpServer.groovy index a346410db64..372101f4f58 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/server/http/TestHttpServer.groovy +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/server/http/TestHttpServer.groovy @@ -6,6 +6,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.core.DDSpan import edu.umd.cs.findbugs.annotations.SuppressFBWarnings +import groovy.transform.CompileStatic import org.eclipse.jetty.http.HttpMethod import org.eclipse.jetty.http.HttpVersion import org.eclipse.jetty.server.Handler @@ -319,6 +320,7 @@ class TestHttpServer implements AutoCloseable { this.prefix = prefix.startsWith("/") ? prefix : "/" + prefix } + @CompileStatic // Groovy 4: workaround to avoid `groovy.lang.MissingMethodException`. @Override void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (target.startsWith(prefix)) { @@ -491,7 +493,7 @@ class TestHttpServer implements AutoCloseable { } void send(byte[] body) { - sendWithType(DEFAULT_TYPE, body) + sendWithType(DEFAULT_TYPE, (byte[]) body) // Groovy 4 has stricter coercions rules. } void sendWithType(String contentType, byte[] body) { diff --git a/dd-smoke-tests/gradle/build.gradle b/dd-smoke-tests/gradle/build.gradle index 76ebc34b6cb..fa9e390ab6f 100644 --- a/dd-smoke-tests/gradle/build.gradle +++ b/dd-smoke-tests/gradle/build.gradle @@ -8,11 +8,23 @@ plugins { apply from: "$rootDir/gradle/java.gradle" description = 'Gradle Daemon Instrumentation Smoke Tests.' +// Gradle 8.14.3 bundles Groovy 3 via `gradleTestKit()`, so we need Spock for Groovy 3 instead of Groovy 4. +// Gradle 9.x bundles Groovy 4, so eventually we can drop this workaround. +configurations.configureEach { + // Exclude Groovy 4. Starting from v4 it has group: `org.apache.groovy`. + exclude group: 'org.apache.groovy' + + resolutionStrategy { + // Force Spock for Groovy 3. + force "org.spockframework:spock-core:2.4-groovy-3.0" + } +} + dependencies { testImplementation gradleTestKit() testImplementation project(':dd-smoke-tests:backend-mock') testImplementation project(':internal-api') - testImplementation project(':dd-java-agent:agent-ci-visibility:civisibility-test-fixtures') + testImplementation(project(':dd-java-agent:agent-ci-visibility:civisibility-test-fixtures')) } tasks.named("test", Test) { diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index 28db0b6c99e..8627b246e09 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -1610,7 +1610,7 @@ protected static final DDSpan buildSpanImpl( List links, DDSpanContext spanContext) { DDSpan span = DDSpan.create(instrumentationName, timestampMicro, spanContext, links); - if (span.isLocalRootSpan()) { + if (span.checkLocalRootSpan()) { EndpointTracker tracker = tracer.onRootSpanStarted(span); if (tracker != null) { span.setEndpointTracker(tracker); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java index 1b321f4536a..3b9ed37e9f5 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java @@ -310,7 +310,7 @@ public boolean isForceKeep() { * * @return true if root, false otherwise */ - public final boolean isRootSpan() { + public final boolean checkRootSpan() { return context.getParentId() == DDSpanId.ZERO; } @@ -330,7 +330,7 @@ public DDSpan getLocalRootSpan() { * * @return {@literal true} if this span is the same as {@linkplain #getLocalRootSpan()} */ - public boolean isLocalRootSpan() { + public boolean checkLocalRootSpan() { return getLocalRootSpan().equals(this); } @@ -382,7 +382,7 @@ private boolean isExceptionReplayEnabled() { boolean captureOnlyRootSpan = (Config.get().isDebuggerExceptionOnlyLocalRoot() || !Config.get().isDebuggerExceptionCaptureIntermediateSpansEnabled()); - if (captureOnlyRootSpan && !isLocalRootSpan()) { + if (captureOnlyRootSpan && !checkLocalRootSpan()) { return false; } return true; diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/DDSpanTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/DDSpanTest.groovy index e7882432d9c..a61fffbab48 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/DDSpanTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/DDSpanTest.groovy @@ -279,14 +279,14 @@ class DDSpanTest extends DDCoreSpecification { new ExtractedContext(DDTraceId.ONE, 2, PrioritySampling.SAMPLER_DROP, "some-origin", propagationTagsFactory.empty(), DATADOG) | _ } - def "isRootSpan() in and not in the context of distributed tracing"() { + def "checkRootSpan() in and not in the context of distributed tracing"() { setup: def root = tracer.buildSpan("root").asChildOf((AgentSpanContext) extractedContext).start() def child = tracer.buildSpan("child").asChildOf(root).start() expect: - root.isRootSpan() == isTraceRootSpan - !child.isRootSpan() + root.checkRootSpan() == isTraceRootSpan + !child.checkRootSpan() cleanup: child.finish() diff --git a/gradle/codenarc.gradle b/gradle/codenarc.gradle index 563d181a0fe..459f8c2c51f 100644 --- a/gradle/codenarc.gradle +++ b/gradle/codenarc.gradle @@ -1,7 +1,7 @@ apply plugin: "codenarc" dependencies { - codenarc('org.codenarc:CodeNarc:3.7.0') + codenarc('org.codenarc:CodeNarc:3.7.0-groovy-4.0') } codenarc { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 37441a0a41b..7d3b706341c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ okhttp = "3.12.15" # Datadog fork to support Java 7 # Languages ## Groovy -groovy = "3.0.25" +groovy = "4.0.29" ## Kotlin kotlin = "1.6.21" @@ -67,7 +67,7 @@ junit4 = "4.13.2" junit5 = "5.14.1" junit-platform = "1.14.1" mockito = "4.4.0" -spock = "2.4-groovy-3.0" +spock = "2.4-groovy-4.0" testcontainers = "1.21.3" [libraries] @@ -83,11 +83,11 @@ okhttp = { module = "com.datadoghq.okhttp3:okhttp", version.ref = "okhttp" } # Languages ## Groovy -groovy = { module = "org.codehaus.groovy:groovy", version.ref = "groovy" } -groovy-json = { module = "org.codehaus.groovy:groovy-json", version.ref = "groovy" } -groovy-templates = { module = "org.codehaus.groovy:groovy-templates", version.ref = "groovy" } -groovy-yaml = { module = "org.codehaus.groovy:groovy-yaml", version.ref = "groovy" } -groovy-xml = { module = "org.codehaus.groovy:groovy-xml", version.ref = "groovy" } +groovy = { module = "org.apache.groovy:groovy", version.ref = "groovy" } +groovy-json = { module = "org.apache.groovy:groovy-json", version.ref = "groovy" } +groovy-templates = { module = "org.apache.groovy:groovy-templates", version.ref = "groovy" } +groovy-yaml = { module = "org.apache.groovy:groovy-yaml", version.ref = "groovy" } +groovy-xml = { module = "org.apache.groovy:groovy-xml", version.ref = "groovy" } ## Kotlin kotlin = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } diff --git a/remote-config/remote-config-core/src/test/groovy/datadog/remoteconfig/DefaultConfigurationPollerSpecification.groovy b/remote-config/remote-config-core/src/test/groovy/datadog/remoteconfig/DefaultConfigurationPollerSpecification.groovy index ae18bd5f839..170409ba388 100644 --- a/remote-config/remote-config-core/src/test/groovy/datadog/remoteconfig/DefaultConfigurationPollerSpecification.groovy +++ b/remote-config/remote-config-core/src/test/groovy/datadog/remoteconfig/DefaultConfigurationPollerSpecification.groovy @@ -588,7 +588,7 @@ class DefaultConfigurationPollerSpecification extends DDSpecification { byte[] fileDecoded = Base64.decoder.decode(it['target_files'][0]['raw']) byte[] newFile = new byte[fileDecoded.length + 1] System.arraycopy(fileDecoded, 0, newFile, 0, fileDecoded.length) - newFile[fileDecoded.length] = '\n' + newFile[fileDecoded.length] = (byte) '\n' // Groovy 4 has strict coercion rules. it['target_files'][0]['raw'] = Base64.encoder.encodeToString(newFile) def targetDecoded = Base64.decoder.decode(it['targets']) def target = SLURPER.parse(targetDecoded)