diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index e9f488551d2..9190a8b8c09 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -45,6 +45,7 @@
# @DataDog/asm-java (AppSec/IAST)
/buildSrc/call-site-instrumentation-plugin/ @DataDog/asm-java
/dd-java-agent/agent-iast/ @DataDog/asm-java
+/dd-java-agent/appsec/appsec-test-fixtures/ @DataDog/asm-java
/dd-java-agent/instrumentation/*iast* @DataDog/asm-java
/dd-java-agent/instrumentation/*appsec* @DataDog/asm-java
/dd-java-agent/instrumentation/json/ @DataDog/asm-java
diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Constants.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Constants.java
index 8f4ba377161..3bb71f4a89c 100644
--- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Constants.java
+++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Constants.java
@@ -11,7 +11,7 @@ public final class Constants {
* packages which will be loaded on the bootstrap classloader
*
*
Updates should be mirrored in
- * datadog.trace.agent.test.SpockRunner#BOOTSTRAP_PACKAGE_PREFIXES_COPY
+ * datadog.trace.agent.test.BootstrapClasspathSetup#BOOTSTRAP_PACKAGE_PREFIXES_COPY
*/
public static final String[] BOOTSTRAP_PACKAGE_PREFIXES = {
"datadog.slf4j",
diff --git a/dd-java-agent/agent-ci-visibility/build.gradle b/dd-java-agent/agent-ci-visibility/build.gradle
index 1f0b8ddd0a4..6974b37459f 100644
--- a/dd-java-agent/agent-ci-visibility/build.gradle
+++ b/dd-java-agent/agent-ci-visibility/build.gradle
@@ -27,7 +27,6 @@ buildscript {
plugins {
id 'com.gradleup.shadow'
- id 'java-test-fixtures'
}
apply from: "$rootDir/gradle/java.gradle"
@@ -42,29 +41,23 @@ dependencies {
api libs.slf4j
implementation libs.bundles.asm
- implementation group: 'org.jacoco', name: 'org.jacoco.core', version: '0.8.12'
- implementation group: 'org.jacoco', name: 'org.jacoco.report', version: '0.8.12'
+ implementation group: 'org.jacoco', name: 'org.jacoco.core', version: '0.8.13'
+ implementation group: 'org.jacoco', name: 'org.jacoco.report', version: '0.8.13'
implementation project(':communication')
implementation project(':components:json')
implementation project(':internal-api')
implementation project(':internal-api:internal-api-9')
- testImplementation project(":utils:test-utils")
+ testImplementation project(':dd-java-agent:testing')
testImplementation("com.google.jimfs:jimfs:1.1") // an in-memory file system for testing code that works with files
testImplementation libs.scala
testImplementation libs.kotlin
- testFixturesApi project(':dd-java-agent:testing')
- testFixturesApi project(':utils:test-utils')
-
- testFixturesApi group: 'org.skyscreamer', name: 'jsonassert', version: '1.5.1'
- testFixturesApi group: 'org.freemarker', name: 'freemarker', version: '2.3.31'
- testFixturesApi group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0'
- testFixturesApi group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.16.0'
- testFixturesApi group: 'org.msgpack', name: 'jackson-dataformat-msgpack', version: '0.9.6'
- testFixturesApi group: 'org.xmlunit', name: 'xmlunit-core', version: '2.10.3'
+ testImplementation group: 'org.skyscreamer', name: 'jsonassert', version: '1.5.1'
+ testImplementation group: 'org.freemarker', name: 'freemarker', version: '2.3.31'
+ testImplementation group: 'org.msgpack', name: 'jackson-dataformat-msgpack', version: '0.9.6'
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.9.2") // Required to update dependency lock files
}
diff --git a/dd-java-agent/agent-ci-visibility/civisibility-instrumentation-test-fixtures/README.MD b/dd-java-agent/agent-ci-visibility/civisibility-instrumentation-test-fixtures/README.MD
new file mode 100644
index 00000000000..9cf13b33cbf
--- /dev/null
+++ b/dd-java-agent/agent-ci-visibility/civisibility-instrumentation-test-fixtures/README.MD
@@ -0,0 +1,10 @@
+# civisibility-instrumentation-test-fixtures
+
+This project contains common logic used in CI Visibility instrumentation tests.
+
+The reason it is defined as a separate project rather than using testFixtures plugin in the parent module is because it
+transitively pulls in :dd-java-agent:instrumentation-testing.
+The latter contains datadog.trace.agent.test.BootstrapClasspathSetupListener that, when present on the classpath,
+patches bootstrap CL adding some tracer classes to it.
+This is needed for the instrumentation tests, but may break regular unit tests.
+If this project used testFixtures, the listener would end up on the classpath of the parent project's unit tests, breaking them.
diff --git a/dd-java-agent/agent-ci-visibility/civisibility-instrumentation-test-fixtures/build.gradle b/dd-java-agent/agent-ci-visibility/civisibility-instrumentation-test-fixtures/build.gradle
new file mode 100644
index 00000000000..dec74075fae
--- /dev/null
+++ b/dd-java-agent/agent-ci-visibility/civisibility-instrumentation-test-fixtures/build.gradle
@@ -0,0 +1,8 @@
+apply from: "$rootDir/gradle/java.gradle"
+apply from: "$rootDir/gradle/version.gradle"
+
+dependencies {
+ api project(':dd-java-agent:instrumentation-testing')
+ api project(':dd-java-agent:agent-ci-visibility:civisibility-test-fixtures')
+}
+
diff --git a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy b/dd-java-agent/agent-ci-visibility/civisibility-instrumentation-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy
similarity index 98%
rename from dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy
rename to dd-java-agent/agent-ci-visibility/civisibility-instrumentation-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy
index f19d88656cf..4697abe5549 100644
--- a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy
+++ b/dd-java-agent/agent-ci-visibility/civisibility-instrumentation-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy
@@ -3,7 +3,7 @@ package datadog.trace.civisibility
import com.fasterxml.jackson.databind.ObjectMapper
import datadog.communication.serialization.GrowableBuffer
import datadog.communication.serialization.msgpack.MsgPackWriter
-import datadog.trace.agent.test.AgentTestRunner
+import datadog.trace.agent.test.InstrumentationSpecification
import datadog.trace.agent.test.asserts.ListWriterAssert
import datadog.trace.api.Config
import datadog.trace.api.DDSpanTypes
@@ -50,6 +50,7 @@ import datadog.trace.civisibility.writer.ddintake.CiTestCycleMapperV1
import datadog.trace.common.writer.ListWriter
import datadog.trace.common.writer.RemoteMapper
import datadog.trace.core.DDSpan
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import org.msgpack.jackson.dataformat.MessagePackFactory
import java.lang.reflect.Method
@@ -61,7 +62,7 @@ import java.util.concurrent.TimeUnit
import java.util.function.Predicate
import java.util.stream.Collectors
-abstract class CiVisibilityInstrumentationTest extends AgentTestRunner {
+abstract class CiVisibilityInstrumentationTest extends InstrumentationSpecification {
public static final int SLOW_TEST_THRESHOLD_MILLIS = 1000
public static final int VERY_SLOW_TEST_THRESHOLD_MILLIS = 2000
@@ -290,6 +291,7 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner {
return true
}
+ @SuppressFBWarnings("UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS")
boolean waitForSpan(Predicate predicate, long timeoutMillis) {
long deadline = System.currentTimeMillis() + timeoutMillis
synchronized (lock) {
diff --git a/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/build.gradle b/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/build.gradle
new file mode 100644
index 00000000000..e8068ab0757
--- /dev/null
+++ b/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/build.gradle
@@ -0,0 +1,15 @@
+apply from: "$rootDir/gradle/java.gradle"
+apply from: "$rootDir/gradle/version.gradle"
+
+dependencies {
+ api project(':dd-java-agent:agent-ci-visibility')
+ api project(':dd-java-agent:testing')
+
+ api group: 'org.skyscreamer', name: 'jsonassert', version: '1.5.1'
+ api group: 'org.freemarker', name: 'freemarker', version: '2.3.31'
+ api group: 'com.jayway.jsonpath', name: 'json-path', version: '2.8.0'
+ api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.16.0'
+ api group: 'org.msgpack', name: 'jackson-dataformat-msgpack', version: '0.9.6'
+ api group: 'org.xmlunit', name: 'xmlunit-core', version: '2.10.3'
+}
+
diff --git a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy b/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy
similarity index 100%
rename from dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy
rename to dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy
diff --git a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy b/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy
similarity index 99%
rename from dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy
rename to dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy
index 86ea005d31e..3709018d587 100644
--- a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy
+++ b/dd-java-agent/agent-ci-visibility/civisibility-test-fixtures/src/main/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy
@@ -171,7 +171,7 @@ abstract class CiVisibilityTestUtils {
println "Expected JSON: $expectedJson"
println "Actual JSON: $actualJson"
}
- throw new AssertionFailedError("Coverage report events mismatch", expectedJson, actualJson, e)
+ throw new AssertionFailedError("Expected and actual JSON mismatch", expectedJson, actualJson, e)
}
}
diff --git a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy
index de0b9f775b2..d853ec8e275 100644
--- a/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy
+++ b/dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/config/ConfigurationApiImplTest.groovy
@@ -10,8 +10,12 @@ import datadog.trace.api.civisibility.config.TestFQN
import datadog.trace.api.civisibility.config.TestIdentifier
import datadog.trace.api.civisibility.config.TestMetadata
import datadog.trace.api.civisibility.telemetry.CiVisibilityMetricCollector
-import datadog.trace.civisibility.CiVisibilityTestUtils
import datadog.trace.api.intake.Intake
+import freemarker.core.Environment
+import freemarker.core.InvalidReferenceException
+import freemarker.template.Template
+import freemarker.template.TemplateException
+import freemarker.template.TemplateExceptionHandler
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import org.apache.commons.io.IOUtils
@@ -233,7 +237,7 @@ class ConfigurationApiImplTest extends Specification {
httpServer {
handlers {
prefix(path) {
- def expectedRequestBody = CiVisibilityTestUtils.getFreemarkerTemplate(requestTemplate, requestData)
+ def expectedRequestBody = getFreemarkerTemplate(requestTemplate, requestData)
def response = response
try {
@@ -242,7 +246,7 @@ class ConfigurationApiImplTest extends Specification {
response.status(400).send(error.getMessage().bytes)
}
- def responseBody = CiVisibilityTestUtils.getFreemarkerTemplate(responseTemplate, responseData).bytes
+ def responseBody = getFreemarkerTemplate(responseTemplate, responseData).bytes
def header = request.getHeader("Accept-Encoding")
def gzipSupported = header != null && header.contains("gzip")
if (gzipSupported) {
@@ -315,4 +319,37 @@ class ConfigurationApiImplTest extends Specification {
}
return bitSet
}
+
+ static final TemplateExceptionHandler SUPPRESS_EXCEPTION_HANDLER = new TemplateExceptionHandler() {
+ @Override
+ void handleTemplateException(TemplateException e, Environment environment, Writer writer) throws TemplateException {
+ if (e instanceof InvalidReferenceException) {
+ writer.write('""')
+ } else {
+ throw e
+ }
+ }
+ }
+
+ static final freemarker.template.Configuration FREEMARKER = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_30) { {
+ setClassLoaderForTemplateLoading(ConfigurationApiImplTest.classLoader, "")
+ setDefaultEncoding("UTF-8")
+ setTemplateExceptionHandler(SUPPRESS_EXCEPTION_HANDLER)
+ setLogTemplateExceptions(false)
+ setWrapUncheckedExceptions(true)
+ setFallbackOnNullLoopVariable(false)
+ setNumberFormat("0.######")
+ }
+ }
+
+ static String getFreemarkerTemplate(String templatePath, Map replacements, List