diff --git a/.circleci/config.continue.yml.j2 b/.circleci/config.continue.yml.j2 index a77a3021ad2..49d07ff39f0 100644 --- a/.circleci/config.continue.yml.j2 +++ b/.circleci/config.continue.yml.j2 @@ -36,7 +36,7 @@ instrumentation_modules: &instrumentation_modules "dd-java-agent/instrumentation debugger_modules: &debugger_modules "dd-java-agent/agent-debugger|dd-java-agent/agent-bootstrap|dd-java-agent/agent-builder|internal-api|communication|dd-trace-core" profiling_modules: &profiling_modules "dd-java-agent/agent-profiling" -default_system_tests_commit: &default_system_tests_commit 55cc62fb333b8de1466f8a0ecfdfa55fe9f57031 +default_system_tests_commit: &default_system_tests_commit 2799fa982318da14c9d3e5f722abdc670d2802c3 parameters: nightly: diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3cf080e8154..5983b5d0bd2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,24 +17,26 @@ dd-java-agent/agent-bootstrap/src/main/java11/datadog/trace/bootstrap/instrument dd-smoke-tests/profiling-integration-tests/ @DataDog/profiling-java # @DataDog/ci-app-libraries-java -dd-java-agent/agent-ci-visibility/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/cucumber/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/jacoco/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/junit-4.10/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/junit-5.3/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/karate/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/scalatest/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/selenium/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/testng/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/gradle-3.0/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/gradle-8.3/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/maven-3.2.1/ @DataDog/ci-app-libraries-java -dd-java-agent/instrumentation/weaver/ @DataDog/ci-app-libraries-java -dd-smoke-tests/gradle/ @DataDog/ci-app-libraries-java -dd-smoke-tests/maven/ @DataDog/ci-app-libraries-java -**/civisibility/ @DataDog/ci-app-libraries-java -**/CiVisibility*.java @DataDog/ci-app-libraries-java -**/CiVisibility*.groovy @DataDog/ci-app-libraries-java +dd-java-agent/agent-ci-visibility/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/cucumber/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/jacoco/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/junit-4.10/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/junit-5.3/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/karate/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/scalatest/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/selenium/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/testng/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/gradle-3.0/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/gradle-8.3/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/gradle-testing/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/maven-3.2.1/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/maven-surefire/ @DataDog/ci-app-libraries-java +dd-java-agent/instrumentation/weaver/ @DataDog/ci-app-libraries-java +dd-smoke-tests/gradle/ @DataDog/ci-app-libraries-java +dd-smoke-tests/maven/ @DataDog/ci-app-libraries-java +**/civisibility/ @DataDog/ci-app-libraries-java +**/CiVisibility*.java @DataDog/ci-app-libraries-java +**/CiVisibility*.groovy @DataDog/ci-app-libraries-java # @DataDog/debugger-java (Live Debugger) dd-java-agent/agent-debugger/ @DataDog/debugger-java diff --git a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy index 65d75d1507c..609f1e41728 100644 --- a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityInstrumentationTest.groovy @@ -388,11 +388,7 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { TEST_WRITER.waitForTraces(expectedOrder.size() + 1) def traces = TEST_WRITER.toList() def events = getEventsAsJson(traces) - def identifiers = getTestIdentifiers(events) - if (identifiers != expectedOrder) { - throw new AssertionError("Expected order: $expectedOrder, but got: $identifiers") - } - return true + return CiVisibilityTestUtils.assertTestsOrder(events, expectedOrder) } def assertCapabilities(Collection capabilities, int expectedTraceCount) { @@ -411,17 +407,6 @@ abstract class CiVisibilityInstrumentationTest extends AgentTestRunner { return true } - def getTestIdentifiers(List events) { - events.sort(Comparator.comparing { it['content']['start'] as Long }) - def testIdentifiers = [] - for (Map event : events) { - if (event['content']['meta']['test.name']) { - testIdentifiers.add(test(event['content']['meta']['test.suite'] as String, event['content']['meta']['test.name'] as String)) - } - } - return testIdentifiers - } - def test(String suite, String name) { return new TestFQN(suite, name) } diff --git a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy index 86eceed7f64..9cfcc134d87 100644 --- a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy +++ b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilitySmokeTest.groovy @@ -1,6 +1,6 @@ package datadog.trace.civisibility - +import datadog.trace.api.civisibility.config.TestFQN import spock.lang.Specification abstract class CiVisibilitySmokeTest extends Specification { @@ -16,6 +16,14 @@ abstract class CiVisibilitySmokeTest extends Specification { } } + protected test(String suiteName, String testName) { + return new TestFQN(suiteName, testName) + } + + protected verifyTestOrder(List> events, List expectedOrder) { + CiVisibilityTestUtils.assertTestsOrder(events, expectedOrder) + } + /** * This is a basic sanity check for telemetry metrics. * It only checks that the reported number of events created and finished is as expected. diff --git a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy index b07295bc4c4..1a513d080e7 100644 --- a/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy +++ b/dd-java-agent/agent-ci-visibility/src/testFixtures/groovy/datadog/trace/civisibility/CiVisibilityTestUtils.groovy @@ -9,6 +9,7 @@ import com.jayway.jsonpath.ReadContext import com.jayway.jsonpath.WriteContext import datadog.trace.api.DDSpanTypes import datadog.trace.api.civisibility.config.LibraryCapability +import datadog.trace.api.civisibility.config.TestFQN import datadog.trace.core.DDSpan import freemarker.core.Environment import freemarker.core.InvalidReferenceException @@ -136,6 +137,25 @@ abstract class CiVisibilityTestUtils { return replacementMap } + static boolean assertTestsOrder(List> events, List expectedOrder) { + def identifiers = getTestIdentifiers(events) + if (identifiers != expectedOrder) { + throw new AssertionError("Expected order: $expectedOrder, but got: $identifiers") + } + return true + } + + static List getTestIdentifiers(List> events) { + events.sort(Comparator.comparing { it['content']['start'] as Long }) + def testIdentifiers = [] + for (Map event : events) { + if (event['content']['meta']['test.name']) { + testIdentifiers.add(new TestFQN(event['content']['meta']['test.suite'] as String, event['content']['meta']['test.name'] as String)) + } + } + return testIdentifiers + } + static List> removeTags(List> events, List tags) { def filteredEvents = [] diff --git a/dd-java-agent/instrumentation/gradle-testing/build.gradle b/dd-java-agent/instrumentation/gradle-testing/build.gradle new file mode 100644 index 00000000000..0d40b85c753 --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-testing/build.gradle @@ -0,0 +1,17 @@ +apply from: "$rootDir/gradle/java.gradle" + +repositories { + maven { + url "https://repo.gradle.org/artifactory/libs-releases-local" + } +} + +// gradle >= v5.1 +dependencies { + compileOnly gradleApi() + compileOnly project(":dd-java-agent:instrumentation:junit-4.10") +} + +forbiddenApisMain { + failOnMissingClasses = false +} diff --git a/dd-java-agent/instrumentation/gradle-testing/gradle.lockfile b/dd-java-agent/instrumentation/gradle-testing/gradle.lockfile new file mode 100644 index 00000000000..90493a88f9c --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-testing/gradle.lockfile @@ -0,0 +1,156 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +cafe.cryptography:curve25519-elisabeth:0.1.0=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +cafe.cryptography:ed25519-elisabeth:0.1.0=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +ch.qos.logback:logback-classic:1.2.3=testCompileClasspath,testRuntimeClasspath +ch.qos.logback:logback-core:1.2.3=testCompileClasspath,testRuntimeClasspath +com.beust:jcommander:1.78=testRuntimeClasspath +com.blogspot.mydailyjava:weak-lock-free:0.17=compileClasspath,instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okhttp3:okhttp:3.12.15=compileClasspath,instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okio:okio:1.17.6=compileClasspath,instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:dd-javac-plugin-client:0.2.2=compileClasspath,instrumentPluginClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:java-dogstatsd-client:4.4.3=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.datadoghq:sketches-java:0.8.3=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.javaparser:javaparser-core:3.25.1=testCompileClasspath,testRuntimeClasspath +com.github.jnr:jffi:1.3.13=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-a64asm:1.0.0=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-constants:0.10.4=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-enxio:0.32.17=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-ffi:2.2.16=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-posix:3.1.19=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-unixsocket:0.38.22=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-x86asm:1.0.2=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.2.0=compileClasspath,testCompileClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.7.3=spotbugs +com.github.spotbugs:spotbugs:4.7.3=spotbugs +com.github.stefanbirkner:system-rules:1.19.0=testCompileClasspath,testRuntimeClasspath +com.google.auto.service:auto-service-annotations:1.0-rc7=annotationProcessor,compileClasspath,testAnnotationProcessor,testCompileClasspath +com.google.auto.service:auto-service:1.0-rc7=annotationProcessor,testAnnotationProcessor +com.google.auto:auto-common:0.10=annotationProcessor,testAnnotationProcessor +com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath +com.google.code.gson:gson:2.9.1=spotbugs +com.google.errorprone:error_prone_annotations:2.2.0=annotationProcessor,testAnnotationProcessor +com.google.guava:failureaccess:1.0.1=annotationProcessor,testAnnotationProcessor +com.google.guava:guava:20.0=testCompileClasspath,testRuntimeClasspath +com.google.guava:guava:27.0.1-jre=annotationProcessor,testAnnotationProcessor +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,testAnnotationProcessor +com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,testAnnotationProcessor +com.google.re2j:re2j:1.7=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.squareup.moshi:moshi:1.11.0=compileClasspath,instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:logging-interceptor:3.12.12=testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:okhttp:3.12.12=testCompileClasspath,testRuntimeClasspath +com.squareup.okio:okio:1.17.5=compileClasspath,instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.thoughtworks.qdox:qdox:1.12.1=testRuntimeClasspath +commons-codec:commons-codec:1.15=spotbugs +commons-fileupload:commons-fileupload:1.5=testCompileClasspath,testRuntimeClasspath +commons-io:commons-io:2.11.0=testCompileClasspath,testRuntimeClasspath +de.thetaphi:forbiddenapis:3.8=compileClasspath +info.picocli:picocli:4.6.3=testRuntimeClasspath +io.sqreen:libsqreen:12.0.0=testRuntimeClasspath +javax.servlet:javax.servlet-api:3.1.0=testCompileClasspath,testRuntimeClasspath +jaxen:jaxen:1.2.0=spotbugs +jline:jline:2.14.6=testRuntimeClasspath +junit:junit-dep:4.11=testCompileClasspath,testRuntimeClasspath +junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.14.18=compileClasspath,instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy:1.14.18=compileClasspath,instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.java.dev.jna:jna-platform:5.8.0=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.java.dev.jna:jna:5.8.0=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.jcip:jcip-annotations:1.0=compileClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath +net.sf.saxon:Saxon-HE:11.4=spotbugs +org.apache.ant:ant-antlr:1.10.12=testRuntimeClasspath +org.apache.ant:ant-antlr:1.9.15=codenarc +org.apache.ant:ant-junit:1.10.12=testRuntimeClasspath +org.apache.ant:ant-junit:1.9.15=codenarc +org.apache.ant:ant-launcher:1.10.12=testRuntimeClasspath +org.apache.ant:ant:1.10.12=testCompileClasspath,testRuntimeClasspath +org.apache.bcel:bcel:6.5.0=spotbugs +org.apache.commons:commons-lang3:3.12.0=spotbugs +org.apache.commons:commons-text:1.10.0=spotbugs +org.apache.httpcomponents.client5:httpclient5:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5-h2:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5:5.1.3=spotbugs +org.apache.logging.log4j:log4j-api:2.19.0=spotbugs +org.apache.logging.log4j:log4j-core:2.19.0=spotbugs +org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath +org.checkerframework:checker-qual:2.5.2=annotationProcessor,testAnnotationProcessor +org.codehaus.groovy:groovy-all:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-ant:2.5.14=codenarc +org.codehaus.groovy:groovy-ant:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-astbuilder:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-cli-picocli:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-console:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-datetime:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-docgenerator:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovydoc:2.5.14=codenarc +org.codehaus.groovy:groovy-groovydoc:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovysh:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jmx:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-json:2.5.14=codenarc +org.codehaus.groovy:groovy-json:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jsr223:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-macro:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-nio:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-servlet:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-sql:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-swing:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-templates:2.5.14=codenarc +org.codehaus.groovy:groovy-templates:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test-junit5:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-testng:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-xml:2.5.14=codenarc +org.codehaus.groovy:groovy-xml:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy:2.5.14=codenarc +org.codehaus.groovy:groovy:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,testAnnotationProcessor +org.codenarc:CodeNarc:2.2.0=codenarc +org.dom4j:dom4j:2.1.3=spotbugs +org.eclipse.jetty:jetty-http:9.4.56.v20240826=testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-io:9.4.56.v20240826=testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-server:9.4.56.v20240826=testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-util:9.4.56.v20240826=testCompileClasspath,testRuntimeClasspath +org.gmetrics:GMetrics:1.1=codenarc +org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath +org.hamcrest:hamcrest:2.2=testCompileClasspath,testRuntimeClasspath +org.jctools:jctools-core:3.3.0=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-api:5.9.2=testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-engine:5.9.2=testRuntimeClasspath +org.junit.platform:junit-platform-commons:1.9.2=testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-engine:1.9.2=testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.9.2=testRuntimeClasspath +org.junit.platform:junit-platform-runner:1.9.2=testRuntimeClasspath +org.junit.platform:junit-platform-suite-api:1.9.2=testRuntimeClasspath +org.junit.platform:junit-platform-suite-commons:1.9.2=testRuntimeClasspath +org.junit:junit-bom:5.9.1=spotbugs +org.junit:junit-bom:5.9.2=testCompileClasspath,testRuntimeClasspath +org.objenesis:objenesis:3.3=testCompileClasspath,testRuntimeClasspath +org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.2=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.4=spotbugs +org.ow2.asm:asm-commons:9.2=instrumentPluginClasspath,muzzleTooling,runtimeClasspath +org.ow2.asm:asm-commons:9.4=spotbugs +org.ow2.asm:asm-commons:9.7.1=testRuntimeClasspath +org.ow2.asm:asm-tree:9.2=instrumentPluginClasspath,muzzleTooling,runtimeClasspath +org.ow2.asm:asm-tree:9.4=spotbugs +org.ow2.asm:asm-tree:9.7.1=testRuntimeClasspath +org.ow2.asm:asm-util:9.2=instrumentPluginClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-util:9.4=spotbugs +org.ow2.asm:asm:9.2=instrumentPluginClasspath,muzzleTooling,runtimeClasspath +org.ow2.asm:asm:9.4=spotbugs +org.ow2.asm:asm:9.7.1=testRuntimeClasspath +org.slf4j:jcl-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath +org.slf4j:jul-to-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath +org.slf4j:log4j-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:1.7.30=compileClasspath,instrumentPluginClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath +org.slf4j:slf4j-api:1.7.32=testRuntimeClasspath +org.slf4j:slf4j-api:2.0.0=spotbugs,spotbugsSlf4j +org.slf4j:slf4j-simple:2.0.0=spotbugsSlf4j +org.spockframework:spock-core:2.2-groovy-3.0=testCompileClasspath,testRuntimeClasspath +org.spockframework:spock-junit4:2.2-groovy-3.0=testCompileClasspath,testRuntimeClasspath +org.testng:testng:7.5=testRuntimeClasspath +org.webjars:jquery:3.5.1=testRuntimeClasspath +org.xmlresolver:xmlresolver:4.4.3=spotbugs +xml-apis:xml-apis:1.4.01=spotbugs +empty=spotbugsPlugins diff --git a/dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java b/dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java new file mode 100644 index 00000000000..04ef0cd181b --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java @@ -0,0 +1,74 @@ +package datadog.trace.instrumentation.gradle.junit4; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.Config; +import datadog.trace.api.civisibility.CIConstants; +import datadog.trace.instrumentation.junit4.JUnit4Instrumentation; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import org.gradle.api.Action; +import org.gradle.internal.actor.Actor; + +@AutoService(InstrumenterModule.class) +public class AbstractJUnitTestClassProcessorInstrumentation extends InstrumenterModule.CiVisibility + implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { + public AbstractJUnitTestClassProcessorInstrumentation() { + super("ci-visibility", "gradle", "junit4"); + } + + @Override + public boolean isApplicable(Set enabledSystems) { + return super.isApplicable(enabledSystems) && Config.get().getCiVisibilityTestOrder() != null; + } + + @Override + public String instrumentedType() { + return "org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor"; + } + + @Override + public String[] helperClassNames() { + return new String[] { + JUnit4Instrumentation.class.getPackage().getName() + ".SkippedByDatadog", + JUnit4Instrumentation.class.getPackage().getName() + ".JUnit4Utils", + JUnit4Instrumentation.class.getPackage().getName() + ".TestEventsHandlerHolder", + JUnit4Instrumentation.class.getPackage().getName() + ".TracingListener", + JUnit4Instrumentation.class.getPackage().getName() + ".order.JUnit4FailFastClassOrderer", + packageName + ".DDCollectAllTestClassesExecutor", + }; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + named("stop"), + AbstractJUnitTestClassProcessorInstrumentation.class.getName() + + "$ProcessAllTestClassesAdvice"); + } + + @Override + public String muzzleDirective() { + return "skipMuzzle"; + } + + public static class ProcessAllTestClassesAdvice { + @SuppressWarnings("bytebuddy-exception-suppression") + @Advice.OnMethodEnter + public static void onStop( + @Advice.FieldValue(value = "executor") final Action executor, + @Advice.FieldValue(value = "resultProcessorActor") final Actor resultProcessorActor) { + String testOrder = Config.get().getCiVisibilityTestOrder(); + if (!CIConstants.FAIL_FAST_TEST_ORDER.equalsIgnoreCase(testOrder)) { + throw new IllegalArgumentException("Unknown test order: " + testOrder); + } + + if (executor instanceof DDCollectAllTestClassesExecutor) { + ((DDCollectAllTestClassesExecutor) executor).processAllTestClasses(); + } + } + } +} diff --git a/dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java b/dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java new file mode 100644 index 00000000000..7648ae06e1b --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java @@ -0,0 +1,58 @@ +package datadog.trace.instrumentation.gradle.junit4; + +import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation; +import datadog.trace.instrumentation.junit4.JUnit4Utils; +import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder; +import datadog.trace.instrumentation.junit4.order.JUnit4FailFastClassOrderer; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import org.gradle.api.Action; +import org.gradle.internal.UncheckedException; + +/** + * Based on JUnitPlatformTestClassProcessor {@link + * org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor}. Collects + * all test classes to order them before execution. + */ +public class DDCollectAllTestClassesExecutor implements Action { + private final List> testClasses = new ArrayList<>(); + private final Action delegate; + private final ClassLoader classLoader; + + public DDCollectAllTestClassesExecutor(Action delegate, ClassLoader junitClassLoader) { + this.delegate = delegate; + this.classLoader = junitClassLoader; + } + + @Override + public void execute(@Nonnull String testClassName) { + Class clazz = loadClass(testClassName); + + TestFrameworkInstrumentation framework = JUnit4Utils.classToFramework(clazz); + if (framework == TestFrameworkInstrumentation.JUNIT4) { + TestEventsHandlerHolder.start( + TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.capabilities(true)); + } + + testClasses.add(clazz); + } + + public void processAllTestClasses() { + testClasses.sort( + new JUnit4FailFastClassOrderer( + TestEventsHandlerHolder.HANDLERS.get(TestFrameworkInstrumentation.JUNIT4))); + + for (Class clazz : testClasses) { + delegate.execute(clazz.getName()); + } + } + + private Class loadClass(String testClassName) { + try { + return Class.forName(testClassName, false, classLoader); + } catch (ClassNotFoundException e) { + throw UncheckedException.throwAsUncheckedException(e); + } + } +} diff --git a/dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java b/dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java new file mode 100644 index 00000000000..4b38d3151b9 --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java @@ -0,0 +1,75 @@ +package datadog.trace.instrumentation.gradle.junit4; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.returns; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.Config; +import datadog.trace.api.civisibility.CIConstants; +import datadog.trace.instrumentation.junit4.JUnit4Instrumentation; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import org.gradle.api.Action; + +@AutoService(InstrumenterModule.class) +public class JUnitTestClassProcessorInstrumentation extends InstrumenterModule.CiVisibility + implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { + public JUnitTestClassProcessorInstrumentation() { + super("ci-visibility", "gradle", "junit4"); + } + + @Override + public boolean isApplicable(Set enabledSystems) { + return super.isApplicable(enabledSystems) && Config.get().getCiVisibilityTestOrder() != null; + } + + @Override + public String instrumentedType() { + return "org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor"; + } + + @Override + public String[] helperClassNames() { + return new String[] { + JUnit4Instrumentation.class.getPackage().getName() + ".JUnit4Utils", + JUnit4Instrumentation.class.getPackage().getName() + ".TestEventsHandlerHolder", + JUnit4Instrumentation.class.getPackage().getName() + ".SkippedByDatadog", + JUnit4Instrumentation.class.getPackage().getName() + ".TracingListener", + JUnit4Instrumentation.class.getPackage().getName() + ".order.JUnit4FailFastClassOrderer", + packageName + ".DDCollectAllTestClassesExecutor", + }; + } + + @Override + public String muzzleDirective() { + return "skipMuzzle"; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + named("createTestExecutor") + .and(takesArgument(0, named("org.gradle.internal.actor.Actor"))) + .and(returns(named("org.gradle.api.Action"))), + JUnitTestClassProcessorInstrumentation.class.getName() + "$TestExecutorAdvice"); + } + + public static class TestExecutorAdvice { + @SuppressWarnings("bytebuddy-exception-suppression") + @Advice.OnMethodExit + public static void onTestExecutorCreation( + @Advice.Return(readOnly = false) Action executor) { + String testOrder = Config.get().getCiVisibilityTestOrder(); + if (!CIConstants.FAIL_FAST_TEST_ORDER.equalsIgnoreCase(testOrder)) { + throw new IllegalArgumentException("Unknown test order: " + testOrder); + } + + executor = + new DDCollectAllTestClassesExecutor( + executor, Thread.currentThread().getContextClassLoader()); + } + } +} diff --git a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/FailFastDescriptionComparator.java b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/FailFastDescriptionComparator.java new file mode 100644 index 00000000000..50741f60564 --- /dev/null +++ b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/FailFastDescriptionComparator.java @@ -0,0 +1,31 @@ +package datadog.trace.instrumentation.junit4.order; + +import datadog.trace.api.civisibility.config.TestIdentifier; +import datadog.trace.api.civisibility.config.TestSourceData; +import datadog.trace.api.civisibility.events.TestDescriptor; +import datadog.trace.api.civisibility.events.TestEventsHandler; +import datadog.trace.api.civisibility.events.TestSuiteDescriptor; +import datadog.trace.instrumentation.junit4.JUnit4Utils; +import java.util.Comparator; +import org.junit.runner.Description; + +public class FailFastDescriptionComparator implements Comparator { + + private final TestEventsHandler handler; + + public FailFastDescriptionComparator( + TestEventsHandler handler) { + this.handler = handler; + } + + private int executionPriority(Description description) { + TestIdentifier testIdentifier = JUnit4Utils.toTestIdentifier(description); + TestSourceData testSourceData = JUnit4Utils.toTestSourceData(description); + return handler.executionPriority(testIdentifier, testSourceData); + } + + @Override + public int compare(Description o1, Description o2) { + return executionPriority(o2) - executionPriority(o1); + } +} diff --git a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4TestOrdererInstrumentation.java b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4TestOrdererInstrumentation.java new file mode 100644 index 00000000000..e871fd9bb92 --- /dev/null +++ b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4TestOrdererInstrumentation.java @@ -0,0 +1,80 @@ +package datadog.trace.instrumentation.junit4.order; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.Config; +import datadog.trace.api.civisibility.CIConstants; +import datadog.trace.api.civisibility.events.TestDescriptor; +import datadog.trace.api.civisibility.events.TestEventsHandler; +import datadog.trace.api.civisibility.events.TestSuiteDescriptor; +import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation; +import datadog.trace.instrumentation.junit4.JUnit4Instrumentation; +import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder; +import datadog.trace.util.Strings; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import org.junit.runner.Description; + +@AutoService(InstrumenterModule.class) +public class JUnit4TestOrdererInstrumentation extends InstrumenterModule.CiVisibility + implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { + private final String parentPackageName = + Strings.getPackageName(JUnit4Instrumentation.class.getName()); + + public JUnit4TestOrdererInstrumentation() { + super("ci-visibility", "junit-4", "test-order"); + } + + @Override + public boolean isApplicable(Set enabledSystems) { + return super.isApplicable(enabledSystems) && Config.get().getCiVisibilityTestOrder() != null; + } + + @Override + public String instrumentedType() { + return "org.junit.runner.manipulation.Orderer"; + } + + @Override + public String[] helperClassNames() { + return new String[] { + parentPackageName + ".SkippedByDatadog", + parentPackageName + ".TracingListener", + parentPackageName + ".JUnit4Utils", + parentPackageName + ".TestEventsHandlerHolder", + packageName + ".FailFastDescriptionComparator", + }; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + named("order"), JUnit4TestOrdererInstrumentation.class.getName() + "$OrderAdvice"); + } + + public static class OrderAdvice { + @SuppressFBWarnings( + value = "UC_USELESS_OBJECT", + justification = "descriptions is the return value of the instrumented method") + @Advice.OnMethodExit + public static void onOrdering(@Advice.Return(readOnly = false) List descriptions) { + String testOrder = Config.get().getCiVisibilityTestOrder(); + TestEventsHandler handler = + TestEventsHandlerHolder.HANDLERS.get(TestFrameworkInstrumentation.JUNIT4); + if (CIConstants.FAIL_FAST_TEST_ORDER.equalsIgnoreCase(testOrder) && handler != null) { + // sort descriptions after the user's sorting method (if any) has been applied + List sorted = new ArrayList(descriptions); + sorted.sort(new FailFastDescriptionComparator(handler)); + descriptions = sorted; + } else { + throw new IllegalArgumentException("Unknown test order: " + testOrder); + } + } + } +} diff --git a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4TestSorterInstrumentation.java b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4TestSorterInstrumentation.java new file mode 100644 index 00000000000..d0d52f689eb --- /dev/null +++ b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4TestSorterInstrumentation.java @@ -0,0 +1,84 @@ +package datadog.trace.instrumentation.junit4.order; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.extendsClass; +import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.implementsInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.Config; +import datadog.trace.api.civisibility.CIConstants; +import datadog.trace.api.civisibility.events.TestDescriptor; +import datadog.trace.api.civisibility.events.TestEventsHandler; +import datadog.trace.api.civisibility.events.TestSuiteDescriptor; +import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation; +import datadog.trace.instrumentation.junit4.JUnit4Instrumentation; +import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder; +import datadog.trace.util.Strings; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.junit.runner.manipulation.Sorter; + +@AutoService(InstrumenterModule.class) +public class JUnit4TestSorterInstrumentation extends InstrumenterModule.CiVisibility + implements Instrumenter.ForTypeHierarchy, Instrumenter.HasMethodAdvice { + private final String parentPackageName = + Strings.getPackageName(JUnit4Instrumentation.class.getName()); + + public JUnit4TestSorterInstrumentation() { + super("ci-visibility", "junit-4", "test-order"); + } + + @Override + public boolean isApplicable(Set enabledSystems) { + return super.isApplicable(enabledSystems) && Config.get().getCiVisibilityTestOrder() != null; + } + + @Override + public String hierarchyMarkerType() { + return "org.junit.runner.Runner"; + } + + @Override + public ElementMatcher hierarchyMatcher() { + return extendsClass(named(hierarchyMarkerType())) + .and(implementsInterface(named("org.junit.runner.manipulation.Sortable"))); + } + + @Override + public String[] helperClassNames() { + return new String[] { + parentPackageName + ".SkippedByDatadog", + parentPackageName + ".TracingListener", + parentPackageName + ".JUnit4Utils", + parentPackageName + ".TestEventsHandlerHolder", + packageName + ".FailFastDescriptionComparator", + }; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + named("sort").and(takesArgument(0, named("org.junit.runner.manipulation.Sorter"))), + JUnit4TestSorterInstrumentation.class.getName() + "$SorterAdvice"); + } + + public static class SorterAdvice { + @Advice.OnMethodEnter + public static void onOrdering(@Advice.Argument(value = 0, readOnly = false) Sorter sorter) { + String testOrder = Config.get().getCiVisibilityTestOrder(); + TestEventsHandler handler = + TestEventsHandlerHolder.HANDLERS.get(TestFrameworkInstrumentation.JUNIT4); + if (CIConstants.FAIL_FAST_TEST_ORDER.equalsIgnoreCase(testOrder) && handler != null) { + // use sorter provided when elements are equal (same execution priority) + sorter = new Sorter(new FailFastDescriptionComparator(handler).thenComparing(sorter)); + } else { + throw new IllegalArgumentException("Unknown test order: " + testOrder); + } + } + } +} diff --git a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/groovy/JUnit413Test.groovy b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/groovy/JUnit413Test.groovy index ed5a06b4ab9..993b48576e0 100644 --- a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/groovy/JUnit413Test.groovy +++ b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/groovy/JUnit413Test.groovy @@ -1,18 +1,22 @@ import datadog.trace.api.DisableTestTrace +import datadog.trace.api.civisibility.config.LibraryCapability import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation import datadog.trace.civisibility.CiVisibilityInstrumentationTest import datadog.trace.instrumentation.junit4.JUnit4Utils import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder -import junit.runner.Version import org.example.TestFailedAfter import org.example.TestFailedAfterClass import org.example.TestFailedAfterParam import org.example.TestFailedBefore import org.example.TestFailedBeforeClass import org.example.TestFailedBeforeParam +import org.example.TestOrderer +import org.example.TestSorter +import org.example.TestSucceed import org.example.TestSucceedBeforeAfter import org.example.TestSucceedBeforeClassAfterClass import org.example.TestSucceedBeforeParamAfterParam +import org.junit.jupiter.api.Assumptions import org.junit.runner.JUnitCore @DisableTestTrace(reason = "avoid self-tracing") @@ -38,8 +42,65 @@ class JUnit413Test extends CiVisibilityInstrumentationTest { "test-failed-after-param" | false | [TestFailedAfterParam] } + def "test known tests ordering #testcaseName"() { + givenKnownTests(knownTestsList) + + runTests(tests) + + assertTestsOrder(expectedOrder) + + where: + testcaseName | tests | knownTestsList | expectedOrder + "sorting-methods" | [TestSorter] | [test("org.example.TestSorter", "test_succeed_1")] | [ + test("org.example.TestSorter", "test_succeed_2"), + test("org.example.TestSorter", "test_succeed_3"), + test("org.example.TestSorter", "test_succeed_1") + ] + "ordering-methods" | [TestOrderer] | [test("org.example.TestOrderer", "test_succeed_2")] | [ + test("org.example.TestOrderer", "test_succeed_3"), + test("org.example.TestOrderer", "test_succeed_1"), + test("org.example.TestOrderer", "test_succeed_2") + ] + } + + def "test flaky tests ordering #testcaseName"() { + givenKnownTests(expectedOrder) + givenFlakyTests(flakyTestList) + + runTests(tests) + + assertTestsOrder(expectedOrder) + + where: + testcaseName | tests | flakyTestList | expectedOrder + "sorting-methods" | [TestSorter] | [test("org.example.TestSorter", "test_succeed_2"), test("org.example.TestSorter", "test_succeed_3")] | [ + test("org.example.TestSorter", "test_succeed_2"), + test("org.example.TestSorter", "test_succeed_3"), + test("org.example.TestSorter", "test_succeed_1") + ] + "ordering-methods" | [TestOrderer] | [ + test("org.example.TestOrderer", "test_succeed_1"), + test("org.example.TestOrderer", "test_succeed_3") + ] | [ + test("org.example.TestOrderer", "test_succeed_3"), + test("org.example.TestOrderer", "test_succeed_1"), + test("org.example.TestOrderer", "test_succeed_2") + ] + } + + def "test capabilities tagging #testcaseName"() { + setup: + Assumptions.assumeTrue(JUnit4Utils.isTestOrderingSupported(JUnit4Utils.getVersion())) + runTests([TestSucceed], true) + def capabilities = new ArrayList<>(JUnit4Utils.BASE_CAPABILITIES) + capabilities.add(LibraryCapability.FAIL_FAST) + + expect: + assertCapabilities(capabilities, 4) + } + private void runTests(Collection> tests, boolean expectSuccess = true) { - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.CAPABILITIES) + TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.capabilities(false)) try { Class[] array = tests.toArray(new Class[0]) def result = runner.run(array) @@ -64,6 +125,6 @@ class JUnit413Test extends CiVisibilityInstrumentationTest { @Override String instrumentedLibraryVersion() { - return Version.id() + return JUnit4Utils.getVersion() } } diff --git a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/ReverseAlphanumeric.java b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/ReverseAlphanumeric.java new file mode 100644 index 00000000000..52cddefe9e2 --- /dev/null +++ b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/ReverseAlphanumeric.java @@ -0,0 +1,27 @@ +package org.example; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import org.junit.runner.Description; +import org.junit.runner.manipulation.Ordering; + +public class ReverseAlphanumeric implements Ordering.Factory { + private static final Comparator COMPARATOR = + (o1, o2) -> o2.getDisplayName().compareTo(o1.getDisplayName()); + + public static class ReverseAlphanumericOrdering extends Ordering { + @Override + public List orderItems(Collection descriptions) { + List sorted = new ArrayList<>(descriptions); + sorted.sort(COMPARATOR); + return sorted; + } + } + + @Override + public Ordering create(Ordering.Context context) { + return new ReverseAlphanumericOrdering(); + } +} diff --git a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestOrderer.java b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestOrderer.java new file mode 100644 index 00000000000..d49929d26c0 --- /dev/null +++ b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestOrderer.java @@ -0,0 +1,24 @@ +package org.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.OrderWith; + +@OrderWith(ReverseAlphanumeric.class) +public class TestOrderer { + @Test + public void test_succeed_1() { + assertTrue(true); + } + + @Test + public void test_succeed_2() { + assertTrue(true); + } + + @Test + public void test_succeed_3() { + assertTrue(true); + } +} diff --git a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestSorter.java b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestSorter.java new file mode 100644 index 00000000000..f1b9dff833a --- /dev/null +++ b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestSorter.java @@ -0,0 +1,25 @@ +package org.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.OrderWith; +import org.junit.runner.manipulation.Alphanumeric; + +@OrderWith(Alphanumeric.class) +public class TestSorter { + @Test + public void test_succeed_1() { + assertTrue(true); + } + + @Test + public void test_succeed_2() { + assertTrue(true); + } + + @Test + public void test_succeed_3() { + assertTrue(true); + } +} diff --git a/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestSucceed.java b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestSucceed.java new file mode 100644 index 00000000000..9fcd9017ac3 --- /dev/null +++ b/dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestSucceed.java @@ -0,0 +1,13 @@ +package org.example; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class TestSucceed { + + @Test + public void test_succeed() { + assertTrue(true); + } +} diff --git a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Instrumentation.java b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Instrumentation.java index 02786479793..dec5a8b7d16 100644 --- a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Instrumentation.java +++ b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Instrumentation.java @@ -3,6 +3,7 @@ import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.extendsClass; import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.implementsInterface; import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -81,19 +82,33 @@ public Map contextStore() { @Override public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + isConstructor(), JUnit4Instrumentation.class.getName() + "$HandlerAdvice"); transformer.applyAdvice( named("run").and(takesArgument(0, named("org.junit.runner.notification.RunNotifier"))), JUnit4Instrumentation.class.getName() + "$JUnit4Advice"); } + public static class HandlerAdvice { + @Advice.OnMethodExit + public static void onRunnerCreation(@Advice.This final Runner runner) { + if (!JUnit4Utils.runnerToFramework(runner).equals(TestFrameworkInstrumentation.JUNIT4)) { + // checking class names in hierarchyMatcher alone is not enough: + // for example, Karate calls #run method of its super class, + // that was transformed + return; + } + + TestEventsHandlerHolder.start( + TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.capabilities(false)); + } + } + public static class JUnit4Advice { @Advice.OnMethodEnter(suppress = Throwable.class) public static void addTracingListener( @Advice.This final Runner runner, @Advice.Argument(0) final RunNotifier runNotifier) { - String runnerClassName = runner.getClass().getName(); - if ("datadog.trace.agent.test.SpockRunner".equals(runnerClassName) - || runnerClassName.startsWith("com.intuit.karate") - || runnerClassName.startsWith("io.cucumber")) { + if (!JUnit4Utils.runnerToFramework(runner).equals(TestFrameworkInstrumentation.JUNIT4)) { // checking class names in hierarchyMatcher alone is not enough: // for example, Karate calls #run method of its super class, // that was transformed @@ -115,8 +130,6 @@ public static void addTracingListener( } } - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.CAPABILITIES); - final TracingListener tracingListener = new JUnit4TracingListener( InstrumentationContext.get(Description.class, TestExecutionHistory.class)); diff --git a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4TracingListener.java b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4TracingListener.java index 90a04b81fdc..5adf3795e45 100644 --- a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4TracingListener.java +++ b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4TracingListener.java @@ -8,7 +8,6 @@ import datadog.trace.bootstrap.ContextStore; import java.lang.reflect.Method; import java.util.List; -import junit.runner.Version; import org.junit.Ignore; import org.junit.runner.Description; import org.junit.runner.notification.Failure; @@ -16,7 +15,7 @@ public class JUnit4TracingListener extends TracingListener { private static final String FRAMEWORK_NAME = "junit4"; - private static final String FRAMEWORK_VERSION = Version.id(); + private static final String FRAMEWORK_VERSION = JUnit4Utils.getVersion(); private final ContextStore executionHistories; diff --git a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Utils.java b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Utils.java index c2213e2fa13..8d3d3c18bd0 100644 --- a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Utils.java +++ b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/JUnit4Utils.java @@ -8,6 +8,8 @@ import datadog.trace.api.civisibility.events.TestDescriptor; import datadog.trace.api.civisibility.events.TestSuiteDescriptor; import datadog.trace.api.civisibility.telemetry.tag.SkipReason; +import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation; +import datadog.trace.util.ComparableVersion; import datadog.trace.util.MethodHandles; import java.lang.annotation.Annotation; import java.lang.invoke.MethodHandle; @@ -20,10 +22,13 @@ import java.util.regex.Pattern; import javax.annotation.Nullable; import junit.framework.TestCase; +import junit.runner.Version; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.Description; +import org.junit.runner.Request; import org.junit.runner.RunWith; +import org.junit.runner.Runner; import org.junit.runner.notification.RunListener; import org.junit.runner.notification.RunNotifier; import org.junit.runners.ParentRunner; @@ -53,7 +58,8 @@ public abstract class JUnit4Utils { private static final MethodHandle DESCRIPTION_UNIQUE_ID = METHOD_HANDLES.privateFieldGetter(Description.class, "fUniqueId"); - public static final List CAPABILITIES = + public static final ComparableVersion junitV413 = new ComparableVersion("4.13"); + public static final List BASE_CAPABILITIES = Arrays.asList( LibraryCapability.TIA, LibraryCapability.ATR, @@ -334,6 +340,45 @@ public static TestSuiteDescriptor toSuiteDescriptor(Description description) { return new TestSuiteDescriptor(testSuiteName, null); } + public static TestFrameworkInstrumentation runnerToFramework(Runner runner) { + String runnerClassName = runner.getClass().getName(); + if ("datadog.trace.agent.test.SpockRunner".equals(runnerClassName)) { + return TestFrameworkInstrumentation.SPOCK; + } else if (runnerClassName.startsWith("com.intuit.karate")) { + return TestFrameworkInstrumentation.KARATE; + } else if (runnerClassName.startsWith("io.cucumber")) { + return TestFrameworkInstrumentation.CUCUMBER; + } else { + return TestFrameworkInstrumentation.JUNIT4; + } + } + + public static TestFrameworkInstrumentation classToFramework(Class testClass) { + Runner runner = Request.aClass(testClass).getRunner(); + return runnerToFramework(runner); + } + + public static List getClassChildren(Class testClass) { + Runner runner = Request.aClass(testClass).getRunner(); + return runner.getDescription().getChildren(); + } + + public static String getVersion() { + return Version.id(); + } + + public static boolean isTestOrderingSupported(String version) { + return version != null && junitV413.compareTo(new ComparableVersion(version)) <= 0; + } + + public static List capabilities(boolean classOrdering) { + List capabilities = new ArrayList<>(BASE_CAPABILITIES); + if (classOrdering || isTestOrderingSupported(getVersion())) { + capabilities.add(LibraryCapability.FAIL_FAST); + } + return capabilities; + } + /** * Is JUnit 5 test that is executed with JUnit 4 * using @RunWith(org.junit.platform.runner.JUnitPlatform.class) diff --git a/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4FailFastClassOrderer.java b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4FailFastClassOrderer.java new file mode 100644 index 00000000000..90cef497140 --- /dev/null +++ b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4FailFastClassOrderer.java @@ -0,0 +1,49 @@ +package datadog.trace.instrumentation.junit4.order; + +import datadog.trace.api.civisibility.config.TestIdentifier; +import datadog.trace.api.civisibility.config.TestSourceData; +import datadog.trace.api.civisibility.events.TestDescriptor; +import datadog.trace.api.civisibility.events.TestEventsHandler; +import datadog.trace.api.civisibility.events.TestSuiteDescriptor; +import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation; +import datadog.trace.instrumentation.junit4.JUnit4Utils; +import java.lang.reflect.Method; +import java.util.Comparator; +import java.util.List; +import javax.annotation.Nullable; + +public class JUnit4FailFastClassOrderer implements Comparator> { + + @Nullable private final TestEventsHandler testEventsHandler; + + public JUnit4FailFastClassOrderer( + @Nullable TestEventsHandler testEventsHandler) { + this.testEventsHandler = testEventsHandler; + } + + public int classExecutionPriority(Class clazz) { + TestFrameworkInstrumentation framework = JUnit4Utils.classToFramework(clazz); + if (testEventsHandler == null || framework != TestFrameworkInstrumentation.JUNIT4) { + return 0; + } + + List children = JUnit4Utils.getTestMethods(clazz); + if (children.isEmpty()) { + return 0; + } + + int childrenPrioritySum = 0; + for (Method child : children) { + TestIdentifier testIdentifier = new TestIdentifier(clazz.getName(), child.getName(), null); + TestSourceData testSourceData = new TestSourceData(clazz, child); + childrenPrioritySum += testEventsHandler.executionPriority(testIdentifier, testSourceData); + } + + return childrenPrioritySum / children.size(); + } + + @Override + public int compare(Class o1, Class o2) { + return classExecutionPriority(o2) - classExecutionPriority(o1); + } +} diff --git a/dd-java-agent/instrumentation/junit-4.10/src/test/groovy/JUnit4Test.groovy b/dd-java-agent/instrumentation/junit-4.10/src/test/groovy/JUnit4Test.groovy index 44fb66f6ffc..c6e438c1e3e 100644 --- a/dd-java-agent/instrumentation/junit-4.10/src/test/groovy/JUnit4Test.groovy +++ b/dd-java-agent/instrumentation/junit-4.10/src/test/groovy/JUnit4Test.groovy @@ -7,8 +7,8 @@ import datadog.trace.civisibility.diff.FileDiff import datadog.trace.civisibility.diff.LineDiff import datadog.trace.instrumentation.junit4.JUnit4Utils import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder -import junit.runner.Version import org.example.* +import org.junit.jupiter.api.Assumptions import org.junit.runner.JUnitCore @DisableTestTrace(reason = "avoid self-tracing") @@ -210,14 +210,15 @@ class JUnit4Test extends CiVisibilityInstrumentationTest { def "test capabilities tagging #testcaseName"() { setup: + Assumptions.assumeFalse(JUnit4Utils.isTestOrderingSupported(JUnit4Utils.getVersion())) runTests([TestSucceed], true) expect: - assertCapabilities(JUnit4Utils.CAPABILITIES, 4) + assertCapabilities(JUnit4Utils.BASE_CAPABILITIES, 4) } private void runTests(Collection> tests, boolean expectSuccess = true) { - TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.CAPABILITIES) + TestEventsHandlerHolder.start(TestFrameworkInstrumentation.JUNIT4, JUnit4Utils.capabilities(false)) try { Class[] array = tests.toArray(new Class[0]) def result = runner.run(array) @@ -242,6 +243,6 @@ class JUnit4Test extends CiVisibilityInstrumentationTest { @Override String instrumentedLibraryVersion() { - return Version.id() + return JUnit4Utils.getVersion() } } diff --git a/dd-java-agent/instrumentation/lettuce-5/build.gradle b/dd-java-agent/instrumentation/lettuce-5/build.gradle index 44006f6a8f4..8ec3c31d5ca 100644 --- a/dd-java-agent/instrumentation/lettuce-5/build.gradle +++ b/dd-java-agent/instrumentation/lettuce-5/build.gradle @@ -11,6 +11,7 @@ muzzle { apply from: "$rootDir/gradle/java.gradle" addTestSuiteForDir('latestDepTest', 'test') +addTestSuiteExtendingForDir('latestDepForkedTest', 'latestDepTest', 'test') dependencies { compileOnly group: 'io.lettuce', name: 'lettuce-core', version: '5.0.0.RELEASE' diff --git a/dd-java-agent/instrumentation/lettuce-5/src/test/groovy/Lettuce5ClientTestBase.groovy b/dd-java-agent/instrumentation/lettuce-5/src/test/groovy/Lettuce5ClientTestBase.groovy index 9943c014c8c..5d917b78d92 100644 --- a/dd-java-agent/instrumentation/lettuce-5/src/test/groovy/Lettuce5ClientTestBase.groovy +++ b/dd-java-agent/instrumentation/lettuce-5/src/test/groovy/Lettuce5ClientTestBase.groovy @@ -42,6 +42,13 @@ abstract class Lettuce5ClientTestBase extends VersionedNamingTestBase { RedisAsyncCommands asyncCommands RedisCommands syncCommands + @Override + boolean useStrictTraceWrites() { + // latest seems leaking continuations that terminates later hence the strict trace will discard our spans. + !isLatestDepTest + } + + def setup() { redisServer.start() println "Using redis: $redisServer.redisURI" diff --git a/dd-java-agent/instrumentation/maven-surefire/build.gradle b/dd-java-agent/instrumentation/maven-surefire/build.gradle new file mode 100644 index 00000000000..f540b7413b1 --- /dev/null +++ b/dd-java-agent/instrumentation/maven-surefire/build.gradle @@ -0,0 +1,24 @@ +apply from: "$rootDir/gradle/java.gradle" + +muzzle { + pass { + group = 'org.apache.maven.surefire' + module = 'surefire-junit4' + versions = '[3.0.0,)' + assertInverse = true + extraDependency 'junit:junit:4.10' + } + pass { + group = 'org.apache.maven.surefire' + module = 'surefire-junit47' + versions = '[3.0.0,)' + assertInverse = true + extraDependency 'junit:junit:4.10' + } +} + +dependencies { + compileOnly group: 'org.apache.maven.surefire', name: 'surefire-junit4', version: '3.0.0' + compileOnly group: 'org.apache.maven.surefire', name: 'surefire-junit47', version: '3.0.0' // parallel provider + implementation project(":dd-java-agent:instrumentation:junit-4.10") +} diff --git a/dd-java-agent/instrumentation/maven-surefire/gradle.lockfile b/dd-java-agent/instrumentation/maven-surefire/gradle.lockfile new file mode 100644 index 00000000000..43c5d24d513 --- /dev/null +++ b/dd-java-agent/instrumentation/maven-surefire/gradle.lockfile @@ -0,0 +1,283 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +aopalliance:aopalliance:1.0=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +cafe.cryptography:curve25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +cafe.cryptography:ed25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +ch.qos.logback:logback-classic:1.2.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +ch.qos.logback:logback-core:1.2.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.beust:jcommander:1.78=latestDepTestRuntimeClasspath,testRuntimeClasspath +com.blogspot.mydailyjava:weak-lock-free:0.17=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okhttp3:okhttp:3.12.15=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okio:okio:1.17.6=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:dd-javac-plugin-client:0.2.2=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:java-dogstatsd-client:4.4.3=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.datadoghq:sketches-java:0.8.3=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-annotations:2.16.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-core:2.16.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-databind:2.16.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson:jackson-bom:2.16.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.github.javaparser:javaparser-core:3.25.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.github.jnr:jffi:1.3.13=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-a64asm:1.0.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-constants:0.10.4=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-enxio:0.32.17=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-ffi:2.2.16=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-posix:3.1.19=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-unixsocket:0.38.22=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-x86asm:1.0.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.2.0=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.7.3=spotbugs +com.github.spotbugs:spotbugs:4.7.3=spotbugs +com.github.stefanbirkner:system-rules:1.19.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.auto.service:auto-service-annotations:1.0-rc7=annotationProcessor,compileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,testAnnotationProcessor,testCompileClasspath +com.google.auto.service:auto-service:1.0-rc7=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.auto:auto-common:0.10=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath +com.google.code.gson:gson:2.9.1=spotbugs +com.google.errorprone:error_prone_annotations:2.2.0=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.errorprone:error_prone_annotations:2.26.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.google.guava:failureaccess:1.0.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:failureaccess:1.0.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.google.guava:guava:10.0.1=compileClasspath +com.google.guava:guava:16.0.1=testCompileClasspath,testRuntimeClasspath +com.google.guava:guava:27.0.1-jre=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:guava:33.2.1-jre=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testAnnotationProcessor +com.google.inject:guice:6.0.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.j2objc:j2objc-annotations:3.0.0=latestDepTestCompileClasspath +com.google.re2j:re2j:1.7=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.jayway.jsonpath:json-path:2.8.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.moshi:moshi:1.11.0=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:logging-interceptor:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:okhttp:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okio:okio:1.17.5=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.thoughtworks.qdox:qdox:1.12.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +com.vaadin.external.google:android-json:0.0.20131108.vaadin1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +commons-cli:commons-cli:1.2=compileClasspath,testCompileClasspath,testRuntimeClasspath +commons-cli:commons-cli:1.8.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +commons-codec:commons-codec:1.15=spotbugs +commons-codec:commons-codec:1.17.1=latestDepTestRuntimeClasspath +commons-codec:commons-codec:1.6=testCompileClasspath,testRuntimeClasspath +commons-fileupload:commons-fileupload:1.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +commons-io:commons-io:2.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +de.thetaphi:forbiddenapis:3.8=compileClasspath +info.picocli:picocli:4.6.3=latestDepTestRuntimeClasspath,testRuntimeClasspath +io.sqreen:libsqreen:12.0.0=latestDepTestRuntimeClasspath,testRuntimeClasspath +jakarta.inject:jakarta.inject-api:2.0.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +javax.annotation:javax.annotation-api:1.3.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +javax.annotation:jsr250-api:1.0=compileClasspath,testCompileClasspath,testRuntimeClasspath +javax.enterprise:cdi-api:1.0=compileClasspath,testCompileClasspath,testRuntimeClasspath +javax.inject:javax.inject:1=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +javax.servlet:javax.servlet-api:3.1.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +jaxen:jaxen:1.2.0=spotbugs +jline:jline:2.14.6=latestDepTestRuntimeClasspath,testRuntimeClasspath +junit:junit-dep:4.11=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +junit:junit:4.13.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.14.18=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy:1.14.18=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.java.dev.jna:jna-platform:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.java.dev.jna:jna:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.jcip:jcip-annotations:1.0=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath +net.minidev:accessors-smart:2.4.9=latestDepTestRuntimeClasspath,testRuntimeClasspath +net.minidev:json-smart:2.4.10=latestDepTestRuntimeClasspath,testRuntimeClasspath +net.sf.saxon:Saxon-HE:11.4=spotbugs +org.apache.ant:ant-antlr:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant-antlr:1.9.15=codenarc +org.apache.ant:ant-junit:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant-junit:1.9.15=codenarc +org.apache.ant:ant-launcher:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant:1.10.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.apache.bcel:bcel:6.5.0=spotbugs +org.apache.commons:commons-lang3:3.12.0=spotbugs +org.apache.commons:commons-text:1.10.0=spotbugs +org.apache.httpcomponents.client5:httpclient5:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5-h2:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5:5.1.3=spotbugs +org.apache.httpcomponents:httpclient:4.2.6=testCompileClasspath,testRuntimeClasspath +org.apache.httpcomponents:httpclient:4.5.14=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.httpcomponents:httpcore:4.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.httpcomponents:httpcore:4.4.16=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.logging.log4j:log4j-api:2.19.0=spotbugs +org.apache.logging.log4j:log4j-core:2.19.0=spotbugs +org.apache.maven.resolver:maven-resolver-api:1.0.3=testCompileClasspath,testRuntimeClasspath +org.apache.maven.resolver:maven-resolver-api:1.9.22=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven.resolver:maven-resolver-connector-basic:1.0.3=testCompileClasspath,testRuntimeClasspath +org.apache.maven.resolver:maven-resolver-connector-basic:1.9.22=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven.resolver:maven-resolver-impl:1.9.22=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven.resolver:maven-resolver-named-locks:1.9.22=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven.resolver:maven-resolver-spi:1.0.3=testCompileClasspath,testRuntimeClasspath +org.apache.maven.resolver:maven-resolver-spi:1.9.22=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven.resolver:maven-resolver-transport-http:1.0.3=testCompileClasspath,testRuntimeClasspath +org.apache.maven.resolver:maven-resolver-transport-http:1.9.22=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven.resolver:maven-resolver-util:1.0.3=testCompileClasspath,testRuntimeClasspath +org.apache.maven.resolver:maven-resolver-util:1.9.22=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven.shared:maven-shared-utils:3.4.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven.wagon:wagon-provider-api:2.8=testRuntimeClasspath +org.apache.maven.wagon:wagon-provider-api:3.5.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-aether-provider:3.2.1=compileClasspath +org.apache.maven:maven-aether-provider:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-api-meta:4.0.0-alpha-5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-api-xml:4.0.0-alpha-5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-artifact:3.2.1=compileClasspath +org.apache.maven:maven-artifact:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-artifact:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-builder-support:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-compat:3.2.5=testRuntimeClasspath +org.apache.maven:maven-compat:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-core:3.2.1=compileClasspath +org.apache.maven:maven-core:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-core:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-embedder:3.2.1=compileClasspath +org.apache.maven:maven-embedder:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-embedder:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-model-builder:3.2.1=compileClasspath +org.apache.maven:maven-model-builder:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-model-builder:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-model:3.2.1=compileClasspath +org.apache.maven:maven-model:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-model:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-plugin-api:3.2.1=compileClasspath +org.apache.maven:maven-plugin-api:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-plugin-api:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-repository-metadata:3.2.1=compileClasspath +org.apache.maven:maven-repository-metadata:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-repository-metadata:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-resolver-provider:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-settings-builder:3.2.1=compileClasspath +org.apache.maven:maven-settings-builder:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-settings-builder:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-settings:3.2.1=compileClasspath +org.apache.maven:maven-settings:3.2.5=testCompileClasspath,testRuntimeClasspath +org.apache.maven:maven-settings:3.9.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.maven:maven-xml-impl:4.0.0-alpha-5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apiguardian:apiguardian-api:1.1.2=latestDepTestCompileClasspath,testCompileClasspath +org.checkerframework:checker-qual:2.5.2=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +org.checkerframework:checker-qual:3.42.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.codehaus.groovy:groovy-all:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-ant:2.5.14=codenarc +org.codehaus.groovy:groovy-ant:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-astbuilder:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-cli-picocli:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-console:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-datetime:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-docgenerator:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovydoc:2.5.14=codenarc +org.codehaus.groovy:groovy-groovydoc:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovysh:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jmx:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-json:2.5.14=codenarc +org.codehaus.groovy:groovy-json:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jsr223:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-macro:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-nio:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-servlet:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-sql:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-swing:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-templates:2.5.14=codenarc +org.codehaus.groovy:groovy-templates:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test-junit5:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-testng:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-xml:2.5.14=codenarc +org.codehaus.groovy:groovy-xml:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy:2.5.14=codenarc +org.codehaus.groovy:groovy:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +org.codehaus.plexus:plexus-cipher:2.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.codehaus.plexus:plexus-classworlds:2.5.1=compileClasspath +org.codehaus.plexus:plexus-classworlds:2.5.2=testCompileClasspath,testRuntimeClasspath +org.codehaus.plexus:plexus-classworlds:2.8.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.codehaus.plexus:plexus-component-annotations:1.5.5=compileClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.plexus:plexus-component-annotations:2.1.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.codehaus.plexus:plexus-interpolation:1.19=compileClasspath +org.codehaus.plexus:plexus-interpolation:1.21=testCompileClasspath,testRuntimeClasspath +org.codehaus.plexus:plexus-interpolation:1.27=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.codehaus.plexus:plexus-sec-dispatcher:2.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.codehaus.plexus:plexus-utils:3.0.17=compileClasspath +org.codehaus.plexus:plexus-utils:3.0.20=testCompileClasspath,testRuntimeClasspath +org.codehaus.plexus:plexus-utils:3.5.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.codehaus.plexus:plexus-xml:4.0.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.codenarc:CodeNarc:2.2.0=codenarc +org.dom4j:dom4j:2.1.3=spotbugs +org.eclipse.aether:aether-api:0.9.0.M2=compileClasspath +org.eclipse.aether:aether-api:1.0.0.v20140518=testCompileClasspath,testRuntimeClasspath +org.eclipse.aether:aether-impl:0.9.0.M2=compileClasspath +org.eclipse.aether:aether-impl:1.0.0.v20140518=testCompileClasspath,testRuntimeClasspath +org.eclipse.aether:aether-spi:0.9.0.M2=compileClasspath +org.eclipse.aether:aether-spi:1.0.0.v20140518=testCompileClasspath,testRuntimeClasspath +org.eclipse.aether:aether-util:0.9.0.M2=compileClasspath +org.eclipse.aether:aether-util:1.0.0.v20140518=testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-http:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-io:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-server:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-util:9.4.56.v20240826=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.sisu:org.eclipse.sisu.inject:0.0.0.M5=compileClasspath +org.eclipse.sisu:org.eclipse.sisu.inject:0.3.0.M1=testCompileClasspath,testRuntimeClasspath +org.eclipse.sisu:org.eclipse.sisu.inject:0.9.0.M3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.eclipse.sisu:org.eclipse.sisu.plexus:0.0.0.M5=compileClasspath +org.eclipse.sisu:org.eclipse.sisu.plexus:0.3.0.M1=testCompileClasspath,testRuntimeClasspath +org.eclipse.sisu:org.eclipse.sisu.plexus:0.9.0.M3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.freemarker:freemarker:2.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.fusesource.jansi:jansi:2.4.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.gmetrics:GMetrics:1.1=codenarc +org.hamcrest:hamcrest-core:1.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.hamcrest:hamcrest:2.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jacoco:org.jacoco.core:0.8.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.jacoco:org.jacoco.report:0.8.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.jctools:jctools-core:3.3.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-common:1.6.21=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.21=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:1.6.21=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jetbrains:annotations:13.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-api:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-engine:5.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-commons:1.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-engine:1.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-runner:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-suite-api:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-suite-commons:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit:junit-bom:5.9.1=spotbugs +org.junit:junit-bom:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-core:4.4.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-junit-jupiter:4.4.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.msgpack:jackson-dataformat-msgpack:0.9.6=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.msgpack:msgpack-core:0.9.6=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.objenesis:objenesis:3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.opentest4j:opentest4j:1.2.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.4=spotbugs +org.ow2.asm:asm-commons:9.2=instrumentPluginClasspath,muzzleTooling,runtimeClasspath +org.ow2.asm:asm-commons:9.4=spotbugs +org.ow2.asm:asm-commons:9.7.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-tree:9.2=instrumentPluginClasspath,muzzleTooling,runtimeClasspath +org.ow2.asm:asm-tree:9.4=spotbugs +org.ow2.asm:asm-tree:9.7.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-util:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-util:9.4=spotbugs +org.ow2.asm:asm:9.2=instrumentPluginClasspath,muzzleTooling,runtimeClasspath +org.ow2.asm:asm:9.4=spotbugs +org.ow2.asm:asm:9.7.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.skyscreamer:jsonassert:1.5.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:jcl-over-slf4j:1.7.30=latestDepTestCompileClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:jcl-over-slf4j:1.7.36=latestDepTestRuntimeClasspath +org.slf4j:jul-to-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:log4j-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:1.7.30=compileClasspath,instrumentPluginClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath +org.slf4j:slf4j-api:1.7.36=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:2.0.0=spotbugs,spotbugsSlf4j +org.slf4j:slf4j-simple:2.0.0=spotbugsSlf4j +org.sonatype.plexus:plexus-cipher:1.7=compileClasspath,testCompileClasspath,testRuntimeClasspath +org.sonatype.plexus:plexus-sec-dispatcher:1.3=compileClasspath,testCompileClasspath,testRuntimeClasspath +org.sonatype.sisu:sisu-guice:3.1.0=compileClasspath +org.sonatype.sisu:sisu-guice:3.2.3=testCompileClasspath,testRuntimeClasspath +org.spockframework:spock-core:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.spockframework:spock-junit4:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.testng:testng:7.5=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.webjars:jquery:3.5.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.xmlresolver:xmlresolver:4.4.3=spotbugs +xml-apis:xml-apis:1.4.01=spotbugs +empty=spotbugsPlugins diff --git a/dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/JUnit4ClassOrderInstrumentation.java b/dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/JUnit4ClassOrderInstrumentation.java new file mode 100644 index 00000000000..23445da5bda --- /dev/null +++ b/dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/JUnit4ClassOrderInstrumentation.java @@ -0,0 +1,90 @@ +package datadog.trace.instrumentation.maven.surefire.junit4; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.api.Config; +import datadog.trace.api.civisibility.CIConstants; +import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation; +import datadog.trace.instrumentation.junit4.JUnit4Instrumentation; +import datadog.trace.instrumentation.junit4.JUnit4Utils; +import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder; +import datadog.trace.instrumentation.junit4.order.JUnit4FailFastClassOrderer; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import org.apache.maven.surefire.api.util.TestsToRun; + +@AutoService(InstrumenterModule.class) +public class JUnit4ClassOrderInstrumentation extends InstrumenterModule.CiVisibility + implements Instrumenter.ForKnownTypes, Instrumenter.HasMethodAdvice { + public JUnit4ClassOrderInstrumentation() { + super("ci-visibility", "maven", "surefire", "junit4"); + } + + @Override + public boolean isApplicable(Set enabledSystems) { + return super.isApplicable(enabledSystems) && Config.get().getCiVisibilityTestOrder() != null; + } + + @Override + public String[] knownMatchingTypes() { + return new String[] { + "org.apache.maven.surefire.junit4.JUnit4Provider", + "org.apache.maven.surefire.junitcore.JUnitCoreProvider", + }; + } + + @Override + public String[] helperClassNames() { + return new String[] { + JUnit4Instrumentation.class.getPackage().getName() + ".JUnit4Utils", + JUnit4Instrumentation.class.getPackage().getName() + ".TestEventsHandlerHolder", + JUnit4Instrumentation.class.getPackage().getName() + ".SkippedByDatadog", + JUnit4Instrumentation.class.getPackage().getName() + ".TracingListener", + JUnit4Instrumentation.class.getPackage().getName() + ".order.JUnit4FailFastClassOrderer", + }; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + named("setTestsToRun"), + JUnit4ClassOrderInstrumentation.class.getName() + "$TestsToRunAdvice"); + } + + public static class TestsToRunAdvice { + @SuppressFBWarnings( + value = "UC_USELESS_OBJECT", + justification = "testsToRun is the field value modified by the advice") + @Advice.OnMethodExit + public static void onSetTestsToRun( + @Advice.FieldValue(value = "testsToRun", readOnly = false) TestsToRun testsToRun) { + String testOrder = Config.get().getCiVisibilityTestOrder(); + if (!CIConstants.FAIL_FAST_TEST_ORDER.equalsIgnoreCase(testOrder)) { + throw new IllegalArgumentException("Unknown test order: " + testOrder); + } + + List> testClasses = new ArrayList<>(); + + for (Class testClass : testsToRun) { + testClasses.add(testClass); + TestFrameworkInstrumentation framework = JUnit4Utils.classToFramework(testClass); + if (framework == TestFrameworkInstrumentation.JUNIT4) { + TestEventsHandlerHolder.start(framework, JUnit4Utils.capabilities(true)); + } + } + + testClasses.sort( + new JUnit4FailFastClassOrderer( + TestEventsHandlerHolder.HANDLERS.get(TestFrameworkInstrumentation.JUNIT4))); + + testsToRun = new TestsToRun(new LinkedHashSet<>(testClasses)); + } + } +} diff --git a/dd-smoke-tests/backend-mock/src/main/groovy/datadog/smoketest/MockBackend.groovy b/dd-smoke-tests/backend-mock/src/main/groovy/datadog/smoketest/MockBackend.groovy index ea52b04fe2a..76ca256f6e9 100644 --- a/dd-smoke-tests/backend-mock/src/main/groovy/datadog/smoketest/MockBackend.groovy +++ b/dd-smoke-tests/backend-mock/src/main/groovy/datadog/smoketest/MockBackend.groovy @@ -31,6 +31,7 @@ class MockBackend implements AutoCloseable { private final Collection> skippableTests = new CopyOnWriteArrayList<>() private final Collection> flakyTests = new CopyOnWriteArrayList<>() + private final Collection> knownTests = new CopyOnWriteArrayList<>() private final Collection> testManagement = new CopyOnWriteArrayList<>() private final Collection changedFiles = new CopyOnWriteArrayList<>() @@ -39,6 +40,7 @@ class MockBackend implements AutoCloseable { private boolean testsSkippingEnabled = true private boolean flakyRetriesEnabled = false private boolean impactedTestsDetectionEnabled = false + private boolean knownTestsEnabled = false private boolean testManagementEnabled = false private int attemptToFixRetries = 0 @@ -51,6 +53,7 @@ class MockBackend implements AutoCloseable { skippableTests.clear() flakyTests.clear() + knownTests.clear() testManagement.clear() changedFiles.clear() } @@ -84,6 +87,14 @@ class MockBackend implements AutoCloseable { changedFiles.add(relativePath) } + void givenKnownTests(boolean knownTests) { + this.knownTestsEnabled = knownTests + } + + void givenKnownTest(String module, String suite, String name) { + knownTests.add(["module": module, "suite": suite, "name": name]) + } + void givenTestManagement(boolean testManagementEnabled) { this.testManagementEnabled = testManagementEnabled } @@ -164,6 +175,7 @@ class MockBackend implements AutoCloseable { "tests_skipping": $testsSkippingEnabled, "flaky_test_retries_enabled": $flakyRetriesEnabled, "impacted_tests_enabled": $impactedTestsDetectionEnabled, + "known_tests_enabled": $knownTestsEnabled, "test_management": { "enabled": $testManagementEnabled, "attempt_to_fix_retries": $attemptToFixRetries @@ -265,6 +277,20 @@ class MockBackend implements AutoCloseable { .send(MockBackend.compress((""" { "data": $flakyTestsResponse } """).bytes)) } + prefix("/api/v2/ci/libraries/tests") { + Map modules = [:] + for (Map test : knownTests) { + Map suites = modules.computeIfAbsent("${test.module}", k -> [:]) + List tests = suites.computeIfAbsent("${test.suite}", k -> []) + tests.add(test.name) + } + + String knownTestsResponse = """{ "tests": ${JSON_MAPPER.writeValueAsString(modules)}}""" + response.status(200) + .addHeader("Content-Encoding", "gzip") + .send(MockBackend.compress((""" { "data": { "attributes": $knownTestsResponse } } """).bytes)) + } + prefix("/api/v2/test/libraries/test-management/tests") { Map modules = [:] for (Map test : testManagement) { diff --git a/dd-smoke-tests/gradle/src/test/groovy/datadog/smoketest/GradleDaemonSmokeTest.groovy b/dd-smoke-tests/gradle/src/test/groovy/datadog/smoketest/GradleDaemonSmokeTest.groovy index ae8aea6af5a..3a4a99e6e8d 100644 --- a/dd-smoke-tests/gradle/src/test/groovy/datadog/smoketest/GradleDaemonSmokeTest.groovy +++ b/dd-smoke-tests/gradle/src/test/groovy/datadog/smoketest/GradleDaemonSmokeTest.groovy @@ -6,19 +6,22 @@ import datadog.trace.api.config.CiVisibilityConfig import datadog.trace.api.config.GeneralConfig import datadog.trace.api.config.TraceInstrumentationConfig import datadog.trace.util.Strings +import java.nio.file.Files +import java.nio.file.Path import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner import org.gradle.testkit.runner.TaskOutcome import org.gradle.util.DistributionLocator import org.gradle.util.GradleVersion -import org.gradle.wrapper.* +import org.gradle.wrapper.Download +import org.gradle.wrapper.GradleUserHomeLookup +import org.gradle.wrapper.Install +import org.gradle.wrapper.PathAssembler +import org.gradle.wrapper.WrapperConfiguration import spock.lang.IgnoreIf import spock.lang.Shared import spock.lang.TempDir -import java.nio.file.Files -import java.nio.file.Path - class GradleDaemonSmokeTest extends AbstractGradleTest { private static final String TEST_SERVICE_NAME = "test-gradle-service" @@ -77,6 +80,50 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { LATEST_GRADLE_VERSION | "test-succeed-gradle-plugin-test" | false | true | false | 5 | 0 } + def "test junit4 class ordering v#gradleVersion"() { + givenGradleVersionIsCompatibleWithCurrentJvm(gradleVersion) + givenGradleProjectFiles(projectName) + ensureDependenciesDownloaded(gradleVersion) + + mockBackend.givenKnownTests(true) + for (flakyTest in flakyTests) { + mockBackend.givenFlakyTest(":test", flakyTest.getSuite(), flakyTest.getName()) + mockBackend.givenKnownTest(":test", flakyTest.getSuite(), flakyTest.getName()) + } + + BuildResult buildResult = runGradleTests(gradleVersion, true, false) + assertBuildSuccessful(buildResult) + + verifyTestOrder(mockBackend.waitForEvents(eventsNumber), expectedOrder) + + where: + gradleVersion | projectName | flakyTests | expectedOrder | eventsNumber + "5.1" | "test-succeed-junit-4-class-ordering" | [ + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | [ + test("datadog.smoke.TestSucceedC", "test_succeed"), + test("datadog.smoke.TestSucceedC", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another") + ] | 15 + LATEST_GRADLE_VERSION | "test-succeed-junit-4-class-ordering" | [ + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | [ + test("datadog.smoke.TestSucceedC", "test_succeed"), + test("datadog.smoke.TestSucceedC", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another") + ] | 15 + } + private runGradleTest(String gradleVersion, String projectName, boolean configurationCache, boolean successExpected, boolean flakyRetries, int expectedTraces, int expectedCoverages) { givenGradleVersionIsCompatibleWithCurrentJvm(gradleVersion) givenConfigurationCacheIsCompatibleWithCurrentPlatform(configurationCache) diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/build.gradleTest b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/build.gradleTest new file mode 100644 index 00000000000..27685459d0e --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/build.gradleTest @@ -0,0 +1,15 @@ +apply plugin: 'java' + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + testImplementation 'junit:junit:4.13.2' +} + +test { + useJUnit() + environment "DD_CIVISIBILITY_TEST_ORDER", "FAILFAST" +} diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/settings.gradleTest b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/settings.gradleTest new file mode 100644 index 00000000000..6040f1decb8 --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/settings.gradleTest @@ -0,0 +1 @@ +rootProject.name = 'gradle-instrumentation-test-project' diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/main/java/datadog/smoke/Calculator.java b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/main/java/datadog/smoke/Calculator.java new file mode 100644 index 00000000000..2f4461a279d --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/main/java/datadog/smoke/Calculator.java @@ -0,0 +1,11 @@ +package datadog.smoke; + +public class Calculator { + public static int add(int a, int b) { + return a + b; + } + + public static int subtract(int a, int b) { + return a - b; + } +} diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedA.java b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedA.java new file mode 100644 index 00000000000..209173057b4 --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedA.java @@ -0,0 +1,21 @@ +package datadog.smoke; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.OrderWith; +import org.junit.runner.manipulation.Alphanumeric; + +@OrderWith(Alphanumeric.class) +public class TestSucceedA { + + @Test + public void test_succeed() { + assertTrue(Calculator.add(2, 2) == 4); + } + + @Test + public void test_succeed_another() { + assertTrue(Calculator.add(2, 2) == 4); + } +} diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedB.java b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedB.java new file mode 100644 index 00000000000..e5a0037120d --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedB.java @@ -0,0 +1,21 @@ +package datadog.smoke; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.OrderWith; +import org.junit.runner.manipulation.Alphanumeric; + +@OrderWith(Alphanumeric.class) +public class TestSucceedB { + + @Test + public void test_succeed() { + assertTrue(Calculator.add(2, 2) == 4); + } + + @Test + public void test_succeed_another() { + assertTrue(Calculator.add(2, 2) == 4); + } +} diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedC.java b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedC.java new file mode 100644 index 00000000000..f01caf6de11 --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedC.java @@ -0,0 +1,21 @@ +package datadog.smoke; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.OrderWith; +import org.junit.runner.manipulation.Alphanumeric; + +@OrderWith(Alphanumeric.class) +public class TestSucceedC { + + @Test + public void test_succeed() { + assertTrue(Calculator.add(2, 2) == 4); + } + + @Test + public void test_succeed_another() { + assertTrue(Calculator.add(2, 2) == 4); + } +} diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/coverages.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/coverages.ftl index 567ef02b425..2fe41431bbf 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/coverages.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/coverages.ftl @@ -1,15 +1,4 @@ [ { - "files" : [ { - "bitmap" : "AAE=", - "filename" : "src/main/java/datadog/smoke/Calculator.java" - }, { - "bitmap" : "AAw=", - "filename" : "src/test/java/datadog/smoke/TestSucceedJunit5.java" - } ], - "span_id" : ${content_span_id_5}, - "test_session_id" : ${content_test_session_id}, - "test_suite_id" : ${content_test_suite_id_2} -}, { "files" : [ { "bitmap" : "gAw=", "filename" : "src/test/java/datadog/smoke/TestSucceed.java" @@ -20,4 +9,15 @@ "span_id" : ${content_span_id_4}, "test_session_id" : ${content_test_session_id}, "test_suite_id" : ${content_test_suite_id} +}, { + "files" : [ { + "bitmap" : "AAE=", + "filename" : "src/main/java/datadog/smoke/Calculator.java" + }, { + "bitmap" : "AAw=", + "filename" : "src/test/java/datadog/smoke/TestSucceedJunit5.java" + } ], + "span_id" : ${content_span_id_5}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id_2} } ] \ No newline at end of file diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/events.ftl index 6e69dc1d8fc..786a207fe9f 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-legacy-instrumentation/events.ftl @@ -186,6 +186,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-new-instrumentation/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-new-instrumentation/events.ftl index f6787d25b40..a87e9a2e32c 100644 --- a/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-new-instrumentation/events.ftl +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-multi-forks-new-instrumentation/events.ftl @@ -235,6 +235,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy b/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy index 7688e8df70e..7458883ca32 100644 --- a/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy +++ b/dd-smoke-tests/maven/src/test/groovy/datadog/smoketest/MavenSmokeTest.groovy @@ -1,10 +1,21 @@ package datadog.smoketest import datadog.trace.api.Config +import datadog.trace.api.civisibility.CIConstants import datadog.trace.api.config.CiVisibilityConfig import datadog.trace.api.config.GeneralConfig import datadog.trace.civisibility.CiVisibilitySmokeTest import datadog.trace.util.Strings +import java.nio.file.FileVisitResult +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.nio.file.SimpleFileVisitor +import java.nio.file.attribute.BasicFileAttributes +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException +import javax.xml.parsers.DocumentBuilder +import javax.xml.parsers.DocumentBuilderFactory import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response @@ -19,17 +30,6 @@ import spock.lang.Shared import spock.lang.TempDir import spock.util.environment.Jvm -import javax.xml.parsers.DocumentBuilder -import javax.xml.parsers.DocumentBuilderFactory -import java.nio.file.FileVisitResult -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.Paths -import java.nio.file.SimpleFileVisitor -import java.nio.file.attribute.BasicFileAttributes -import java.util.concurrent.TimeUnit -import java.util.concurrent.TimeoutException - class MavenSmokeTest extends CiVisibilitySmokeTest { private static final Logger LOGGER = LoggerFactory.getLogger(MavenSmokeTest.class) @@ -149,8 +149,83 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { verifyEventsAndCoverages(projectName, "maven", mavenVersion, mockBackend.waitForEvents(15), mockBackend.waitForCoverages(6)) where: - projectName | mavenVersion - "test_successful_maven_run_test_management" | "3.9.9" + projectName | mavenVersion + "test_successful_maven_run_test_management" | "3.9.9" + } + + def "test junit4 class ordering #testcaseName"() { + def additionalEnvVars = ["SMOKE_TEST_SUREFIRE_VERSION": surefireVersion] + + givenWrapperPropertiesFile(mavenVersion) + givenMavenProjectFiles(projectName) + givenMavenDependenciesAreLoaded(projectName, mavenVersion, additionalEnvVars) + + for (flakyTest in flakyTests) { + mockBackend.givenFlakyTest("Maven Smoke Tests Project maven-surefire-plugin default-test", flakyTest.getSuite(), flakyTest.getName()) + } + + mockBackend.givenKnownTests(true) + for (knownTest in knownTests) { + mockBackend.givenKnownTest("Maven Smoke Tests Project maven-surefire-plugin default-test", knownTest.getSuite(), knownTest.getName()) + } + + def exitCode = whenRunningMavenBuild([ + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_TEST_ORDER)}=${CIConstants.FAIL_FAST_TEST_ORDER}" as String + ], [], additionalEnvVars) + assert exitCode == 0 + + verifyTestOrder(mockBackend.waitForEvents(eventsNumber), expectedOrder) + + where: + testcaseName | projectName | mavenVersion | surefireVersion | flakyTests | knownTests | expectedOrder | eventsNumber + "junit4-provider" | "test_successful_maven_run_junit4_class_ordering" | "3.9.9" | "3.0.0" | [ + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | [ + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | [ + test("datadog.smoke.TestSucceedC", "test_succeed"), + test("datadog.smoke.TestSucceedC", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another") + ] | 15 + "junit47-provider" | "test_successful_maven_run_junit4_class_ordering_parallel" | "3.9.9" | "3.0.0" | [test("datadog.smoke.TestSucceedC", "test_succeed")] | [ + test("datadog.smoke.TestSucceedC", "test_succeed"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | [ + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedC", "test_succeed"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | 12 + "junit4-provider-latest-surefire" | "test_successful_maven_run_junit4_class_ordering" | "3.9.9" | getLatestMavenSurefireVersion() | [ + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | [ + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | [ + test("datadog.smoke.TestSucceedC", "test_succeed"), + test("datadog.smoke.TestSucceedC", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed_another"), + test("datadog.smoke.TestSucceedA", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedB", "test_succeed_another") + ] | 15 + "junit47-provider-latest-surefire" | "test_successful_maven_run_junit4_class_ordering_parallel" | "3.9.9" | getLatestMavenSurefireVersion() | [test("datadog.smoke.TestSucceedC", "test_succeed")] | [ + test("datadog.smoke.TestSucceedC", "test_succeed"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | [ + test("datadog.smoke.TestSucceedB", "test_succeed"), + test("datadog.smoke.TestSucceedC", "test_succeed"), + test("datadog.smoke.TestSucceedA", "test_succeed") + ] | 12 } private void givenWrapperPropertiesFile(String mavenVersion) { @@ -198,25 +273,25 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { * Here, in order to reduce flakiness, we ensure that all of the dependencies are loaded (retrying if necessary), * before proceeding with running the build */ - private void givenMavenDependenciesAreLoaded(String projectName, String mavenVersion) { + private void givenMavenDependenciesAreLoaded(String projectName, String mavenVersion, Map additionalEnvVars = [:]) { if (LOADED_DEPENDENCIES.add("$projectName:$mavenVersion")) { - retryUntilSuccessfulOrNoAttemptsLeft(["dependency:go-offline"]) + retryUntilSuccessfulOrNoAttemptsLeft(["dependency:go-offline"], additionalEnvVars) } // dependencies below are download separately // because they are not declared in the project, // but are added at runtime by the tracer if (LOADED_DEPENDENCIES.add("com.datadoghq:dd-javac-plugin:$JAVAC_PLUGIN_VERSION")) { - retryUntilSuccessfulOrNoAttemptsLeft(["dependency:get", "-Dartifact=com.datadoghq:dd-javac-plugin:$JAVAC_PLUGIN_VERSION".toString()]) + retryUntilSuccessfulOrNoAttemptsLeft(["dependency:get", "-Dartifact=com.datadoghq:dd-javac-plugin:$JAVAC_PLUGIN_VERSION".toString()], additionalEnvVars) } if (LOADED_DEPENDENCIES.add("org.jacoco:jacoco-maven-plugin:$JACOCO_PLUGIN_VERSION")) { - retryUntilSuccessfulOrNoAttemptsLeft(["dependency:get", "-Dartifact=org.jacoco:jacoco-maven-plugin:$JACOCO_PLUGIN_VERSION".toString()]) + retryUntilSuccessfulOrNoAttemptsLeft(["dependency:get", "-Dartifact=org.jacoco:jacoco-maven-plugin:$JACOCO_PLUGIN_VERSION".toString()], additionalEnvVars) } } private static final Collection LOADED_DEPENDENCIES = new HashSet<>() - private void retryUntilSuccessfulOrNoAttemptsLeft(List mvnCommand) { - def processBuilder = createProcessBuilder(mvnCommand, false, []) + private void retryUntilSuccessfulOrNoAttemptsLeft(List mvnCommand, Map additionalEnvVars = [:]) { + def processBuilder = createProcessBuilder(mvnCommand, false, [], additionalEnvVars) for (int attempt = 0; attempt < DEPENDENCIES_DOWNLOAD_RETRIES; attempt++) { def exitCode = runProcess(processBuilder.start()) if (exitCode == 0) { @@ -226,8 +301,8 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { throw new AssertionError((Object) "Tried $DEPENDENCIES_DOWNLOAD_RETRIES times to execute $mvnCommand and failed") } - private int whenRunningMavenBuild(List additionalAgentArgs, List additionalCommandLineParams) { - def processBuilder = createProcessBuilder(["-B", "test"] + additionalCommandLineParams, true, additionalAgentArgs) + private int whenRunningMavenBuild(List additionalAgentArgs, List additionalCommandLineParams, Map additionalEnvVars = [:]) { + def processBuilder = createProcessBuilder(["-B", "test"] + additionalCommandLineParams, true, additionalAgentArgs, additionalEnvVars) processBuilder.environment().put("DD_API_KEY", "01234567890abcdef123456789ABCDEF") @@ -248,7 +323,7 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { return p.exitValue() } - ProcessBuilder createProcessBuilder(List mvnCommand, boolean runWithAgent, List additionalAgentArgs) { + ProcessBuilder createProcessBuilder(List mvnCommand, boolean runWithAgent, List additionalAgentArgs, Map additionalEnvVars) { String mavenRunnerShadowJar = System.getProperty("datadog.smoketest.maven.jar.path") assert new File(mavenRunnerShadowJar).isFile() @@ -263,6 +338,9 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { processBuilder.directory(projectHome.toFile()) processBuilder.environment().put("JAVA_HOME", System.getProperty("java.home")) + for (envVar in additionalEnvVars) { + processBuilder.environment().put(envVar.key, envVar.value) + } return processBuilder } @@ -362,6 +440,43 @@ class MavenSmokeTest extends CiVisibilitySmokeTest { return hardcodedLatestVersion } + private static String getLatestMavenSurefireVersion() { + OkHttpClient client = new OkHttpClient() + Request request = + new Request.Builder() + .url( + "https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-surefire-plugin/maven-metadata.xml") + .build() + try (Response response = client.newCall(request).execute()) { + if (response.isSuccessful()) { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance() + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder() + Document doc = dBuilder.parse(response.body().byteStream()) + doc.getDocumentElement().normalize() + + NodeList versionList = doc.getElementsByTagName("latest") + if (versionList.getLength() > 0) { + String version = versionList.item(0).getTextContent() + if (!version.contains("alpha") && !version.contains("beta")) { + LOGGER.info("Will run the 'latest' tests with version " + version) + return version + } + } + } else { + LOGGER.warn( + "Could not get latest Maven Surefire version, response from repo.maven.apache.org is " + + response.code() + + ":" + + response.body().string()) + } + } catch (Exception e) { + LOGGER.warn("Could not get latest Maven Surefire version", e) + } + String hardcodedLatestVersion = "3.5.0" // latest version that is known to work + LOGGER.info("Will run the 'latest' tests with hard-coded version " + hardcodedLatestVersion) + return hardcodedLatestVersion + } + private static BitSet bits(int ... indices) { BitSet bitSet = new BitSet() for (int i : indices) { diff --git a/dd-smoke-tests/maven/src/test/resources/test_failed_maven_run_flaky_retries/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_run_flaky_retries/events.ftl index 3dcdf89901a..aa09cea362d 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_failed_maven_run_flaky_retries/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_failed_maven_run_flaky_retries/events.ftl @@ -307,6 +307,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -369,6 +370,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -433,6 +435,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -497,6 +500,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -561,6 +565,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run/events.ftl index 028ae502e83..2c16bf028a1 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run/events.ftl @@ -311,6 +311,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -371,6 +372,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_builtin_coverage/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_builtin_coverage/events.ftl index 9c08cc57fe1..379f69d7ece 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_builtin_coverage/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_builtin_coverage/events.ftl @@ -275,6 +275,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -335,6 +336,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_impacted_tests/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_impacted_tests/events.ftl index 73aba91b29f..408b8037fcd 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_impacted_tests/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_impacted_tests/events.ftl @@ -273,6 +273,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -334,6 +335,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/pom.xml b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/pom.xml new file mode 100644 index 00000000000..3f616315427 --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + com.datadog.ci.test + maven-smoke-test + 1.0-SNAPSHOT + Maven Smoke Tests Project + + + 8 + 8 + UTF-8 + + + + + + + false + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + + + + never + + + false + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + + + + junit + junit + 4.13.2 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${env.SMOKE_TEST_SUREFIRE_VERSION} + + + + + diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/main/java/datadog/smoke/Calculator.java b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/main/java/datadog/smoke/Calculator.java new file mode 100644 index 00000000000..2f4461a279d --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/main/java/datadog/smoke/Calculator.java @@ -0,0 +1,11 @@ +package datadog.smoke; + +public class Calculator { + public static int add(int a, int b) { + return a + b; + } + + public static int subtract(int a, int b) { + return a - b; + } +} diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedA.java b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedA.java new file mode 100644 index 00000000000..209173057b4 --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedA.java @@ -0,0 +1,21 @@ +package datadog.smoke; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.OrderWith; +import org.junit.runner.manipulation.Alphanumeric; + +@OrderWith(Alphanumeric.class) +public class TestSucceedA { + + @Test + public void test_succeed() { + assertTrue(Calculator.add(2, 2) == 4); + } + + @Test + public void test_succeed_another() { + assertTrue(Calculator.add(2, 2) == 4); + } +} diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedB.java b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedB.java new file mode 100644 index 00000000000..e5a0037120d --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedB.java @@ -0,0 +1,21 @@ +package datadog.smoke; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.OrderWith; +import org.junit.runner.manipulation.Alphanumeric; + +@OrderWith(Alphanumeric.class) +public class TestSucceedB { + + @Test + public void test_succeed() { + assertTrue(Calculator.add(2, 2) == 4); + } + + @Test + public void test_succeed_another() { + assertTrue(Calculator.add(2, 2) == 4); + } +} diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedC.java b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedC.java new file mode 100644 index 00000000000..f01caf6de11 --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedC.java @@ -0,0 +1,21 @@ +package datadog.smoke; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.OrderWith; +import org.junit.runner.manipulation.Alphanumeric; + +@OrderWith(Alphanumeric.class) +public class TestSucceedC { + + @Test + public void test_succeed() { + assertTrue(Calculator.add(2, 2) == 4); + } + + @Test + public void test_succeed_another() { + assertTrue(Calculator.add(2, 2) == 4); + } +} diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/pom.xml b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/pom.xml new file mode 100644 index 00000000000..54f90b7ee7d --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/pom.xml @@ -0,0 +1,66 @@ + + + + 4.0.0 + com.datadog.ci.test + maven-smoke-test + 1.0-SNAPSHOT + Maven Smoke Tests Project + + + 8 + 8 + UTF-8 + + + + + + + false + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + + + + never + + + false + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + + + + junit + junit + 4.13.2 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${env.SMOKE_TEST_SUREFIRE_VERSION} + + methods + 1 + + + + + + diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/main/java/datadog/smoke/Calculator.java b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/main/java/datadog/smoke/Calculator.java new file mode 100644 index 00000000000..2f4461a279d --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/main/java/datadog/smoke/Calculator.java @@ -0,0 +1,11 @@ +package datadog.smoke; + +public class Calculator { + public static int add(int a, int b) { + return a + b; + } + + public static int subtract(int a, int b) { + return a - b; + } +} diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedA.java b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedA.java new file mode 100644 index 00000000000..3efdcbfe150 --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedA.java @@ -0,0 +1,13 @@ +package datadog.smoke; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class TestSucceedA { + + @Test + public void test_succeed() { + assertTrue(Calculator.add(2, 2) == 4); + } +} diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedB.java b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedB.java new file mode 100644 index 00000000000..2a44846b235 --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedB.java @@ -0,0 +1,13 @@ +package datadog.smoke; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class TestSucceedB { + + @Test + public void test_succeed() { + assertTrue(Calculator.add(2, 2) == 4); + } +} diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedC.java b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedC.java new file mode 100644 index 00000000000..930b6062ef9 --- /dev/null +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedC.java @@ -0,0 +1,13 @@ +package datadog.smoke; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class TestSucceedC { + + @Test + public void test_succeed() { + assertTrue(Calculator.add(2, 2) == 4); + } +} diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_0_0/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_0_0/events.ftl index 028ae502e83..2c16bf028a1 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_0_0/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_0_0/events.ftl @@ -311,6 +311,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -371,6 +372,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_5_0/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_5_0/events.ftl index 028ae502e83..2c16bf028a1 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_5_0/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_surefire_3_5_0/events.ftl @@ -311,6 +311,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -371,6 +372,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_test_management/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_test_management/events.ftl index da63275f2e9..d0e066fc11d 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_test_management/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_test_management/events.ftl @@ -275,6 +275,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -339,6 +340,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -405,6 +407,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -471,6 +474,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -537,6 +541,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -604,6 +609,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -715,6 +721,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_arg_line_property/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_arg_line_property/events.ftl index 43bcef123f8..0236ad535e5 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_arg_line_property/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_arg_line_property/events.ftl @@ -267,6 +267,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_jacoco_and_argline/events.ftl b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_jacoco_and_argline/events.ftl index 15425720a16..00b227bf3aa 100644 --- a/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_jacoco_and_argline/events.ftl +++ b/dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_with_jacoco_and_argline/events.ftl @@ -311,6 +311,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", @@ -371,6 +372,7 @@ "meta" : { "_dd.library_capabilities.auto_test_retries" : "1", "_dd.library_capabilities.early_flake_detection" : "1", + "_dd.library_capabilities.fail_fast_test_order" : "1", "_dd.library_capabilities.impacted_tests" : "1", "_dd.library_capabilities.test_impact_analysis" : "1", "_dd.library_capabilities.test_management.attempt_to_fix" : "2", diff --git a/settings.gradle b/settings.gradle index 299c277d138..615cd539a17 100644 --- a/settings.gradle +++ b/settings.gradle @@ -279,6 +279,7 @@ include ':dd-java-agent:instrumentation:google-pubsub' include ':dd-java-agent:instrumentation:graal:native-image' include ':dd-java-agent:instrumentation:gradle-3.0' include ':dd-java-agent:instrumentation:gradle-8.3' +include ':dd-java-agent:instrumentation:gradle-testing' include ':dd-java-agent:instrumentation:graphql-java' include ':dd-java-agent:instrumentation:graphql-java:graphql-java-14.0' include ':dd-java-agent:instrumentation:graphql-java:graphql-java-20.0' @@ -398,6 +399,7 @@ include ':dd-java-agent:instrumentation:log4j2' include ':dd-java-agent:instrumentation:log4j2:logs-intake' include ':dd-java-agent:instrumentation:logback-1' include ':dd-java-agent:instrumentation:maven-3.2.1' +include ':dd-java-agent:instrumentation:maven-surefire' include ':dd-java-agent:instrumentation:micronaut' include ':dd-java-agent:instrumentation:micronaut:http-server-netty-2.0' include ':dd-java-agent:instrumentation:micronaut:http-server-netty-3.0'