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 7d6352d308e..5e4c61cbffd 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 @@ -103,6 +103,12 @@ abstract class CiVisibilityTestUtils { try { JSONAssert.assertEquals(expectedEvents, actualEvents, comparisonMode) } catch (AssertionError e) { + if (ciRun) { + // When running in CI the assertion error message does not contain the actual diff, + // so we print the events to the console to help debug the issue + println "Expected events: $expectedEvents" + println "Actual events: $actualEvents" + } throw new org.opentest4j.AssertionFailedError("Events mismatch", expectedEvents, actualEvents, e) } @@ -111,6 +117,12 @@ abstract class CiVisibilityTestUtils { try { JSONAssert.assertEquals(expectedCoverages, actualCoverages, comparisonMode) } catch (AssertionError e) { + if (ciRun) { + // When running in CI the assertion error message does not contain the actual diff, + // so we print the events to the console to help debug the issue + println "Expected coverages: $expectedCoverages" + println "Actual coverages: $actualCoverages" + } throw new org.opentest4j.AssertionFailedError("Coverages mismatch", expectedCoverages, actualCoverages, e) } diff --git a/dd-java-agent/instrumentation/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/GradleDaemonInjectionUtils.java b/dd-java-agent/instrumentation/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/GradleDaemonInjectionUtils.java index cebfcff24d3..aaf161be27c 100644 --- a/dd-java-agent/instrumentation/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/GradleDaemonInjectionUtils.java +++ b/dd-java-agent/instrumentation/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/GradleDaemonInjectionUtils.java @@ -1,6 +1,9 @@ package datadog.trace.instrumentation.gradle; +import static datadog.trace.util.Strings.propertyNameToSystemPropertyName; + import datadog.trace.api.Config; +import datadog.trace.api.config.CiVisibilityConfig; import java.io.File; import java.nio.file.Path; import java.util.HashMap; @@ -11,17 +14,30 @@ public class GradleDaemonInjectionUtils { public static Map addJavaagentToGradleDaemonProperties( Map jvmOptions) { + Properties systemProperties = System.getProperties(); + if (systemProperties.containsKey( + propertyNameToSystemPropertyName( + CiVisibilityConfig.CIVISIBILITY_INJECTED_TRACER_VERSION))) { + // This Gradle launcher is started by a process that is itself instrumented, + // most likely this is a Gradle build using Gradle Test Kit to fork another Gradle instance + // (e.g. to test a Gradle plugin). + // We don't want to instrument/trace such "nested" Gradle instances + return jvmOptions; + } + File agentJar = Config.get().getCiVisibilityAgentJarFile(); Path agentJarPath = agentJar.toPath(); - StringBuilder agentArg = new StringBuilder("-javaagent:").append(agentJarPath).append('='); - Properties systemProperties = System.getProperties(); for (Map.Entry e : systemProperties.entrySet()) { String propertyName = (String) e.getKey(); Object propertyValue = e.getValue(); if (propertyName.startsWith(Config.PREFIX)) { - agentArg.append(propertyName).append('=').append(propertyValue).append(','); + agentArg + .append(propertyName) + .append("='") + .append(String.valueOf(propertyValue).replace("'", "'\\''")) + .append("',"); } } diff --git a/dd-java-agent/instrumentation/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/GradleServiceValidationInstrumentation.java b/dd-java-agent/instrumentation/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/GradleServiceValidationInstrumentation.java new file mode 100644 index 00000000000..92ac63f9ef2 --- /dev/null +++ b/dd-java-agent/instrumentation/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/GradleServiceValidationInstrumentation.java @@ -0,0 +1,63 @@ +package datadog.trace.instrumentation.gradle; + +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 java.util.Set; +import net.bytebuddy.asm.Advice; + +/** + * We inject {@link CiVisibilityGradleListener} into Gradle and register it with {@code + * Scope.Build.class} scope. + * + *

A class named {@code org.gradle.internal.service.ServiceScopeValidator} checks that every + * service registered with a scope is annotated with {@code @ServiceScope(.class)}. + * + *

We cannot annotate our service, as {@code Scope.Build.class} is a recent addition: we need to + * support older Gradle versions, besides this class is absent in the Gradle API version that the + * tracer currently uses. + * + *

To suppress validation for our service we patch a "workaround" class that is used internally + * by Gradle. + */ +@AutoService(InstrumenterModule.class) +public class GradleServiceValidationInstrumentation extends InstrumenterModule.CiVisibility + implements Instrumenter.ForSingleType, Instrumenter.HasMethodAdvice { + + public GradleServiceValidationInstrumentation() { + super("gradle", "gradle-build-scope-services"); + } + + @Override + public String instrumentedType() { + return "org.gradle.internal.service.ServiceScopeValidatorWorkarounds"; + } + + @Override + public boolean isApplicable(Set enabledSystems) { + return super.isApplicable(enabledSystems) + && Config.get().isCiVisibilityBuildInstrumentationEnabled(); + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + named("shouldSuppressValidation").and(takesArgument(0, Class.class)), + getClass().getName() + "$SuppressValidation"); + } + + public static class SuppressValidation { + @Advice.OnMethodExit(suppress = Throwable.class) + public static void suppressValidationForCiVisService( + @Advice.Argument(0) final Class validatedClass, + @Advice.Return(readOnly = false) boolean suppressValidation) { + if (validatedClass.getName().endsWith("CiVisibilityGradleListener")) { + suppressValidation = true; + } + } + } +} 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 ebe0f6a285c..ae8aea6af5a 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 @@ -1,20 +1,17 @@ package datadog.smoketest - import datadog.trace.api.Config import datadog.trace.api.Platform import datadog.trace.api.config.CiVisibilityConfig import datadog.trace.api.config.GeneralConfig +import datadog.trace.api.config.TraceInstrumentationConfig import datadog.trace.util.Strings 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.Download -import org.gradle.wrapper.Install -import org.gradle.wrapper.PathAssembler -import org.gradle.wrapper.WrapperConfiguration +import org.gradle.wrapper.* import spock.lang.IgnoreIf import spock.lang.Shared import spock.lang.TempDir @@ -49,34 +46,35 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { runGradleTest(gradleVersion, projectName, false, successExpected, false, expectedTraces, expectedCoverages) where: - gradleVersion | projectName | successExpected | expectedTraces | expectedCoverages - "3.0" | "test-succeed-old-gradle" | true | 5 | 1 - "7.6.4" | "test-succeed-legacy-instrumentation" | true | 5 | 1 - "7.6.4" | "test-succeed-multi-module-legacy-instrumentation" | true | 7 | 2 - "7.6.4" | "test-succeed-multi-forks-legacy-instrumentation" | true | 6 | 2 - "7.6.4" | "test-skip-legacy-instrumentation" | true | 2 | 0 - "7.6.4" | "test-failed-legacy-instrumentation" | false | 4 | 0 - "7.6.4" | "test-corrupted-config-legacy-instrumentation" | false | 1 | 0 + gradleVersion | projectName | successExpected | expectedTraces | expectedCoverages + "3.0" | "test-succeed-old-gradle" | true | 5 | 1 + "7.6.4" | "test-succeed-legacy-instrumentation" | true | 5 | 1 + "7.6.4" | "test-succeed-multi-module-legacy-instrumentation" | true | 7 | 2 + "7.6.4" | "test-succeed-multi-forks-legacy-instrumentation" | true | 6 | 2 + "7.6.4" | "test-skip-legacy-instrumentation" | true | 2 | 0 + "7.6.4" | "test-failed-legacy-instrumentation" | false | 4 | 0 + "7.6.4" | "test-corrupted-config-legacy-instrumentation" | false | 1 | 0 } def "test #projectName, v#gradleVersion, configCache: #configurationCache"() { runGradleTest(gradleVersion, projectName, configurationCache, successExpected, flakyRetries, expectedTraces, expectedCoverages) where: - gradleVersion | projectName | configurationCache | successExpected | flakyRetries | expectedTraces | expectedCoverages - "8.3" | "test-succeed-new-instrumentation" | false | true | false | 5 | 1 - "8.9" | "test-succeed-new-instrumentation" | false | true | false | 5 | 1 - LATEST_GRADLE_VERSION | "test-succeed-new-instrumentation" | false | true | false | 5 | 1 - "8.3" | "test-succeed-new-instrumentation" | true | true | false | 5 | 1 - "8.9" | "test-succeed-new-instrumentation" | true | true | false | 5 | 1 - LATEST_GRADLE_VERSION | "test-succeed-new-instrumentation" | true | true | false | 5 | 1 - LATEST_GRADLE_VERSION | "test-succeed-multi-module-new-instrumentation" | false | true | false | 7 | 2 - LATEST_GRADLE_VERSION | "test-succeed-multi-forks-new-instrumentation" | false | true | false | 6 | 2 - LATEST_GRADLE_VERSION | "test-skip-new-instrumentation" | false | true | false | 2 | 0 - LATEST_GRADLE_VERSION | "test-failed-new-instrumentation" | false | false | false | 4 | 0 - LATEST_GRADLE_VERSION | "test-corrupted-config-new-instrumentation" | false | false | false | 1 | 0 - LATEST_GRADLE_VERSION | "test-succeed-junit-5" | false | true | false | 5 | 1 - LATEST_GRADLE_VERSION | "test-failed-flaky-retries" | false | false | true | 8 | 0 + gradleVersion | projectName | configurationCache | successExpected | flakyRetries | expectedTraces | expectedCoverages + "8.3" | "test-succeed-new-instrumentation" | false | true | false | 5 | 1 + "8.9" | "test-succeed-new-instrumentation" | false | true | false | 5 | 1 + LATEST_GRADLE_VERSION | "test-succeed-new-instrumentation" | false | true | false | 5 | 1 + "8.3" | "test-succeed-new-instrumentation" | true | true | false | 5 | 1 + "8.9" | "test-succeed-new-instrumentation" | true | true | false | 5 | 1 + LATEST_GRADLE_VERSION | "test-succeed-new-instrumentation" | true | true | false | 5 | 1 + LATEST_GRADLE_VERSION | "test-succeed-multi-module-new-instrumentation" | false | true | false | 7 | 2 + LATEST_GRADLE_VERSION | "test-succeed-multi-forks-new-instrumentation" | false | true | false | 6 | 2 + LATEST_GRADLE_VERSION | "test-skip-new-instrumentation" | false | true | false | 2 | 0 + LATEST_GRADLE_VERSION | "test-failed-new-instrumentation" | false | false | false | 4 | 0 + LATEST_GRADLE_VERSION | "test-corrupted-config-new-instrumentation" | false | false | false | 1 | 0 + LATEST_GRADLE_VERSION | "test-succeed-junit-5" | false | true | false | 5 | 1 + LATEST_GRADLE_VERSION | "test-failed-flaky-retries" | false | false | true | 8 | 0 + LATEST_GRADLE_VERSION | "test-succeed-gradle-plugin-test" | false | true | false | 5 | 0 } private runGradleTest(String gradleVersion, String projectName, boolean configurationCache, boolean successExpected, boolean flakyRetries, int expectedTraces, int expectedCoverages) { @@ -131,6 +129,16 @@ class GradleDaemonSmokeTest extends AbstractGradleTest { "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_AGENTLESS_ENABLED)}=true," + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_GIT_UPLOAD_ENABLED)}=false," + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_CIPROVIDER_INTEGRATION_ENABLED)}=false," + + /* + * Some of the smoke tests (in particular the one with the Gradle plugin), are using Gradle Test Kit for their tests. + * Gradle Test Kit needs to do a "chmod" when starting a Gradle Daemon. + * This "chmod" operation is traced by datadog.trace.instrumentation.java.lang.ProcessImplInstrumentation and is reported as a span. + * The problem is that the "chmod" only happens when running in CI (could be due to differences in OS or FS permissions), + * so when running the tests locally, the "chmod" span is not there. + * This causes the tests to fail because the number of reported traces is different. + * To avoid this discrepancy between local and CI runs, we disable tracing instrumentations. + */ + "${Strings.propertyNameToSystemPropertyName(TraceInstrumentationConfig.TRACE_ENABLED)}=false," + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_JACOCO_PLUGIN_VERSION)}=$JACOCO_PLUGIN_VERSION," + "${Strings.propertyNameToSystemPropertyName(CiVisibilityConfig.CIVISIBILITY_AGENTLESS_URL)}=${mockBackend.intakeUrl}" diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/build.gradleTest b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/build.gradleTest new file mode 100644 index 00000000000..f8a38f33853 --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/build.gradleTest @@ -0,0 +1,28 @@ +plugins { + id 'java' + id 'java-gradle-plugin' +} + +gradlePlugin { + plugins { + mySimplePlugin { + id = 'datadog.smoke.helloplugin' + implementationClass = 'datadog.smoke.HelloPlugin' + } + } +} + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + testImplementation gradleTestKit() + + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2' +} + +tasks.withType(Test).configureEach { + useJUnitPlatform() +} diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/coverages.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/coverages.ftl new file mode 100644 index 00000000000..64b294628d6 --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/coverages.ftl @@ -0,0 +1,9 @@ +[ { + "files" : [ { + "bitmap" : "AAAAx98=", + "filename" : "src/test/java/datadog/smoke/HelloPluginFunctionalTest.java" + } ], + "span_id" : ${content_span_id_4}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id} +} ] \ No newline at end of file diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl new file mode 100644 index 00000000000..4cc0fb7e6f6 --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/events.ftl @@ -0,0 +1,459 @@ +[ { + "content" : { + "duration" : ${content_duration}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "gradle", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test_session_end", + "test.code_coverage.backfilled" : "true", + "test.code_coverage.enabled" : "true", + "test.command" : "gradle test", + "test.framework" : "junit5", + "test.framework_version" : "5.10.2", + "test.itr.tests_skipping.enabled" : "true", + "test.itr.tests_skipping.type" : "test", + "test.status" : "pass", + "test.toolchain" : ${content_meta_test_toolchain}, + "test.type" : "test", + "test_session.name" : "gradle test" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id}, + "test.code_coverage.lines_pct" : 0, + "test.itr.tests_skipping.count" : 0 + }, + "name" : "gradle.test_session", + "resource" : ":", + "service" : "test-gradle-service", + "start" : ${content_start}, + "test_session_id" : ${content_test_session_id} + }, + "type" : "test_session_end", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_2}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_2}, + "_dd.test.is_user_provided_service" : "true", + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "gradle", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test_module_end", + "test.code_coverage.backfilled" : "true", + "test.code_coverage.enabled" : "true", + "test.command" : "gradle test", + "test.framework" : "junit5", + "test.framework_version" : "5.10.2", + "test.itr.tests_skipping.enabled" : "true", + "test.itr.tests_skipping.type" : "test", + "test.module" : ":test", + "test.status" : "pass", + "test.type" : "test", + "test_session.name" : "gradle test" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_2}, + "test.code_coverage.lines_pct" : 0, + "test.itr.tests_skipping.count" : 0 + }, + "name" : "gradle.test_module", + "resource" : ":test", + "service" : "test-gradle-service", + "start" : ${content_start_2}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id} + }, + "type" : "test_module_end", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_3}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_3}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "classes", + "parent_id" : ${content_test_session_id}, + "resource" : "classes", + "service" : "test-gradle-service", + "span_id" : ${content_span_id}, + "start" : ${content_start_3}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_4}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_4}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "compileJava", + "parent_id" : ${content_test_session_id}, + "resource" : "compileJava", + "service" : "test-gradle-service", + "span_id" : ${content_span_id_2}, + "start" : ${content_start_4}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_5}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_5}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "compileTestJava", + "parent_id" : ${content_test_session_id}, + "resource" : "compileTestJava", + "service" : "test-gradle-service", + "span_id" : ${content_span_id_3}, + "start" : ${content_start_5}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_6}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_6}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id_2}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test_suite_end", + "test.framework" : "junit5", + "test.framework_version" : "5.10.2", + "test.module" : ":test", + "test.source.file" : "src/test/java/datadog/smoke/HelloPluginFunctionalTest.java", + "test.status" : "pass", + "test.suite" : "datadog.smoke.HelloPluginFunctionalTest", + "test.type" : "test", + "test_session.name" : "gradle test" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_3}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id_2}, + "test.source.end" : 40, + "test.source.start" : 16 + }, + "name" : "junit.test_suite", + "resource" : "datadog.smoke.HelloPluginFunctionalTest", + "service" : "test-gradle-service", + "start" : ${content_start_6}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id} + }, + "type" : "test_suite_end", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_7}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_7}, + "_dd.test.is_user_provided_service" : "true", + "_dd.tracer_host" : ${content_meta__dd_tracer_host}, + "ci.workspace_path" : ${content_meta_ci_workspace_path}, + "component" : "junit", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id_2}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "span.kind" : "test", + "test.framework" : "junit5", + "test.framework_version" : "5.10.2", + "test.module" : ":test", + "test.name" : "pluginPrintsHelloMessageOnGradle85", + "test.source.file" : "src/test/java/datadog/smoke/HelloPluginFunctionalTest.java", + "test.source.method" : "pluginPrintsHelloMessageOnGradle85()V", + "test.status" : "pass", + "test.suite" : "datadog.smoke.HelloPluginFunctionalTest", + "test.type" : "test", + "test_session.name" : "gradle test" + }, + "metrics" : { + "_dd.host.vcpu_count" : ${content_metrics__dd_host_vcpu_count_4}, + "_dd.profiling.enabled" : 0, + "_dd.trace_span_attribute_schema" : 0, + "process_id" : ${content_metrics_process_id_2}, + "test.source.end" : 39, + "test.source.start" : 30 + }, + "name" : "junit.test", + "parent_id" : ${content_parent_id}, + "resource" : "datadog.smoke.HelloPluginFunctionalTest.pluginPrintsHelloMessageOnGradle85", + "service" : "test-gradle-service", + "span_id" : ${content_span_id_4}, + "start" : ${content_start_7}, + "test_module_id" : ${content_test_module_id}, + "test_session_id" : ${content_test_session_id}, + "test_suite_id" : ${content_test_suite_id}, + "trace_id" : ${content_trace_id} + }, + "type" : "test", + "version" : 2 +}, { + "content" : { + "duration" : ${content_duration_8}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_8}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "pluginDescriptors", + "parent_id" : ${content_test_session_id}, + "resource" : "pluginDescriptors", + "service" : "test-gradle-service", + "span_id" : ${content_span_id_5}, + "start" : ${content_start_8}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_9}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_9}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "pluginUnderTestMetadata", + "parent_id" : ${content_test_session_id}, + "resource" : "pluginUnderTestMetadata", + "service" : "test-gradle-service", + "span_id" : ${content_span_id_6}, + "start" : ${content_start_9}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_10}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_10}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "processResources", + "parent_id" : ${content_test_session_id}, + "resource" : "processResources", + "service" : "test-gradle-service", + "span_id" : ${content_span_id_7}, + "start" : ${content_start_10}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_11}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_11}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "processTestResources", + "parent_id" : ${content_test_session_id}, + "resource" : "processTestResources", + "service" : "test-gradle-service", + "span_id" : ${content_span_id_8}, + "start" : ${content_start_11}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_12}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_12}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id_2}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version}, + "test.callback" : "BeforeEach" + }, + "metrics" : { }, + "name" : "setUp", + "parent_id" : ${content_span_id_4}, + "resource" : "setUp", + "service" : "test-gradle-service", + "span_id" : ${content_span_id_9}, + "start" : ${content_start_12}, + "trace_id" : ${content_trace_id} + }, + "type" : "span", + "version" : 1 +}, { + "content" : { + "duration" : ${content_duration_13}, + "error" : 0, + "meta" : { + "_dd.p.tid" : ${content_meta__dd_p_tid_13}, + "_dd.test.is_user_provided_service" : "true", + "env" : "integration-test", + "language" : "jvm", + "library_version" : ${content_meta_library_version}, + "os.architecture" : ${content_meta_os_architecture}, + "os.platform" : ${content_meta_os_platform}, + "os.version" : ${content_meta_os_version}, + "runtime-id" : ${content_meta_runtime_id}, + "runtime.name" : ${content_meta_runtime_name}, + "runtime.vendor" : ${content_meta_runtime_vendor}, + "runtime.version" : ${content_meta_runtime_version} + }, + "metrics" : { }, + "name" : "testClasses", + "parent_id" : ${content_test_session_id}, + "resource" : "testClasses", + "service" : "test-gradle-service", + "span_id" : ${content_span_id_10}, + "start" : ${content_start_13}, + "trace_id" : ${content_test_session_id} + }, + "type" : "span", + "version" : 1 +} ] \ No newline at end of file diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/settings.gradleTest b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/settings.gradleTest new file mode 100644 index 00000000000..6040f1decb8 --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/settings.gradleTest @@ -0,0 +1 @@ +rootProject.name = 'gradle-instrumentation-test-project' diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/main/java/datadog/smoke/HelloPlugin.java b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/main/java/datadog/smoke/HelloPlugin.java new file mode 100644 index 00000000000..59af37dda5e --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/main/java/datadog/smoke/HelloPlugin.java @@ -0,0 +1,20 @@ +package datadog.smoke; + +import org.gradle.api.DefaultTask; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.tasks.TaskAction; + +public class HelloPlugin implements Plugin { + @Override + public void apply(Project project) { + project.getTasks().create("hello", HelloTask.class); + } + + public static class HelloTask extends DefaultTask { + @TaskAction + public void execute() { + System.out.println("Hello from my plugin!"); + } + } +} diff --git a/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java new file mode 100644 index 00000000000..0beae7152b6 --- /dev/null +++ b/dd-smoke-tests/gradle/src/test/resources/test-succeed-gradle-plugin-test/src/test/java/datadog/smoke/HelloPluginFunctionalTest.java @@ -0,0 +1,40 @@ +package datadog.smoke; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.GradleRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +class HelloPluginFunctionalTest { + + @TempDir + Path testProjectDir; + private File buildFile; + + @BeforeEach + void setUp() throws IOException { + buildFile = testProjectDir.resolve("build.gradle").toFile(); + Files.write(buildFile.toPath(), "plugins { id 'datadog.smoke.helloplugin' }".getBytes(StandardCharsets.UTF_8)); + } + + @Test + void pluginPrintsHelloMessageOnGradle85() { + BuildResult result = GradleRunner.create() + .withProjectDir(testProjectDir.toFile()) + .withPluginClasspath() + .withGradleVersion("8.5") + .withArguments("hello", "--stacktrace") + .forwardOutput() + .build(); + + assertTrue(result.getOutput().contains("Hello from my plugin!")); + } +}