From 6c9a35424c0e1e2e36e7eab3b9822528ebbb187f Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Fri, 28 Mar 2025 10:33:29 +0100 Subject: [PATCH 01/12] add junit4 test ordering --- .../order/FailFastDescriptionComparator.java | 33 ++++++++ .../JUnit4TestOrdererInstrumentation.java | 79 ++++++++++++++++++ .../JUnit4TestSorterInstrumentation.java | 83 +++++++++++++++++++ .../src/test/groovy/JUnit413Test.groovy | 48 ++++++++++- .../java/org/example/ReverseAlphanumeric.java | 27 ++++++ .../test/java/org/example/TestOrderer.java | 24 ++++++ .../src/test/java/org/example/TestSorter.java | 25 ++++++ .../test/java/org/example/TestSucceed.java | 13 +++ .../junit4/JUnit4Instrumentation.java | 25 ++++-- .../junit4/JUnit4TracingListener.java | 2 +- .../instrumentation/junit4/JUnit4Utils.java | 42 +++++++++- .../src/test/groovy/JUnit4Test.groovy | 8 +- .../coverages.ftl | 22 ++--- .../events.ftl | 1 + .../events.ftl | 1 + .../events.ftl | 5 ++ .../test_successful_maven_run/events.ftl | 2 + .../events.ftl | 2 + .../events.ftl | 2 + .../events.ftl | 2 + .../events.ftl | 2 + .../events.ftl | 7 ++ .../events.ftl | 1 + .../events.ftl | 2 + 24 files changed, 433 insertions(+), 25 deletions(-) create mode 100644 dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/FailFastDescriptionComparator.java create mode 100644 dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4TestOrdererInstrumentation.java create mode 100644 dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4TestSorterInstrumentation.java create mode 100644 dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/ReverseAlphanumeric.java create mode 100644 dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestOrderer.java create mode 100644 dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestSorter.java create mode 100644 dd-java-agent/instrumentation/junit-4.10/junit-4.13/src/test/java/org/example/TestSucceed.java 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..1a09a06df5a --- /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,33 @@ +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; + private final Comparator comparator; + + public FailFastDescriptionComparator( + TestEventsHandler handler) { + this.handler = handler; + this.comparator = Comparator.comparing(this::executionPriority).reversed(); + } + + 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 comparator.compare(o1, o2); + } +} 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..c875b3c7e16 --- /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,79 @@ +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.JUnit4Utils; +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(JUnit4Utils.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..e6a63bf050c --- /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,83 @@ +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.JUnit4Utils; +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(JUnit4Utils.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..a674494f241 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,46 @@ 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 +106,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..53b748d26ca 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 @@ -16,7 +16,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..1763a8d1582 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,40 @@ 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 frameworkForClass(Class testClass) { + Runner runner = Request.aClass(testClass).getRunner(); + return runnerToFramework(runner); + } + + 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/test/groovy/JUnit4Test.groovy b/dd-java-agent/instrumentation/junit-4.10/src/test/groovy/JUnit4Test.groovy index 44fb66f6ffc..06f1ff0ee2f 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 @@ -9,6 +9,7 @@ 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 +211,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 +244,6 @@ class JUnit4Test extends CiVisibilityInstrumentationTest { @Override String instrumentedLibraryVersion() { - return Version.id() + return JUnit4Utils.getVersion() } } 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/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_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", From 1d3c3944dffcfecaf62c4b9522a8106e02fc7f54 Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Fri, 28 Mar 2025 17:32:19 +0100 Subject: [PATCH 02/12] add maven-surefire instrumentation for junit4 class ordering --- .../CiVisibilityInstrumentationTest.groovy | 17 +- .../civisibility/CiVisibilitySmokeTest.groovy | 10 +- .../civisibility/CiVisibilityTestUtils.groovy | 20 ++ .../JUnit4TestOrdererInstrumentation.java | 10 +- .../JUnit4TestSorterInstrumentation.java | 10 +- .../src/test/groovy/JUnit413Test.groovy | 27 +- .../junit4/JUnit4TracingListener.java | 1 - .../instrumentation/junit4/JUnit4Utils.java | 7 +- .../src/test/groovy/JUnit4Test.groovy | 1 - .../maven-surefire/build.gradle | 20 ++ .../maven-surefire/gradle.lockfile | 283 ++++++++++++++++++ .../surefire/junit4/FailFastClassOrderer.java | 39 +++ .../JUnit4ClassOrderInstrumentation.java | 89 ++++++ .../datadog/smoketest/MockBackend.groovy | 26 ++ .../datadog/smoketest/MavenSmokeTest.groovy | 159 ++++++++-- .../pom.xml | 62 ++++ .../main/java/datadog/smoke/Calculator.java | 11 + .../test/java/datadog/smoke/TestSucceedA.java | 21 ++ .../test/java/datadog/smoke/TestSucceedB.java | 21 ++ .../test/java/datadog/smoke/TestSucceedC.java | 21 ++ .../pom.xml | 66 ++++ .../main/java/datadog/smoke/Calculator.java | 11 + .../test/java/datadog/smoke/TestSucceedA.java | 13 + .../test/java/datadog/smoke/TestSucceedB.java | 13 + .../test/java/datadog/smoke/TestSucceedC.java | 13 + settings.gradle | 1 + 26 files changed, 916 insertions(+), 56 deletions(-) create mode 100644 dd-java-agent/instrumentation/maven-surefire/build.gradle create mode 100644 dd-java-agent/instrumentation/maven-surefire/gradle.lockfile create mode 100644 dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/FailFastClassOrderer.java create mode 100644 dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/JUnit4ClassOrderInstrumentation.java create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/pom.xml create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/main/java/datadog/smoke/Calculator.java create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedA.java create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedB.java create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering/src/test/java/datadog/smoke/TestSucceedC.java create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/pom.xml create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/main/java/datadog/smoke/Calculator.java create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedA.java create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedB.java create mode 100644 dd-smoke-tests/maven/src/test/resources/test_successful_maven_run_junit4_class_ordering_parallel/src/test/java/datadog/smoke/TestSucceedC.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/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 index c875b3c7e16..27e49fd3bce 100644 --- 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 @@ -43,11 +43,11 @@ public String instrumentedType() { @Override public String[] helperClassNames() { return new String[] { - parentPackageName + ".SkippedByDatadog", - parentPackageName + ".TracingListener", - parentPackageName + ".JUnit4Utils", - parentPackageName + ".TestEventsHandlerHolder", - packageName + ".FailFastDescriptionComparator", + parentPackageName + ".SkippedByDatadog", + parentPackageName + ".TracingListener", + parentPackageName + ".JUnit4Utils", + parentPackageName + ".TestEventsHandlerHolder", + packageName + ".FailFastDescriptionComparator", }; } 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 index e6a63bf050c..ae5af150dc2 100644 --- 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 @@ -51,11 +51,11 @@ public ElementMatcher hierarchyMatcher() { @Override public String[] helperClassNames() { return new String[] { - parentPackageName + ".SkippedByDatadog", - parentPackageName + ".TracingListener", - parentPackageName + ".JUnit4Utils", - parentPackageName + ".TestEventsHandlerHolder", - packageName + ".FailFastDescriptionComparator", + parentPackageName + ".SkippedByDatadog", + parentPackageName + ".TracingListener", + parentPackageName + ".JUnit4Utils", + parentPackageName + ".TestEventsHandlerHolder", + packageName + ".FailFastDescriptionComparator", }; } 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 a674494f241..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 @@ -51,8 +51,16 @@ class JUnit413Test extends CiVisibilityInstrumentationTest { 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")] + "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"() { @@ -65,8 +73,19 @@ class JUnit413Test extends CiVisibilityInstrumentationTest { 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")] + "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"() { 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 53b748d26ca..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; 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 1763a8d1582..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 @@ -353,11 +353,16 @@ public static TestFrameworkInstrumentation runnerToFramework(Runner runner) { } } - public static TestFrameworkInstrumentation frameworkForClass(Class testClass) { + 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(); } 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 06f1ff0ee2f..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,7 +7,6 @@ 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 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..98e78a5ab17 --- /dev/null +++ b/dd-java-agent/instrumentation/maven-surefire/build.gradle @@ -0,0 +1,20 @@ +apply from: "$rootDir/gradle/java.gradle" + +muzzle { + pass { + group = 'org.apache.maven.surefire' + module = 'surefire-junit4' + versions = '[3.0.0,)' + } + pass { + group = 'org.apache.maven.surefire' + module = 'surefire-junit47' + versions = '[3.0.0,)' + } +} + +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 + compileOnly 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/FailFastClassOrderer.java b/dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/FailFastClassOrderer.java new file mode 100644 index 00000000000..0cb1ea4dacf --- /dev/null +++ b/dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/FailFastClassOrderer.java @@ -0,0 +1,39 @@ +package datadog.trace.instrumentation.maven.surefire.junit4; + +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 datadog.trace.instrumentation.junit4.TestEventsHandlerHolder; +import java.lang.reflect.Method; +import java.util.List; + +public abstract class FailFastClassOrderer { + + public static int classExecutionPriority(Class clazz) { + TestFrameworkInstrumentation framework = JUnit4Utils.classToFramework(clazz); + if (framework != TestFrameworkInstrumentation.JUNIT4) { + return 0; + } + + TestEventsHandler testEventsHandler = + TestEventsHandlerHolder.HANDLERS.get(TestFrameworkInstrumentation.JUNIT4); + + 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(); + } +} 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..7a69043225c --- /dev/null +++ b/dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/JUnit4ClassOrderInstrumentation.java @@ -0,0 +1,89 @@ +package datadog.trace.instrumentation.maven.surefire.junit4; + +import static net.bytebuddy.matcher.ElementMatchers.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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.ArrayList; +import java.util.Comparator; +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", + packageName + ".FailFastClassOrderer", + }; + } + + @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( + Comparator.comparing(FailFastClassOrderer::classExecutionPriority).reversed()); + + 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/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_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/settings.gradle b/settings.gradle index b78e2287dda..368648da2e5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -376,6 +376,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' From 06ead3bf65465f72122baf412dcda3ed4a7b0192 Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Mon, 31 Mar 2025 14:58:30 +0200 Subject: [PATCH 03/12] add gradle-8.0 instrumentation for junit4 class ordering --- .../instrumentation/gradle-8.0/build.gradle | 16 ++ .../gradle-8.0/gradle.lockfile | 156 ++++++++++++++++++ ...UnitTestClassProcessorInstrumentation.java | 73 ++++++++ .../DDCollectAllTestClassesExecutor.java | 57 +++++++ ...UnitTestClassProcessorInstrumentation.java | 72 ++++++++ .../order/JUnit4FailFastClassOrderer.java} | 4 +- .../JUnit4ClassOrderInstrumentation.java | 5 +- .../smoketest/GradleDaemonSmokeTest.groovy | 63 ++++++- .../build.gradleTest | 19 +++ .../settings.gradleTest | 1 + .../main/java/datadog/smoke/Calculator.java | 11 ++ .../test/java/datadog/smoke/TestSucceedA.java | 21 +++ .../test/java/datadog/smoke/TestSucceedB.java | 21 +++ .../test/java/datadog/smoke/TestSucceedC.java | 21 +++ settings.gradle | 1 + 15 files changed, 530 insertions(+), 11 deletions(-) create mode 100644 dd-java-agent/instrumentation/gradle-8.0/build.gradle create mode 100644 dd-java-agent/instrumentation/gradle-8.0/gradle.lockfile create mode 100644 dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java create mode 100644 dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java create mode 100644 dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java rename dd-java-agent/instrumentation/{maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/FailFastClassOrderer.java => junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4FailFastClassOrderer.java} (93%) create mode 100644 dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/build.gradleTest create mode 100644 dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/settings.gradleTest create mode 100644 dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/main/java/datadog/smoke/Calculator.java create mode 100644 dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedA.java create mode 100644 dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedB.java create mode 100644 dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/src/test/java/datadog/smoke/TestSucceedC.java diff --git a/dd-java-agent/instrumentation/gradle-8.0/build.gradle b/dd-java-agent/instrumentation/gradle-8.0/build.gradle new file mode 100644 index 00000000000..f9056ea1c6c --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-8.0/build.gradle @@ -0,0 +1,16 @@ +apply from: "$rootDir/gradle/java.gradle" + +repositories { + maven { + url "https://repo.gradle.org/artifactory/libs-releases-local" + } +} + +dependencies { + compileOnly gradleApi() + compileOnly project(":dd-java-agent:instrumentation:junit-4.10") +} + +forbiddenApisMain { + failOnMissingClasses = false +} diff --git a/dd-java-agent/instrumentation/gradle-8.0/gradle.lockfile b/dd-java-agent/instrumentation/gradle-8.0/gradle.lockfile new file mode 100644 index 00000000000..90493a88f9c --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-8.0/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-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java b/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java new file mode 100644 index 00000000000..81b382722b9 --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java @@ -0,0 +1,73 @@ +package datadog.trace.instrumentation.gradle.junit4; + +import static net.bytebuddy.matcher.ElementMatchers.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 datadog.trace.instrumentation.junit4.order.JUnit4FailFastClassOrderer; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import org.gradle.api.Action; +import org.gradle.api.services.ServiceReference; + +@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() + ".JUnit4Utils", + JUnit4Instrumentation.class.getPackage().getName() + ".TestEventsHandlerHolder", + JUnit4Instrumentation.class.getPackage().getName() + ".SkippedByDatadog", + JUnit4Instrumentation.class.getPackage().getName() + ".TracingListener", + JUnit4FailFastClassOrderer.class.getPackage().getName() + ".JUnit4FailFastClassOrderer", + packageName + ".DDCollectAllTestClassesExecutor", + }; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + named("stop"), + AbstractJUnitTestClassProcessorInstrumentation.class.getName() + + "$ProcessAllTestClassesAdvice"); + } + + public static class ProcessAllTestClassesAdvice { + @Advice.OnMethodEnter + public static void onStop( + @Advice.FieldValue(value = "executor") final Action executor) { + 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(); + } + } + } + + // Gradle 8.0 and above + public static String muzzleCheck(ServiceReference serviceReference) { + return serviceReference.value(); + } +} diff --git a/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java b/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java new file mode 100644 index 00000000000..b360985469d --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java @@ -0,0 +1,57 @@ +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.Comparator; +import java.util.List; +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<>(); + Action delegate; + ClassLoader classLoader; + + public DDCollectAllTestClassesExecutor(Action delegate, ClassLoader junitClassLoader) { + this.delegate = delegate; + this.classLoader = junitClassLoader; + } + + @Override + public void execute(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( + Comparator.comparing(JUnit4FailFastClassOrderer::classExecutionPriority).reversed()); + + 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-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java b/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java new file mode 100644 index 00000000000..816f313e57f --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java @@ -0,0 +1,72 @@ +package datadog.trace.instrumentation.gradle.junit4; + +import static net.bytebuddy.matcher.ElementMatchers.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 datadog.trace.instrumentation.junit4.order.JUnit4FailFastClassOrderer; +import java.util.Set; +import net.bytebuddy.asm.Advice; +import org.gradle.api.Action; +import org.gradle.api.services.ServiceReference; + +@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", + JUnit4FailFastClassOrderer.class.getPackage().getName() + ".JUnit4FailFastClassOrderer", + packageName + ".DDCollectAllTestClassesExecutor", + }; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + named("createTestExecutor"), + JUnitTestClassProcessorInstrumentation.class.getName() + "$TestExecutorAdvice"); + } + + public static class TestExecutorAdvice { + @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()); + } + } + + // Gradle 8.0 and above + public static String muzzleCheck(ServiceReference serviceReference) { + return serviceReference.value(); + } +} diff --git a/dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/FailFastClassOrderer.java b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4FailFastClassOrderer.java similarity index 93% rename from dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/FailFastClassOrderer.java rename to dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4FailFastClassOrderer.java index 0cb1ea4dacf..757bb989c2a 100644 --- a/dd-java-agent/instrumentation/maven-surefire/src/main/java/datadog/trace/instrumentation/maven/surefire/junit4/FailFastClassOrderer.java +++ b/dd-java-agent/instrumentation/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/order/JUnit4FailFastClassOrderer.java @@ -1,4 +1,4 @@ -package datadog.trace.instrumentation.maven.surefire.junit4; +package datadog.trace.instrumentation.junit4.order; import datadog.trace.api.civisibility.config.TestIdentifier; import datadog.trace.api.civisibility.config.TestSourceData; @@ -11,7 +11,7 @@ import java.lang.reflect.Method; import java.util.List; -public abstract class FailFastClassOrderer { +public abstract class JUnit4FailFastClassOrderer { public static int classExecutionPriority(Class clazz) { TestFrameworkInstrumentation framework = JUnit4Utils.classToFramework(clazz); 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 index 7a69043225c..448f34144b7 100644 --- 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 @@ -11,6 +11,7 @@ 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.Comparator; @@ -47,7 +48,7 @@ public String[] helperClassNames() { JUnit4Instrumentation.class.getPackage().getName() + ".TestEventsHandlerHolder", JUnit4Instrumentation.class.getPackage().getName() + ".SkippedByDatadog", JUnit4Instrumentation.class.getPackage().getName() + ".TracingListener", - packageName + ".FailFastClassOrderer", + JUnit4FailFastClassOrderer.class.getPackage().getName() + ".JUnit4FailFastClassOrderer", }; } @@ -81,7 +82,7 @@ public static void onSetTestsToRun( } testClasses.sort( - Comparator.comparing(FailFastClassOrderer::classExecutionPriority).reversed()); + Comparator.comparing(JUnit4FailFastClassOrderer::classExecutionPriority).reversed()); testsToRun = new TestsToRun(new LinkedHashSet<>(testClasses)); } 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..386c11caca8 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 @@ -2,23 +2,27 @@ package datadog.smoketest import datadog.trace.api.Config import datadog.trace.api.Platform +import datadog.trace.api.civisibility.CIConstants 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 +81,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, [("${Strings.propertyNameToEnvironmentVariableName(CiVisibilityConfig.CIVISIBILITY_TEST_ORDER)}" as String): "${CIConstants.FAIL_FAST_TEST_ORDER}" as String]) + assertBuildSuccessful(buildResult) + + verifyTestOrder(mockBackend.waitForEvents(eventsNumber), expectedOrder) + + where: + gradleVersion | projectName | flakyTests | expectedOrder | eventsNumber + "8.0" | "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) @@ -145,7 +193,7 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { Files.write(testKitFolder.resolve("gradle.properties"), gradleProperties.getBytes()) } - private BuildResult runGradleTests(String gradleVersion, boolean successExpected = true, boolean configurationCache = false) { + private BuildResult runGradleTests(String gradleVersion, boolean successExpected = true, boolean configurationCache = false, Map environment = [:]) { def arguments = ["test", "--stacktrace"] if (gradleVersion > "4.5") { // warning mode available starting from Gradle 4.5 @@ -154,7 +202,7 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { if (configurationCache) { arguments += ["--configuration-cache", "--rerun-tasks"] } - BuildResult buildResult = runGradle(gradleVersion, arguments, successExpected) + BuildResult buildResult = runGradle(gradleVersion, arguments, successExpected, environment) buildResult } @@ -191,12 +239,13 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { } } - private runGradle(String gradleVersion, List arguments, boolean successExpected) { + private runGradle(String gradleVersion, List arguments, boolean successExpected, Map environment) { GradleRunner gradleRunner = GradleRunner.create() .withTestKitDir(testKitFolder.toFile()) .withProjectDir(projectFolder.toFile()) .withGradleVersion(gradleVersion) .withArguments(arguments) + .withEnvironment(environment) .forwardOutput() println "${new Date()}: $specificationContext.currentIteration.displayName - Starting Gradle run" 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..f4603ff5051 --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-junit-4-class-ordering/build.gradleTest @@ -0,0 +1,19 @@ +apply plugin: 'java' +apply plugin: 'jvm-test-suite' + +repositories { + mavenLocal() + mavenCentral() +} + +testing { + suites { + test { + useJUnit() + + dependencies { + implementation 'junit:junit:4.13' + } + } + } +} 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/settings.gradle b/settings.gradle index 368648da2e5..96bbb809a4d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -256,6 +256,7 @@ include ':dd-java-agent:instrumentation:google-http-client' 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.0' include ':dd-java-agent:instrumentation:gradle-8.3' include ':dd-java-agent:instrumentation:graphql-java' include ':dd-java-agent:instrumentation:graphql-java:graphql-java-14.0' From 56403878d2fc0aab8aa2d19c302b87b85aec997d Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Tue, 1 Apr 2025 11:11:29 +0200 Subject: [PATCH 04/12] update gradle junit instrumentation to support starting on 5.1 --- .../{gradle-8.0 => gradle-5.1}/build.gradle | 0 .../{gradle-8.0 => gradle-5.1}/gradle.lockfile | 0 ...actJUnitTestClassProcessorInstrumentation.java | 15 ++++++--------- .../junit4/DDCollectAllTestClassesExecutor.java | 3 ++- .../JUnitTestClassProcessorInstrumentation.java | 13 +++++-------- settings.gradle | 2 +- 6 files changed, 14 insertions(+), 19 deletions(-) rename dd-java-agent/instrumentation/{gradle-8.0 => gradle-5.1}/build.gradle (100%) rename dd-java-agent/instrumentation/{gradle-8.0 => gradle-5.1}/gradle.lockfile (100%) rename dd-java-agent/instrumentation/{gradle-8.0 => gradle-5.1}/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java (89%) rename dd-java-agent/instrumentation/{gradle-8.0 => gradle-5.1}/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java (95%) rename dd-java-agent/instrumentation/{gradle-8.0 => gradle-5.1}/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java (85%) diff --git a/dd-java-agent/instrumentation/gradle-8.0/build.gradle b/dd-java-agent/instrumentation/gradle-5.1/build.gradle similarity index 100% rename from dd-java-agent/instrumentation/gradle-8.0/build.gradle rename to dd-java-agent/instrumentation/gradle-5.1/build.gradle diff --git a/dd-java-agent/instrumentation/gradle-8.0/gradle.lockfile b/dd-java-agent/instrumentation/gradle-5.1/gradle.lockfile similarity index 100% rename from dd-java-agent/instrumentation/gradle-8.0/gradle.lockfile rename to dd-java-agent/instrumentation/gradle-5.1/gradle.lockfile diff --git a/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java b/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java similarity index 89% rename from dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java rename to dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java index 81b382722b9..6014d5e0db4 100644 --- a/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java +++ b/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.gradle.junit4; -import static net.bytebuddy.matcher.ElementMatchers.named; +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -12,7 +12,7 @@ import java.util.Set; import net.bytebuddy.asm.Advice; import org.gradle.api.Action; -import org.gradle.api.services.ServiceReference; +import org.gradle.internal.actor.Actor; @AutoService(InstrumenterModule.class) public class AbstractJUnitTestClassProcessorInstrumentation extends InstrumenterModule.CiVisibility @@ -34,9 +34,9 @@ public String instrumentedType() { @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() + ".SkippedByDatadog", JUnit4Instrumentation.class.getPackage().getName() + ".TracingListener", JUnit4FailFastClassOrderer.class.getPackage().getName() + ".JUnit4FailFastClassOrderer", packageName + ".DDCollectAllTestClassesExecutor", @@ -52,9 +52,11 @@ public void methodAdvice(MethodTransformer transformer) { } public static class ProcessAllTestClassesAdvice { + @SuppressWarnings("bytebuddy-exception-suppression") @Advice.OnMethodEnter public static void onStop( - @Advice.FieldValue(value = "executor") final Action executor) { + @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); @@ -65,9 +67,4 @@ public static void onStop( } } } - - // Gradle 8.0 and above - public static String muzzleCheck(ServiceReference serviceReference) { - return serviceReference.value(); - } } diff --git a/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java b/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java similarity index 95% rename from dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java rename to dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java index b360985469d..9c77f8dd356 100644 --- a/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java +++ b/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import javax.annotation.Nonnull; import org.gradle.api.Action; import org.gradle.internal.UncheckedException; @@ -26,7 +27,7 @@ public DDCollectAllTestClassesExecutor(Action delegate, ClassLoader juni } @Override - public void execute(String testClassName) { + public void execute(@Nonnull String testClassName) { Class clazz = loadClass(testClassName); TestFrameworkInstrumentation framework = JUnit4Utils.classToFramework(clazz); diff --git a/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java b/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java similarity index 85% rename from dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java rename to dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java index 816f313e57f..c087a90ecd6 100644 --- a/dd-java-agent/instrumentation/gradle-8.0/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java +++ b/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java @@ -1,6 +1,8 @@ package datadog.trace.instrumentation.gradle.junit4; -import static net.bytebuddy.matcher.ElementMatchers.named; +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; @@ -12,7 +14,6 @@ import java.util.Set; import net.bytebuddy.asm.Advice; import org.gradle.api.Action; -import org.gradle.api.services.ServiceReference; @AutoService(InstrumenterModule.class) public class JUnitTestClassProcessorInstrumentation extends InstrumenterModule.CiVisibility @@ -46,11 +47,12 @@ public String[] helperClassNames() { @Override public void methodAdvice(MethodTransformer transformer) { transformer.applyAdvice( - named("createTestExecutor"), + 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) { @@ -64,9 +66,4 @@ public static void onTestExecutorCreation( executor, Thread.currentThread().getContextClassLoader()); } } - - // Gradle 8.0 and above - public static String muzzleCheck(ServiceReference serviceReference) { - return serviceReference.value(); - } } diff --git a/settings.gradle b/settings.gradle index 96bbb809a4d..e81aac308d3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -256,7 +256,7 @@ include ':dd-java-agent:instrumentation:google-http-client' 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.0' +include ':dd-java-agent:instrumentation:gradle-5.1' include ':dd-java-agent:instrumentation:gradle-8.3' include ':dd-java-agent:instrumentation:graphql-java' include ':dd-java-agent:instrumentation:graphql-java:graphql-java-14.0' From e295114f23781555da5840882a630cb61a88e7a2 Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Tue, 1 Apr 2025 11:11:51 +0200 Subject: [PATCH 05/12] remove withEnvironment in smoke tests in favor of build.gradle setup --- .../smoketest/GradleDaemonSmokeTest.groovy | 11 +++++------ .../build.gradleTest | 16 ++++++---------- 2 files changed, 11 insertions(+), 16 deletions(-) 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 386c11caca8..444766421b8 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 @@ -92,14 +92,14 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { mockBackend.givenKnownTest(":test", flakyTest.getSuite(), flakyTest.getName()) } - BuildResult buildResult = runGradleTests(gradleVersion, true, false, [("${Strings.propertyNameToEnvironmentVariableName(CiVisibilityConfig.CIVISIBILITY_TEST_ORDER)}" as String): "${CIConstants.FAIL_FAST_TEST_ORDER}" as String]) + BuildResult buildResult = runGradleTests(gradleVersion, true, false) assertBuildSuccessful(buildResult) verifyTestOrder(mockBackend.waitForEvents(eventsNumber), expectedOrder) where: gradleVersion | projectName | flakyTests | expectedOrder | eventsNumber - "8.0" | "test-succeed-junit-4-class-ordering" | [ + "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") @@ -193,7 +193,7 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { Files.write(testKitFolder.resolve("gradle.properties"), gradleProperties.getBytes()) } - private BuildResult runGradleTests(String gradleVersion, boolean successExpected = true, boolean configurationCache = false, Map environment = [:]) { + private BuildResult runGradleTests(String gradleVersion, boolean successExpected = true, boolean configurationCache = false) { def arguments = ["test", "--stacktrace"] if (gradleVersion > "4.5") { // warning mode available starting from Gradle 4.5 @@ -202,7 +202,7 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { if (configurationCache) { arguments += ["--configuration-cache", "--rerun-tasks"] } - BuildResult buildResult = runGradle(gradleVersion, arguments, successExpected, environment) + BuildResult buildResult = runGradle(gradleVersion, arguments, successExpected) buildResult } @@ -239,13 +239,12 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { } } - private runGradle(String gradleVersion, List arguments, boolean successExpected, Map environment) { + private runGradle(String gradleVersion, List arguments, boolean successExpected) { GradleRunner gradleRunner = GradleRunner.create() .withTestKitDir(testKitFolder.toFile()) .withProjectDir(projectFolder.toFile()) .withGradleVersion(gradleVersion) .withArguments(arguments) - .withEnvironment(environment) .forwardOutput() println "${new Date()}: $specificationContext.currentIteration.displayName - Starting Gradle run" 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 index f4603ff5051..27685459d0e 100644 --- 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 @@ -1,19 +1,15 @@ apply plugin: 'java' -apply plugin: 'jvm-test-suite' repositories { mavenLocal() mavenCentral() } -testing { - suites { - test { - useJUnit() +dependencies { + testImplementation 'junit:junit:4.13.2' +} - dependencies { - implementation 'junit:junit:4.13' - } - } - } +test { + useJUnit() + environment "DD_CIVISIBILITY_TEST_ORDER", "FAILFAST" } From 3a452f975b0aa5e1d2f9a89d38cca377dda50efc Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Tue, 1 Apr 2025 11:14:57 +0200 Subject: [PATCH 06/12] fix spotless and codenarc --- .../gradle/junit4/JUnitTestClassProcessorInstrumentation.java | 4 +++- .../groovy/datadog/smoketest/GradleDaemonSmokeTest.groovy | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java b/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java index c087a90ecd6..66c44085e90 100644 --- a/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java +++ b/dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java @@ -47,7 +47,9 @@ public String[] helperClassNames() { @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"))), + named("createTestExecutor") + .and(takesArgument(0, named("org.gradle.internal.actor.Actor"))) + .and(returns(named("org.gradle.api.Action"))), JUnitTestClassProcessorInstrumentation.class.getName() + "$TestExecutorAdvice"); } 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 444766421b8..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 @@ -2,7 +2,6 @@ package datadog.smoketest import datadog.trace.api.Config import datadog.trace.api.Platform -import datadog.trace.api.civisibility.CIConstants import datadog.trace.api.config.CiVisibilityConfig import datadog.trace.api.config.GeneralConfig import datadog.trace.api.config.TraceInstrumentationConfig From f2a78b36ec9cb2d216394fb1842e488e9a7999ff Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Tue, 1 Apr 2025 14:45:50 +0200 Subject: [PATCH 07/12] PR fixes --- .github/CODEOWNERS | 38 ++++++++++--------- .../build.gradle | 6 --- .../gradle.lockfile | 0 ...UnitTestClassProcessorInstrumentation.java | 3 +- .../DDCollectAllTestClassesExecutor.java | 8 ++-- ...UnitTestClassProcessorInstrumentation.java | 3 +- .../order/FailFastDescriptionComparator.java | 4 +- .../JUnit4TestOrdererInstrumentation.java | 5 ++- .../JUnit4TestSorterInstrumentation.java | 5 ++- .../order/JUnit4FailFastClassOrderer.java | 24 ++++++++---- .../maven-surefire/build.gradle | 2 + .../JUnit4ClassOrderInstrumentation.java | 6 +-- settings.gradle | 2 +- 13 files changed, 56 insertions(+), 50 deletions(-) rename dd-java-agent/instrumentation/{gradle-5.1 => gradle-testing}/build.gradle (67%) rename dd-java-agent/instrumentation/{gradle-5.1 => gradle-testing}/gradle.lockfile (100%) rename dd-java-agent/instrumentation/{gradle-5.1 => gradle-testing}/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java (93%) rename dd-java-agent/instrumentation/{gradle-5.1 => gradle-testing}/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java (89%) rename dd-java-agent/instrumentation/{gradle-5.1 => gradle-testing}/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java (94%) 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/instrumentation/gradle-5.1/build.gradle b/dd-java-agent/instrumentation/gradle-testing/build.gradle similarity index 67% rename from dd-java-agent/instrumentation/gradle-5.1/build.gradle rename to dd-java-agent/instrumentation/gradle-testing/build.gradle index f9056ea1c6c..f9e5631c426 100644 --- a/dd-java-agent/instrumentation/gradle-5.1/build.gradle +++ b/dd-java-agent/instrumentation/gradle-testing/build.gradle @@ -1,11 +1,5 @@ apply from: "$rootDir/gradle/java.gradle" -repositories { - maven { - url "https://repo.gradle.org/artifactory/libs-releases-local" - } -} - dependencies { compileOnly gradleApi() compileOnly project(":dd-java-agent:instrumentation:junit-4.10") diff --git a/dd-java-agent/instrumentation/gradle-5.1/gradle.lockfile b/dd-java-agent/instrumentation/gradle-testing/gradle.lockfile similarity index 100% rename from dd-java-agent/instrumentation/gradle-5.1/gradle.lockfile rename to dd-java-agent/instrumentation/gradle-testing/gradle.lockfile diff --git a/dd-java-agent/instrumentation/gradle-5.1/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 similarity index 93% rename from dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java rename to dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/AbstractJUnitTestClassProcessorInstrumentation.java index 6014d5e0db4..0f33d011b06 100644 --- a/dd-java-agent/instrumentation/gradle-5.1/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 @@ -8,7 +8,6 @@ import datadog.trace.api.Config; import datadog.trace.api.civisibility.CIConstants; import datadog.trace.instrumentation.junit4.JUnit4Instrumentation; -import datadog.trace.instrumentation.junit4.order.JUnit4FailFastClassOrderer; import java.util.Set; import net.bytebuddy.asm.Advice; import org.gradle.api.Action; @@ -38,7 +37,7 @@ public String[] helperClassNames() { JUnit4Instrumentation.class.getPackage().getName() + ".JUnit4Utils", JUnit4Instrumentation.class.getPackage().getName() + ".TestEventsHandlerHolder", JUnit4Instrumentation.class.getPackage().getName() + ".TracingListener", - JUnit4FailFastClassOrderer.class.getPackage().getName() + ".JUnit4FailFastClassOrderer", + JUnit4Instrumentation.class.getPackage().getName() + ".order.JUnit4FailFastClassOrderer", packageName + ".DDCollectAllTestClassesExecutor", }; } diff --git a/dd-java-agent/instrumentation/gradle-5.1/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 similarity index 89% rename from dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java rename to dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/DDCollectAllTestClassesExecutor.java index 9c77f8dd356..7648ae06e1b 100644 --- a/dd-java-agent/instrumentation/gradle-5.1/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 @@ -5,7 +5,6 @@ import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder; import datadog.trace.instrumentation.junit4.order.JUnit4FailFastClassOrderer; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import javax.annotation.Nonnull; import org.gradle.api.Action; @@ -18,8 +17,8 @@ */ public class DDCollectAllTestClassesExecutor implements Action { private final List> testClasses = new ArrayList<>(); - Action delegate; - ClassLoader classLoader; + private final Action delegate; + private final ClassLoader classLoader; public DDCollectAllTestClassesExecutor(Action delegate, ClassLoader junitClassLoader) { this.delegate = delegate; @@ -41,7 +40,8 @@ public void execute(@Nonnull String testClassName) { public void processAllTestClasses() { testClasses.sort( - Comparator.comparing(JUnit4FailFastClassOrderer::classExecutionPriority).reversed()); + new JUnit4FailFastClassOrderer( + TestEventsHandlerHolder.HANDLERS.get(TestFrameworkInstrumentation.JUNIT4))); for (Class clazz : testClasses) { delegate.execute(clazz.getName()); diff --git a/dd-java-agent/instrumentation/gradle-5.1/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 similarity index 94% rename from dd-java-agent/instrumentation/gradle-5.1/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java rename to dd-java-agent/instrumentation/gradle-testing/src/main/groovy/datadog/trace/instrumentation/gradle/junit4/JUnitTestClassProcessorInstrumentation.java index 66c44085e90..aedd7f5b05e 100644 --- a/dd-java-agent/instrumentation/gradle-5.1/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 @@ -10,7 +10,6 @@ import datadog.trace.api.Config; import datadog.trace.api.civisibility.CIConstants; import datadog.trace.instrumentation.junit4.JUnit4Instrumentation; -import datadog.trace.instrumentation.junit4.order.JUnit4FailFastClassOrderer; import java.util.Set; import net.bytebuddy.asm.Advice; import org.gradle.api.Action; @@ -39,7 +38,7 @@ public String[] helperClassNames() { JUnit4Instrumentation.class.getPackage().getName() + ".TestEventsHandlerHolder", JUnit4Instrumentation.class.getPackage().getName() + ".SkippedByDatadog", JUnit4Instrumentation.class.getPackage().getName() + ".TracingListener", - JUnit4FailFastClassOrderer.class.getPackage().getName() + ".JUnit4FailFastClassOrderer", + JUnit4Instrumentation.class.getPackage().getName() + ".order.JUnit4FailFastClassOrderer", packageName + ".DDCollectAllTestClassesExecutor", }; } 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 index 1a09a06df5a..50741f60564 100644 --- 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 @@ -12,12 +12,10 @@ public class FailFastDescriptionComparator implements Comparator { private final TestEventsHandler handler; - private final Comparator comparator; public FailFastDescriptionComparator( TestEventsHandler handler) { this.handler = handler; - this.comparator = Comparator.comparing(this::executionPriority).reversed(); } private int executionPriority(Description description) { @@ -28,6 +26,6 @@ private int executionPriority(Description description) { @Override public int compare(Description o1, Description o2) { - return comparator.compare(o1, 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 index 27e49fd3bce..e871fd9bb92 100644 --- 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 @@ -11,7 +11,7 @@ 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 datadog.trace.instrumentation.junit4.JUnit4Instrumentation; import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder; import datadog.trace.util.Strings; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -24,7 +24,8 @@ @AutoService(InstrumenterModule.class) public class JUnit4TestOrdererInstrumentation extends InstrumenterModule.CiVisibility implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { - private final String parentPackageName = Strings.getPackageName(JUnit4Utils.class.getName()); + private final String parentPackageName = + Strings.getPackageName(JUnit4Instrumentation.class.getName()); public JUnit4TestOrdererInstrumentation() { super("ci-visibility", "junit-4", "test-order"); 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 index ae5af150dc2..d0d52f689eb 100644 --- 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 @@ -14,7 +14,7 @@ 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 datadog.trace.instrumentation.junit4.JUnit4Instrumentation; import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder; import datadog.trace.util.Strings; import java.util.Set; @@ -26,7 +26,8 @@ @AutoService(InstrumenterModule.class) public class JUnit4TestSorterInstrumentation extends InstrumenterModule.CiVisibility implements Instrumenter.ForTypeHierarchy, Instrumenter.HasMethodAdvice { - private final String parentPackageName = Strings.getPackageName(JUnit4Utils.class.getName()); + private final String parentPackageName = + Strings.getPackageName(JUnit4Instrumentation.class.getName()); public JUnit4TestSorterInstrumentation() { super("ci-visibility", "junit-4", "test-order"); 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 index 757bb989c2a..90cef497140 100644 --- 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 @@ -7,21 +7,26 @@ import datadog.trace.api.civisibility.events.TestSuiteDescriptor; import datadog.trace.api.civisibility.telemetry.tag.TestFrameworkInstrumentation; import datadog.trace.instrumentation.junit4.JUnit4Utils; -import datadog.trace.instrumentation.junit4.TestEventsHandlerHolder; import java.lang.reflect.Method; +import java.util.Comparator; import java.util.List; +import javax.annotation.Nullable; -public abstract class JUnit4FailFastClassOrderer { +public class JUnit4FailFastClassOrderer implements Comparator> { - public static int classExecutionPriority(Class clazz) { + @Nullable private final TestEventsHandler testEventsHandler; + + public JUnit4FailFastClassOrderer( + @Nullable TestEventsHandler testEventsHandler) { + this.testEventsHandler = testEventsHandler; + } + + public int classExecutionPriority(Class clazz) { TestFrameworkInstrumentation framework = JUnit4Utils.classToFramework(clazz); - if (framework != TestFrameworkInstrumentation.JUNIT4) { + if (testEventsHandler == null || framework != TestFrameworkInstrumentation.JUNIT4) { return 0; } - TestEventsHandler testEventsHandler = - TestEventsHandlerHolder.HANDLERS.get(TestFrameworkInstrumentation.JUNIT4); - List children = JUnit4Utils.getTestMethods(clazz); if (children.isEmpty()) { return 0; @@ -36,4 +41,9 @@ public static int classExecutionPriority(Class clazz) { return childrenPrioritySum / children.size(); } + + @Override + public int compare(Class o1, Class o2) { + return classExecutionPriority(o2) - classExecutionPriority(o1); + } } diff --git a/dd-java-agent/instrumentation/maven-surefire/build.gradle b/dd-java-agent/instrumentation/maven-surefire/build.gradle index 98e78a5ab17..61d85f2ba01 100644 --- a/dd-java-agent/instrumentation/maven-surefire/build.gradle +++ b/dd-java-agent/instrumentation/maven-surefire/build.gradle @@ -5,11 +5,13 @@ muzzle { group = 'org.apache.maven.surefire' module = 'surefire-junit4' versions = '[3.0.0,)' + extraDependency 'junit:junit:4.10' } pass { group = 'org.apache.maven.surefire' module = 'surefire-junit47' versions = '[3.0.0,)' + extraDependency 'junit:junit:4.10' } } 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 index 448f34144b7..67a013b5c46 100644 --- 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 @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.maven.surefire.junit4; -import static net.bytebuddy.matcher.ElementMatchers.named; +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -14,7 +14,6 @@ import datadog.trace.instrumentation.junit4.order.JUnit4FailFastClassOrderer; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; -import java.util.Comparator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -82,7 +81,8 @@ public static void onSetTestsToRun( } testClasses.sort( - Comparator.comparing(JUnit4FailFastClassOrderer::classExecutionPriority).reversed()); + new JUnit4FailFastClassOrderer( + TestEventsHandlerHolder.HANDLERS.get(TestFrameworkInstrumentation.JUNIT4))); testsToRun = new TestsToRun(new LinkedHashSet<>(testClasses)); } diff --git a/settings.gradle b/settings.gradle index e81aac308d3..24c8a1fcf88 100644 --- a/settings.gradle +++ b/settings.gradle @@ -256,8 +256,8 @@ include ':dd-java-agent:instrumentation:google-http-client' 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-5.1' 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' From fe09e0d228be12f48a059e6c476fe3f19637b9ae Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Wed, 2 Apr 2025 14:17:45 +0200 Subject: [PATCH 08/12] fix muzzle checks --- dd-java-agent/instrumentation/gradle-testing/build.gradle | 7 +++++++ .../AbstractJUnitTestClassProcessorInstrumentation.java | 5 +++++ .../junit4/JUnitTestClassProcessorInstrumentation.java | 5 +++++ dd-java-agent/instrumentation/maven-surefire/build.gradle | 4 +++- .../surefire/junit4/JUnit4ClassOrderInstrumentation.java | 2 +- 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/instrumentation/gradle-testing/build.gradle b/dd-java-agent/instrumentation/gradle-testing/build.gradle index f9e5631c426..0d40b85c753 100644 --- a/dd-java-agent/instrumentation/gradle-testing/build.gradle +++ b/dd-java-agent/instrumentation/gradle-testing/build.gradle @@ -1,5 +1,12 @@ 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") 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 index 0f33d011b06..04ef0cd181b 100644 --- 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 @@ -50,6 +50,11 @@ public void methodAdvice(MethodTransformer transformer) { + "$ProcessAllTestClassesAdvice"); } + @Override + public String muzzleDirective() { + return "skipMuzzle"; + } + public static class ProcessAllTestClassesAdvice { @SuppressWarnings("bytebuddy-exception-suppression") @Advice.OnMethodEnter 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 index aedd7f5b05e..4b38d3151b9 100644 --- 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 @@ -43,6 +43,11 @@ public String[] helperClassNames() { }; } + @Override + public String muzzleDirective() { + return "skipMuzzle"; + } + @Override public void methodAdvice(MethodTransformer transformer) { transformer.applyAdvice( diff --git a/dd-java-agent/instrumentation/maven-surefire/build.gradle b/dd-java-agent/instrumentation/maven-surefire/build.gradle index 61d85f2ba01..f540b7413b1 100644 --- a/dd-java-agent/instrumentation/maven-surefire/build.gradle +++ b/dd-java-agent/instrumentation/maven-surefire/build.gradle @@ -5,12 +5,14 @@ muzzle { 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' } } @@ -18,5 +20,5 @@ muzzle { 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 - compileOnly project(":dd-java-agent:instrumentation:junit-4.10") + implementation project(":dd-java-agent:instrumentation:junit-4.10") } 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 index 67a013b5c46..23445da5bda 100644 --- 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 @@ -47,7 +47,7 @@ public String[] helperClassNames() { JUnit4Instrumentation.class.getPackage().getName() + ".TestEventsHandlerHolder", JUnit4Instrumentation.class.getPackage().getName() + ".SkippedByDatadog", JUnit4Instrumentation.class.getPackage().getName() + ".TracingListener", - JUnit4FailFastClassOrderer.class.getPackage().getName() + ".JUnit4FailFastClassOrderer", + JUnit4Instrumentation.class.getPackage().getName() + ".order.JUnit4FailFastClassOrderer", }; } From 4c3e430ac6e53c7e928b9ea65876de44b1caa0c4 Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Thu, 3 Apr 2025 12:23:52 +0200 Subject: [PATCH 09/12] Update system-tests to 2799fa982318da14c9d3e5f722abdc670d2802c3 --- .circleci/config.continue.yml.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.continue.yml.j2 b/.circleci/config.continue.yml.j2 index d519d2536b1..d12eef32d24 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 69a5e874384dd256e2e3f42fc1c95807a67efbe6 +default_system_tests_commit: &default_system_tests_commit 2799fa982318da14c9d3e5f722abdc670d2802c3 parameters: nightly: From f59331e43cf3c2c8107aba05d4ae8ac5b3b04d37 Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Fri, 4 Apr 2025 11:06:39 +0200 Subject: [PATCH 10/12] update gradle-testing dependency to implementation Co-authored-by: Nikita Tkachenko <121111529+nikita-tkachenko-datadog@users.noreply.github.com> --- dd-java-agent/instrumentation/gradle-testing/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/instrumentation/gradle-testing/build.gradle b/dd-java-agent/instrumentation/gradle-testing/build.gradle index 0d40b85c753..bebbc730cdf 100644 --- a/dd-java-agent/instrumentation/gradle-testing/build.gradle +++ b/dd-java-agent/instrumentation/gradle-testing/build.gradle @@ -9,7 +9,7 @@ repositories { // gradle >= v5.1 dependencies { compileOnly gradleApi() - compileOnly project(":dd-java-agent:instrumentation:junit-4.10") + implementation project(":dd-java-agent:instrumentation:junit-4.10") } forbiddenApisMain { From df417bd2cd67119d3cb11028c9cff76b8f1a46a6 Mon Sep 17 00:00:00 2001 From: Daniel Mohedano Date: Fri, 4 Apr 2025 11:51:18 +0200 Subject: [PATCH 11/12] Revert "update gradle-testing dependency to implementation" This reverts commit f59331e43cf3c2c8107aba05d4ae8ac5b3b04d37. --- dd-java-agent/instrumentation/gradle-testing/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/instrumentation/gradle-testing/build.gradle b/dd-java-agent/instrumentation/gradle-testing/build.gradle index bebbc730cdf..0d40b85c753 100644 --- a/dd-java-agent/instrumentation/gradle-testing/build.gradle +++ b/dd-java-agent/instrumentation/gradle-testing/build.gradle @@ -9,7 +9,7 @@ repositories { // gradle >= v5.1 dependencies { compileOnly gradleApi() - implementation project(":dd-java-agent:instrumentation:junit-4.10") + compileOnly project(":dd-java-agent:instrumentation:junit-4.10") } forbiddenApisMain { From 0c2e77f2780af47879f925d0875fbec9da73d1c2 Mon Sep 17 00:00:00 2001 From: Andrea Marziali Date: Fri, 4 Apr 2025 15:13:05 +0200 Subject: [PATCH 12/12] Do not use strict write with latest lettuce --- dd-java-agent/instrumentation/lettuce-5/build.gradle | 1 + .../src/test/groovy/Lettuce5ClientTestBase.groovy | 7 +++++++ 2 files changed, 8 insertions(+) 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"