From 063e30c831d15d79adbdba0144d5260e31376db8 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Sun, 23 Feb 2025 16:34:52 -0500 Subject: [PATCH 01/23] Create initial app and ExecutorService demo. --- dd-smoke-tests/concurrent/build.gradle | 42 ++++++++++++ .../smoketest/concurrent/ConcurrentApp.java | 18 ++++++ .../concurrent/demoExecutorService.java | 64 +++++++++++++++++++ settings.gradle | 2 +- 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 dd-smoke-tests/concurrent/build.gradle create mode 100644 dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java create mode 100644 dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java diff --git a/dd-smoke-tests/concurrent/build.gradle b/dd-smoke-tests/concurrent/build.gradle new file mode 100644 index 00000000000..5e4ab333225 --- /dev/null +++ b/dd-smoke-tests/concurrent/build.gradle @@ -0,0 +1,42 @@ +plugins { + id 'java' + id 'application' +} + +apply from: "$rootDir/gradle/java.gradle" + +description = 'Concurrent Integration Tests.' + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':dd-trace-api') + testImplementation project(':dd-smoke-tests') + + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +application { + mainClassName = 'datadog.smoketest.concurrent.ConcurrentApp' +} + +test { + useJUnitPlatform() +} + +jar { + manifest { + attributes( + 'Main-Class': 'datadog.smoketest.concurrent.ConcurrentApp' + ) + } +} + +//tasks.withType(Test).configureEach { +// dependsOn "shadowJar" +// +// jvmArgs "-Ddatadog.smoketest.shadowJar.path=${tasks.shadowJar.archiveFile.get()}" +//} diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java new file mode 100644 index 00000000000..043b2c79427 --- /dev/null +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -0,0 +1,18 @@ +package datadog.smoketest.concurrent; + +public class ConcurrentApp { + public static void main(String[] args) { + System.out.println("=====ConcurrentApp start====="); + + // demo ExecutorService + demoExecutorService.main(args); + + // demo ForkJoin + + // demo custom spans + + // demo something else? + + System.out.println("=====ConcurrentApp finish====="); + } +} diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java new file mode 100644 index 00000000000..20e2914e67e --- /dev/null +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java @@ -0,0 +1,64 @@ +package datadog.smoketest.concurrent; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +// examples from https://www.baeldung.com/java-executor-service-tutorial +public class demoExecutorService { + public static void main(String[] args) { + System.out.println("=====demoExecutorService start====="); + + // instantiate executorService and result + ExecutorService executorService = Executors.newFixedThreadPool(10); + List result = new ArrayList<>(); + + // create callable task + Callable callableTask = + () -> { + TimeUnit.MILLISECONDS.sleep(300); + return "callableTask executed!"; + }; + + // invoke callable tasks three times + List> callableTasks = new ArrayList<>(); + callableTasks.add(callableTask); + callableTasks.add(callableTask); + callableTasks.add(callableTask); + List> futures; + try { + futures = executorService.invokeAll(callableTasks); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + // add futures result to 'result' var + for (Future future : futures) { + try { + result.add(future.get()); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } + + // shutdown executorService + executorService.shutdown(); + try { + if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) { + executorService.shutdownNow(); + } + } catch (InterruptedException e) { + executorService.shutdownNow(); + } + + // print result + System.out.println("ExecutorService result: " + result); + + System.out.println("=====demoExecutorService finish====="); + } +} diff --git a/settings.gradle b/settings.gradle index c79530dd5ba..ff125e2aad2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -96,6 +96,7 @@ include ':dd-smoke-tests:apm-tracing-disabled' include ':dd-smoke-tests:armeria-grpc' include ':dd-smoke-tests:backend-mock' include ':dd-smoke-tests:cli' +include 'dd-smoke-tests:concurrent' include ':dd-smoke-tests:crashtracking' include ':dd-smoke-tests:custom-systemloader' include ':dd-smoke-tests:dynamic-config' @@ -524,4 +525,3 @@ include ':dd-java-agent:benchmark' include ':dd-java-agent:benchmark-integration' include ':dd-java-agent:benchmark-integration:jetty-perftest' include ':dd-java-agent:benchmark-integration:play-perftest' - From 84edb2b15a306fa0a586e6e3a6c9e4e3a8a74ed9 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Mon, 24 Feb 2025 10:15:41 -0500 Subject: [PATCH 02/23] Add ForkJoin demo. --- .../smoketest/concurrent/ConcurrentApp.java | 1 + .../smoketest/concurrent/demoForkJoin.java | 80 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index 043b2c79427..42779de8a2c 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -8,6 +8,7 @@ public static void main(String[] args) { demoExecutorService.main(args); // demo ForkJoin + demoForkJoin.main(args); // demo custom spans diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java new file mode 100644 index 00000000000..61926f7ddb1 --- /dev/null +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java @@ -0,0 +1,80 @@ +package datadog.smoketest.concurrent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.RecursiveTask; + +// examples from https://www.baeldung.com/java-fork-join +public class demoForkJoin { + public static void main(String[] args) { + System.out.println("=====demoForkJoin start====="); + + // instantiate forkJoinPool + ForkJoinPool forkJoinPool = ForkJoinPool.commonPool(); + + // execute forkJoinPool tasks + Random random = new Random(); + int[] arr = new int[20]; + for (int i = 0; i < arr.length; i++) { + arr[i] = random.nextInt(20); + } + + CustomRecursiveTask customRecursiveTask = new CustomRecursiveTask(arr); + forkJoinPool.execute(customRecursiveTask); + customRecursiveTask.join(); + + CustomRecursiveTask customRecursiveTask1 = new CustomRecursiveTask(arr); + CustomRecursiveTask customRecursiveTask2 = new CustomRecursiveTask(arr); + CustomRecursiveTask customRecursiveTask3 = new CustomRecursiveTask(arr); + customRecursiveTask1.fork(); + customRecursiveTask2.fork(); + customRecursiveTask3.fork(); + + // join the results + int result = 0; + result += customRecursiveTask3.join(); + result += customRecursiveTask2.join(); + result += customRecursiveTask1.join(); + + // print the result + System.out.println("ForkJoinPool result: " + result); + + System.out.println("=====demoForkJoin finish====="); + } + + public static class CustomRecursiveTask extends RecursiveTask { + private int[] arr; + + private static final int THRESHOLD = 20; + + public CustomRecursiveTask(int[] arr) { + this.arr = arr; + } + + @Override + protected Integer compute() { + if (arr.length > THRESHOLD) { + return ForkJoinTask.invokeAll(createSubtasks()).stream().mapToInt(ForkJoinTask::join).sum(); + } else { + return processing(arr); + } + } + + private Collection createSubtasks() { + List dividedTasks = new ArrayList<>(); + dividedTasks.add(new CustomRecursiveTask(Arrays.copyOfRange(arr, 0, arr.length / 2))); + dividedTasks.add( + new CustomRecursiveTask(Arrays.copyOfRange(arr, arr.length / 2, arr.length))); + return dividedTasks; + } + + private Integer processing(int[] arr) { + return Arrays.stream(arr).filter(a -> a > 10 && a < 27).map(a -> a * 10).sum(); + } + } +} From d101383c556ff14df5cfd8c7c25837b83d9d0550 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Mon, 24 Feb 2025 16:15:01 -0500 Subject: [PATCH 03/23] Start writing tests. --- dd-smoke-tests/concurrent/build.gradle | 11 +++++----- .../smoketest/DemoExecutorServiceTest.groovy | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy diff --git a/dd-smoke-tests/concurrent/build.gradle b/dd-smoke-tests/concurrent/build.gradle index 5e4ab333225..d761bf77e7a 100644 --- a/dd-smoke-tests/concurrent/build.gradle +++ b/dd-smoke-tests/concurrent/build.gradle @@ -1,6 +1,7 @@ plugins { id 'java' id 'application' + id 'com.github.johnrengelman.shadow' } apply from: "$rootDir/gradle/java.gradle" @@ -35,8 +36,8 @@ jar { } } -//tasks.withType(Test).configureEach { -// dependsOn "shadowJar" -// -// jvmArgs "-Ddatadog.smoketest.shadowJar.path=${tasks.shadowJar.archiveFile.get()}" -//} +tasks.withType(Test).configureEach { + dependsOn "shadowJar" + + jvmArgs "-Ddatadog.smoketest.shadowJar.path=${tasks.shadowJar.archiveFile.get()}" +} diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy new file mode 100644 index 00000000000..249a9236b9c --- /dev/null +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -0,0 +1,22 @@ +package datadog.smoketest + +class DemoExecutorServiceTest extends AbstractSmokeTest { + public static final int TIMEOUT_SECS = 30 + + @Override + ProcessBuilder createProcessBuilder() { + def jarPath = System.getProperty("datadog.smoketest.shadowJar.path") + def command = new ArrayList() + command.add(javaPath()) + command.addAll(defaultJavaProperties) + command.addAll(["-jar", jarPath]) + + ProcessBuilder processBuilder = new ProcessBuilder(command) + processBuilder.directory(new File(buildDirectory)) + } + + def 'tmp'() { + expect: + assert true == true + } +} From 11758ff22b6acb16cce1f9fcb490e7538e3e3628 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Mon, 24 Feb 2025 17:17:21 -0500 Subject: [PATCH 04/23] Add simple OTel spans for now. --- dd-smoke-tests/concurrent/build.gradle | 9 +++---- .../smoketest/concurrent/ConcurrentApp.java | 24 ++++++++++++++++++- .../smoketest/DemoExecutorServiceTest.groovy | 10 ++++++++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/dd-smoke-tests/concurrent/build.gradle b/dd-smoke-tests/concurrent/build.gradle index d761bf77e7a..6a4b3a3a914 100644 --- a/dd-smoke-tests/concurrent/build.gradle +++ b/dd-smoke-tests/concurrent/build.gradle @@ -8,11 +8,12 @@ apply from: "$rootDir/gradle/java.gradle" description = 'Concurrent Integration Tests.' -repositories { - mavenCentral() +application { + mainClassName = 'datadog.smoketest.concurrent.ConcurrentApp' } dependencies { + implementation('io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations:2.13.1') implementation project(':dd-trace-api') testImplementation project(':dd-smoke-tests') @@ -20,10 +21,6 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter' } -application { - mainClassName = 'datadog.smoketest.concurrent.ConcurrentApp' -} - test { useJUnitPlatform() } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index 42779de8a2c..4db42e25c63 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -1,9 +1,26 @@ package datadog.smoketest.concurrent; +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.instrumentation.annotations.WithSpan; + public class ConcurrentApp { - public static void main(String[] args) { + + @WithSpan + static void startSpan() { + System.out.println("=====startSpan====="); + } + + public static void main(String[] args) throws InterruptedException { System.out.println("=====ConcurrentApp start====="); + // start parent span + startSpan(); + + // get an Open Telemetry tracer + Tracer tracer = GlobalOpenTelemetry.getTracerProvider().tracerBuilder("smoketests").build(); + // demo ExecutorService demoExecutorService.main(args); @@ -11,6 +28,11 @@ public static void main(String[] args) { demoForkJoin.main(args); // demo custom spans + for (int i = 0; i < 10; i++) { + Span span = tracer.spanBuilder("span-" + i).startSpan(); + Thread.sleep(20); + span.end(); + } // demo something else? diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 249a9236b9c..2b5f175a2a6 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -1,5 +1,7 @@ package datadog.smoketest +import static java.util.concurrent.TimeUnit.SECONDS + class DemoExecutorServiceTest extends AbstractSmokeTest { public static final int TIMEOUT_SECS = 30 @@ -9,6 +11,7 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { def command = new ArrayList() command.add(javaPath()) command.addAll(defaultJavaProperties) + command.add("-Ddd.trace.otel.enabled=true") command.addAll(["-jar", jarPath]) ProcessBuilder processBuilder = new ProcessBuilder(command) @@ -19,4 +22,11 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { expect: assert true == true } + + def 'receive trace'() { + expect: + waitForTraceCount(11) // 1 annotated, 10 manual + assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) + assert testedProcess.exitValue() == 0 + } } From 2153181400e279cc5905b3eb00d4a972e71fcceb Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Sun, 2 Mar 2025 17:28:19 -0500 Subject: [PATCH 05/23] Add FibonacciCalculator interface and adjust tests and demos accordingly. --- .../smoketest/concurrent/ConcurrentApp.java | 42 ++++---- .../concurrent/FibonacciCalculator.java | 7 ++ .../concurrent/demoExecutorService.java | 75 ++++++++------- .../smoketest/concurrent/demoForkJoin.java | 96 +++++++------------ .../smoketest/DemoExecutorServiceTest.groovy | 9 +- .../datadog/smoketest/DemoForkJoinTest.groovy | 33 +++++++ .../smoketest/DemoMixedConcurrencyTest.groovy | 33 +++++++ 7 files changed, 180 insertions(+), 115 deletions(-) create mode 100644 dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/FibonacciCalculator.java create mode 100644 dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy create mode 100644 dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index 4db42e25c63..8037523e124 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -1,9 +1,7 @@ package datadog.smoketest.concurrent; -import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.trace.Span; -import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.instrumentation.annotations.WithSpan; +import java.util.concurrent.ExecutionException; public class ConcurrentApp { @@ -12,30 +10,42 @@ static void startSpan() { System.out.println("=====startSpan====="); } - public static void main(String[] args) throws InterruptedException { + public static void main(String[] args) throws InterruptedException, ExecutionException { System.out.println("=====ConcurrentApp start====="); // start parent span startSpan(); // get an Open Telemetry tracer - Tracer tracer = GlobalOpenTelemetry.getTracerProvider().tracerBuilder("smoketests").build(); - - // demo ExecutorService - demoExecutorService.main(args); - - // demo ForkJoin - demoForkJoin.main(args); + // Tracer tracer = + // GlobalOpenTelemetry.getTracerProvider().tracerBuilder("smoketests").build(); + + // do fibonacci calculation + FibonacciCalculator calc; + if (args.length > 0) { + for (String arg : args) { + if (arg.equalsIgnoreCase("executorService")) { + calc = new demoExecutorService(); + long result = calc.computeFibonacci(10); + System.out.println("=====ExecutorService result: " + result + "====="); + } else if (arg.equalsIgnoreCase("forkJoin")) { + calc = new demoForkJoin(); + long result = calc.computeFibonacci(10); + System.out.println("=====ForkJoin result: " + result + "====="); + } + } + } // demo custom spans - for (int i = 0; i < 10; i++) { - Span span = tracer.spanBuilder("span-" + i).startSpan(); - Thread.sleep(20); - span.end(); - } + // for (int i = 0; i < 10; i++) { + // Span span = tracer.spanBuilder("span-" + i).startSpan(); + // Thread.sleep(20); + // span.end(); + // } // demo something else? System.out.println("=====ConcurrentApp finish====="); + System.exit(0); } } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/FibonacciCalculator.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/FibonacciCalculator.java new file mode 100644 index 00000000000..27c5fd1a984 --- /dev/null +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/FibonacciCalculator.java @@ -0,0 +1,7 @@ +package datadog.smoketest.concurrent; + +import java.util.concurrent.ExecutionException; + +public interface FibonacciCalculator { + long computeFibonacci(int n) throws ExecutionException, InterruptedException; +} diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java index 20e2914e67e..0a9d3912c5d 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java @@ -1,7 +1,6 @@ package datadog.smoketest.concurrent; -import java.util.ArrayList; -import java.util.List; +import io.opentelemetry.instrumentation.annotations.WithSpan; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -9,44 +8,46 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -// examples from https://www.baeldung.com/java-executor-service-tutorial -public class demoExecutorService { - public static void main(String[] args) { - System.out.println("=====demoExecutorService start====="); +public class demoExecutorService implements FibonacciCalculator { + private static ExecutorService executorService; - // instantiate executorService and result - ExecutorService executorService = Executors.newFixedThreadPool(10); - List result = new ArrayList<>(); + public demoExecutorService() { + executorService = Executors.newFixedThreadPool(10); + } - // create callable task - Callable callableTask = - () -> { - TimeUnit.MILLISECONDS.sleep(300); - return "callableTask executed!"; - }; + @WithSpan + @Override + public long computeFibonacci(int n) throws ExecutionException, InterruptedException { + FibonacciTask task = new FibonacciTask(10); + Future future = executorService.submit(task); + return future.get(); + } - // invoke callable tasks three times - List> callableTasks = new ArrayList<>(); - callableTasks.add(callableTask); - callableTasks.add(callableTask); - callableTasks.add(callableTask); - List> futures; - try { - futures = executorService.invokeAll(callableTasks); - } catch (InterruptedException e) { - throw new RuntimeException(e); + private static class FibonacciTask implements Callable { + private int n; + + public FibonacciTask(int n) { + this.n = n; } - // add futures result to 'result' var - for (Future future : futures) { - try { - result.add(future.get()); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); + @WithSpan + @Override + public Integer call() { + if (n <= 1) { + return n; } + return fibonacci(n); } - // shutdown executorService + private int fibonacci(int n) { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); + } + } + + public void shutdown() { executorService.shutdown(); try { if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) { @@ -55,9 +56,15 @@ public static void main(String[] args) { } catch (InterruptedException e) { executorService.shutdownNow(); } + } + + public static void main(String[] args) throws ExecutionException, InterruptedException { + System.out.println("=====demoExecutorService start====="); - // print result - System.out.println("ExecutorService result: " + result); + demoExecutorService demoService = new demoExecutorService(); + long result = demoService.computeFibonacci(10); + System.out.println("=====result: " + result + "====="); + demoService.shutdown(); System.out.println("=====demoExecutorService finish====="); } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java index 61926f7ddb1..780cbd41b5f 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java @@ -1,80 +1,54 @@ package datadog.smoketest.concurrent; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Random; +import io.opentelemetry.instrumentation.annotations.WithSpan; import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.ForkJoinTask; import java.util.concurrent.RecursiveTask; -// examples from https://www.baeldung.com/java-fork-join -public class demoForkJoin { - public static void main(String[] args) { - System.out.println("=====demoForkJoin start====="); - - // instantiate forkJoinPool - ForkJoinPool forkJoinPool = ForkJoinPool.commonPool(); - - // execute forkJoinPool tasks - Random random = new Random(); - int[] arr = new int[20]; - for (int i = 0; i < arr.length; i++) { - arr[i] = random.nextInt(20); - } +public class demoForkJoin implements FibonacciCalculator { + private static ForkJoinPool forkJoinPool; - CustomRecursiveTask customRecursiveTask = new CustomRecursiveTask(arr); - forkJoinPool.execute(customRecursiveTask); - customRecursiveTask.join(); - - CustomRecursiveTask customRecursiveTask1 = new CustomRecursiveTask(arr); - CustomRecursiveTask customRecursiveTask2 = new CustomRecursiveTask(arr); - CustomRecursiveTask customRecursiveTask3 = new CustomRecursiveTask(arr); - customRecursiveTask1.fork(); - customRecursiveTask2.fork(); - customRecursiveTask3.fork(); - - // join the results - int result = 0; - result += customRecursiveTask3.join(); - result += customRecursiveTask2.join(); - result += customRecursiveTask1.join(); - - // print the result - System.out.println("ForkJoinPool result: " + result); - - System.out.println("=====demoForkJoin finish====="); + public demoForkJoin() { + forkJoinPool = new ForkJoinPool(); } - public static class CustomRecursiveTask extends RecursiveTask { - private int[] arr; + @WithSpan + @Override + public long computeFibonacci(int n) { + return forkJoinPool.invoke(new FibonacciTask(n)); + } - private static final int THRESHOLD = 20; + private static class FibonacciTask extends RecursiveTask { + private final int n; - public CustomRecursiveTask(int[] arr) { - this.arr = arr; + public FibonacciTask(int n) { + this.n = n; } + @WithSpan @Override - protected Integer compute() { - if (arr.length > THRESHOLD) { - return ForkJoinTask.invokeAll(createSubtasks()).stream().mapToInt(ForkJoinTask::join).sum(); - } else { - return processing(arr); + protected Long compute() { + if (n <= 1) { + return (long) n; } + FibonacciTask taskOne = new FibonacciTask(n - 1); + taskOne.fork(); + FibonacciTask taskTwo = new FibonacciTask(n - 2); + return taskTwo.compute() + taskOne.join(); } + } - private Collection createSubtasks() { - List dividedTasks = new ArrayList<>(); - dividedTasks.add(new CustomRecursiveTask(Arrays.copyOfRange(arr, 0, arr.length / 2))); - dividedTasks.add( - new CustomRecursiveTask(Arrays.copyOfRange(arr, arr.length / 2, arr.length))); - return dividedTasks; - } + public static void shutdown() { + forkJoinPool.shutdown(); + } - private Integer processing(int[] arr) { - return Arrays.stream(arr).filter(a -> a > 10 && a < 27).map(a -> a * 10).sum(); - } + public static void main(String[] args) { + System.out.println("=====demoForkJoin start====="); + + demoForkJoin demoService = new demoForkJoin(); + long result = demoService.computeFibonacci(10); + System.out.println("=====result: " + result + "====="); + demoForkJoin.shutdown(); + + System.out.println("=====demoForkJoin finish====="); } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 2b5f175a2a6..12717920ce6 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -3,7 +3,7 @@ package datadog.smoketest import static java.util.concurrent.TimeUnit.SECONDS class DemoExecutorServiceTest extends AbstractSmokeTest { - public static final int TIMEOUT_SECS = 30 + public static final int TIMEOUT_SECS = 10 @Override ProcessBuilder createProcessBuilder() { @@ -12,7 +12,7 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { command.add(javaPath()) command.addAll(defaultJavaProperties) command.add("-Ddd.trace.otel.enabled=true") - command.addAll(["-jar", jarPath]) + command.addAll(["-jar", jarPath, "executorService"]) ProcessBuilder processBuilder = new ProcessBuilder(command) processBuilder.directory(new File(buildDirectory)) @@ -23,9 +23,10 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { assert true == true } - def 'receive trace'() { + def 'receive trace for ExecutorService'() { expect: - waitForTraceCount(11) // 1 annotated, 10 manual + waitForTraceCount(1) // one parent trace + assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy new file mode 100644 index 00000000000..b039a31f7ff --- /dev/null +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -0,0 +1,33 @@ +package datadog.smoketest + +import static java.util.concurrent.TimeUnit.SECONDS + +class DemoForkJoinTest extends AbstractSmokeTest { + public static final int TIMEOUT_SECS = 10 + + @Override + ProcessBuilder createProcessBuilder() { + def jarPath = System.getProperty("datadog.smoketest.shadowJar.path") + def command = new ArrayList() + command.add(javaPath()) + command.addAll(defaultJavaProperties) + command.add("-Ddd.trace.otel.enabled=true") + command.addAll(["-jar", jarPath, "forkJoin"]) + + ProcessBuilder processBuilder = new ProcessBuilder(command) + processBuilder.directory(new File(buildDirectory)) + } + + def 'tmp'() { + expect: + assert true == true + } + + def 'receive trace for ForkJoin'() { + expect: + waitForTraceCount(1) // one parent trace + + assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) + assert testedProcess.exitValue() == 0 + } +} diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy new file mode 100644 index 00000000000..6d0f3db44b3 --- /dev/null +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -0,0 +1,33 @@ +package datadog.smoketest + +import static java.util.concurrent.TimeUnit.SECONDS + +class DemoMixedConcurrencyTest extends AbstractSmokeTest { + public static final int TIMEOUT_SECS = 10 + + @Override + ProcessBuilder createProcessBuilder() { + def jarPath = System.getProperty("datadog.smoketest.shadowJar.path") + def command = new ArrayList() + command.add(javaPath()) + command.addAll(defaultJavaProperties) + command.add("-Ddd.trace.otel.enabled=true") + command.addAll(["-jar", jarPath, "executorService", "forkJoin"]) + + ProcessBuilder processBuilder = new ProcessBuilder(command) + processBuilder.directory(new File(buildDirectory)) + } + + def 'tmp'() { + expect: + assert true == true + } + + def 'receive trace for ExecutorService and ForkJoin'() { + expect: + waitForTraceCount(1) // one parent trace + + assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) + assert testedProcess.exitValue() == 0 + } +} From 5ca2aaba4c2ccfd8071cafc6e31f3f713baca9f5 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Tue, 4 Mar 2025 15:15:12 -0500 Subject: [PATCH 06/23] Change trace expectations to reality. --- .../groovy/datadog/smoketest/DemoExecutorServiceTest.groovy | 2 +- .../src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy | 2 +- .../groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 12717920ce6..6c4b80aece6 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -25,7 +25,7 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { def 'receive trace for ExecutorService'() { expect: - waitForTraceCount(1) // one parent trace + waitForTraceCount(2) // one parent trace assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index b039a31f7ff..8d28eb0338e 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -25,7 +25,7 @@ class DemoForkJoinTest extends AbstractSmokeTest { def 'receive trace for ForkJoin'() { expect: - waitForTraceCount(1) // one parent trace + waitForTraceCount(2) // one parent trace assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index 6d0f3db44b3..cd4272f9124 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -25,7 +25,7 @@ class DemoMixedConcurrencyTest extends AbstractSmokeTest { def 'receive trace for ExecutorService and ForkJoin'() { expect: - waitForTraceCount(1) // one parent trace + waitForTraceCount(3) // one parent trace assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 From cc4c1a4e6ad2db0367163dfc218691602ce32a50 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Wed, 5 Mar 2025 22:12:30 -0500 Subject: [PATCH 07/23] Extract calculations to helper function and update tests. --- .../smoketest/concurrent/ConcurrentApp.java | 48 +++++++------------ .../smoketest/DemoExecutorServiceTest.groovy | 3 +- .../datadog/smoketest/DemoForkJoinTest.groovy | 3 +- .../smoketest/DemoMixedConcurrencyTest.groovy | 3 +- 4 files changed, 22 insertions(+), 35 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index 8037523e124..d5c773729a7 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -4,46 +4,30 @@ import java.util.concurrent.ExecutionException; public class ConcurrentApp { - @WithSpan - static void startSpan() { - System.out.println("=====startSpan====="); + static void computeFibonacciHelper(String[] args) + throws ExecutionException, InterruptedException { + FibonacciCalculator calc; + for (String arg : args) { + if (arg.equalsIgnoreCase("executorService")) { + calc = new demoExecutorService(); + long result = calc.computeFibonacci(10); + System.out.println("=====ExecutorService result: " + result + "====="); + } else if (arg.equalsIgnoreCase("forkJoin")) { + calc = new demoForkJoin(); + long result = calc.computeFibonacci(10); + System.out.println("=====ForkJoin result: " + result + "====="); + } + } } public static void main(String[] args) throws InterruptedException, ExecutionException { System.out.println("=====ConcurrentApp start====="); - // start parent span - startSpan(); - - // get an Open Telemetry tracer - // Tracer tracer = - // GlobalOpenTelemetry.getTracerProvider().tracerBuilder("smoketests").build(); - // do fibonacci calculation - FibonacciCalculator calc; - if (args.length > 0) { - for (String arg : args) { - if (arg.equalsIgnoreCase("executorService")) { - calc = new demoExecutorService(); - long result = calc.computeFibonacci(10); - System.out.println("=====ExecutorService result: " + result + "====="); - } else if (arg.equalsIgnoreCase("forkJoin")) { - calc = new demoForkJoin(); - long result = calc.computeFibonacci(10); - System.out.println("=====ForkJoin result: " + result + "====="); - } - } - } - - // demo custom spans - // for (int i = 0; i < 10; i++) { - // Span span = tracer.spanBuilder("span-" + i).startSpan(); - // Thread.sleep(20); - // span.end(); - // } + computeFibonacciHelper(args); - // demo something else? + // add custom spans here / elsewhere? System.out.println("=====ConcurrentApp finish====="); System.exit(0); diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 6c4b80aece6..220228664e8 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -25,7 +25,8 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { def 'receive trace for ExecutorService'() { expect: - waitForTraceCount(2) // one parent trace + waitForTraceCount(1) // one parent trace + traceCount.get() == 1 assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index 8d28eb0338e..50991bfe8cc 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -25,7 +25,8 @@ class DemoForkJoinTest extends AbstractSmokeTest { def 'receive trace for ForkJoin'() { expect: - waitForTraceCount(2) // one parent trace + waitForTraceCount(1) // one parent trace + traceCount.get() == 1 assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index cd4272f9124..78323df1c40 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -25,7 +25,8 @@ class DemoMixedConcurrencyTest extends AbstractSmokeTest { def 'receive trace for ExecutorService and ForkJoin'() { expect: - waitForTraceCount(3) // one parent trace + waitForTraceCount(1) // one parent trace + traceCount.get() == 1 assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 From 58b15f193a47518b42bdf471009702415fd01bda Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Thu, 6 Mar 2025 16:48:20 -0500 Subject: [PATCH 08/23] Check that span name is as expected. --- .../smoketest/DemoExecutorServiceTest.groovy | 16 +++++++++++++++- .../datadog/smoketest/DemoForkJoinTest.groovy | 16 +++++++++++++++- .../smoketest/DemoMixedConcurrencyTest.groovy | 16 +++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 220228664e8..d166f05c331 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -1,5 +1,10 @@ package datadog.smoketest +import datadog.trace.test.agent.decoder.DecodedSpan +import spock.util.concurrent.PollingConditions + +import java.util.function.Function + import static java.util.concurrent.TimeUnit.SECONDS class DemoExecutorServiceTest extends AbstractSmokeTest { @@ -23,9 +28,18 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { assert true == true } + @Override + Closure decodedTracesCallback() { + return {} // force traces decoding + } + + private static Function checkSpanName() { + return { span -> span.getName() == "ConcurrentApp.computeFibonacciHelper" } + } + def 'receive trace for ExecutorService'() { expect: - waitForTraceCount(1) // one parent trace + waitForSpan(new PollingConditions(timeout: TIMEOUT_SECS), checkSpanName()) traceCount.get() == 1 assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index 50991bfe8cc..75f290e00cf 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -1,5 +1,10 @@ package datadog.smoketest +import datadog.trace.test.agent.decoder.DecodedSpan +import spock.util.concurrent.PollingConditions + +import java.util.function.Function + import static java.util.concurrent.TimeUnit.SECONDS class DemoForkJoinTest extends AbstractSmokeTest { @@ -23,9 +28,18 @@ class DemoForkJoinTest extends AbstractSmokeTest { assert true == true } + @Override + Closure decodedTracesCallback() { + return {} // force traces decoding + } + + private static Function checkSpanName() { + return { span -> span.getName() == "ConcurrentApp.computeFibonacciHelper" } + } + def 'receive trace for ForkJoin'() { expect: - waitForTraceCount(1) // one parent trace + waitForSpan(new PollingConditions(timeout: TIMEOUT_SECS), checkSpanName()) traceCount.get() == 1 assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index 78323df1c40..f16fcab1484 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -1,5 +1,10 @@ package datadog.smoketest +import datadog.trace.test.agent.decoder.DecodedSpan +import spock.util.concurrent.PollingConditions + +import java.util.function.Function + import static java.util.concurrent.TimeUnit.SECONDS class DemoMixedConcurrencyTest extends AbstractSmokeTest { @@ -23,9 +28,18 @@ class DemoMixedConcurrencyTest extends AbstractSmokeTest { assert true == true } + @Override + Closure decodedTracesCallback() { + return {} // force traces decoding + } + + private static Function checkSpanName() { + return { span -> span.getName() == "ConcurrentApp.computeFibonacciHelper" } + } + def 'receive trace for ExecutorService and ForkJoin'() { expect: - waitForTraceCount(1) // one parent trace + waitForSpan(new PollingConditions(timeout: TIMEOUT_SECS), checkSpanName()) traceCount.get() == 1 assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) From cfb6aaa120d94d7e9f66bdc0b46b1971c5a282ed Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Thu, 6 Mar 2025 17:38:59 -0500 Subject: [PATCH 09/23] Clean PR. --- .../smoketest/concurrent/ConcurrentApp.java | 20 +++++++------------ .../concurrent/demoExecutorService.java | 9 ++------- .../smoketest/concurrent/demoForkJoin.java | 7 +------ .../smoketest/DemoExecutorServiceTest.groovy | 9 ++------- .../datadog/smoketest/DemoForkJoinTest.groovy | 11 ++-------- .../smoketest/DemoMixedConcurrencyTest.groovy | 11 ++-------- 6 files changed, 16 insertions(+), 51 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index d5c773729a7..25587f9fecf 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -4,32 +4,26 @@ import java.util.concurrent.ExecutionException; public class ConcurrentApp { + @WithSpan - static void computeFibonacciHelper(String[] args) - throws ExecutionException, InterruptedException { + static void spanWrapper(String[] args) throws ExecutionException, InterruptedException { + // calculate fibonacci using concurrent strategies FibonacciCalculator calc; for (String arg : args) { if (arg.equalsIgnoreCase("executorService")) { calc = new demoExecutorService(); - long result = calc.computeFibonacci(10); - System.out.println("=====ExecutorService result: " + result + "====="); + calc.computeFibonacci(10); } else if (arg.equalsIgnoreCase("forkJoin")) { calc = new demoForkJoin(); - long result = calc.computeFibonacci(10); - System.out.println("=====ForkJoin result: " + result + "====="); + calc.computeFibonacci(10); } } } public static void main(String[] args) throws InterruptedException, ExecutionException { - System.out.println("=====ConcurrentApp start====="); - - // do fibonacci calculation - computeFibonacciHelper(args); - - // add custom spans here / elsewhere? + // wrap calculations in a span + spanWrapper(args); - System.out.println("=====ConcurrentApp finish====="); System.exit(0); } } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java index 0a9d3912c5d..53fd2e6988c 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java @@ -24,7 +24,7 @@ public long computeFibonacci(int n) throws ExecutionException, InterruptedExcept } private static class FibonacciTask implements Callable { - private int n; + private final int n; public FibonacciTask(int n) { this.n = n; @@ -59,13 +59,8 @@ public void shutdown() { } public static void main(String[] args) throws ExecutionException, InterruptedException { - System.out.println("=====demoExecutorService start====="); - demoExecutorService demoService = new demoExecutorService(); - long result = demoService.computeFibonacci(10); - System.out.println("=====result: " + result + "====="); + demoService.computeFibonacci(10); demoService.shutdown(); - - System.out.println("=====demoExecutorService finish====="); } } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java index 780cbd41b5f..be1ed92d228 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java @@ -42,13 +42,8 @@ public static void shutdown() { } public static void main(String[] args) { - System.out.println("=====demoForkJoin start====="); - demoForkJoin demoService = new demoForkJoin(); - long result = demoService.computeFibonacci(10); - System.out.println("=====result: " + result + "====="); + demoService.computeFibonacci(10); demoForkJoin.shutdown(); - - System.out.println("=====demoForkJoin finish====="); } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index d166f05c331..c5f46c3f34f 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -23,21 +23,16 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { processBuilder.directory(new File(buildDirectory)) } - def 'tmp'() { - expect: - assert true == true - } - @Override Closure decodedTracesCallback() { return {} // force traces decoding } private static Function checkSpanName() { - return { span -> span.getName() == "ConcurrentApp.computeFibonacciHelper" } + return { span -> span.getName() == "ConcurrentApp.spanWrapper" } } - def 'receive trace for ExecutorService'() { + def 'receive one expected trace for ExecutorService'() { expect: waitForSpan(new PollingConditions(timeout: TIMEOUT_SECS), checkSpanName()) traceCount.get() == 1 diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index 75f290e00cf..6471cb11894 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -2,9 +2,7 @@ package datadog.smoketest import datadog.trace.test.agent.decoder.DecodedSpan import spock.util.concurrent.PollingConditions - import java.util.function.Function - import static java.util.concurrent.TimeUnit.SECONDS class DemoForkJoinTest extends AbstractSmokeTest { @@ -23,21 +21,16 @@ class DemoForkJoinTest extends AbstractSmokeTest { processBuilder.directory(new File(buildDirectory)) } - def 'tmp'() { - expect: - assert true == true - } - @Override Closure decodedTracesCallback() { return {} // force traces decoding } private static Function checkSpanName() { - return { span -> span.getName() == "ConcurrentApp.computeFibonacciHelper" } + return { span -> span.getName() == "ConcurrentApp.spanWrapper" } } - def 'receive trace for ForkJoin'() { + def 'receive one expected trace for ForkJoin'() { expect: waitForSpan(new PollingConditions(timeout: TIMEOUT_SECS), checkSpanName()) traceCount.get() == 1 diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index f16fcab1484..ca43b331313 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -2,9 +2,7 @@ package datadog.smoketest import datadog.trace.test.agent.decoder.DecodedSpan import spock.util.concurrent.PollingConditions - import java.util.function.Function - import static java.util.concurrent.TimeUnit.SECONDS class DemoMixedConcurrencyTest extends AbstractSmokeTest { @@ -23,21 +21,16 @@ class DemoMixedConcurrencyTest extends AbstractSmokeTest { processBuilder.directory(new File(buildDirectory)) } - def 'tmp'() { - expect: - assert true == true - } - @Override Closure decodedTracesCallback() { return {} // force traces decoding } private static Function checkSpanName() { - return { span -> span.getName() == "ConcurrentApp.computeFibonacciHelper" } + return { span -> span.getName() == "ConcurrentApp.spanWrapper" } } - def 'receive trace for ExecutorService and ForkJoin'() { + def 'receive one expected trace for ExecutorService and ForkJoin'() { expect: waitForSpan(new PollingConditions(timeout: TIMEOUT_SECS), checkSpanName()) traceCount.get() == 1 From 02e1922925d09511d23031e34a4bd648dda490e6 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 7 Mar 2025 14:34:23 -0500 Subject: [PATCH 10/23] Update settings.gradle Co-authored-by: Bruce Bujon --- settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index ff125e2aad2..33318144af5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -96,7 +96,7 @@ include ':dd-smoke-tests:apm-tracing-disabled' include ':dd-smoke-tests:armeria-grpc' include ':dd-smoke-tests:backend-mock' include ':dd-smoke-tests:cli' -include 'dd-smoke-tests:concurrent' +include ':dd-smoke-tests:concurrent' include ':dd-smoke-tests:crashtracking' include ':dd-smoke-tests:custom-systemloader' include ':dd-smoke-tests:dynamic-config' From ea34748990cb26ad53b672af50b262c36f730dce Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 7 Mar 2025 14:34:44 -0500 Subject: [PATCH 11/23] Update dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java Co-authored-by: Bruce Bujon --- .../java/datadog/smoketest/concurrent/demoExecutorService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java index 53fd2e6988c..be4180f3694 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java @@ -8,7 +8,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -public class demoExecutorService implements FibonacciCalculator { +public class DemoExecutorService implements FibonacciCalculator { private static ExecutorService executorService; public demoExecutorService() { From 3297e0c3531411a2b962ee9d5be6e00edb5fd583 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 7 Mar 2025 14:35:02 -0500 Subject: [PATCH 12/23] Update dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java Co-authored-by: Bruce Bujon --- .../main/java/datadog/smoketest/concurrent/demoForkJoin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java index be1ed92d228..739c2ec9d6a 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java @@ -4,7 +4,7 @@ import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; -public class demoForkJoin implements FibonacciCalculator { +public class DemoForkJoin implements FibonacciCalculator { private static ForkJoinPool forkJoinPool; public demoForkJoin() { From 7c62ddd351b9aed20b26ee3e4d773cb5de3e890f Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 7 Mar 2025 15:28:38 -0500 Subject: [PATCH 13/23] Update names. --- .../datadog/smoketest/concurrent/ConcurrentApp.java | 2 +- ...moExecutorService.java => DemoExecutorService.java} | 6 +++--- .../{demoForkJoin.java => DemoForkJoin.java} | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) rename dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/{demoExecutorService.java => DemoExecutorService.java} (91%) rename dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/{demoForkJoin.java => DemoForkJoin.java} (84%) diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index 25587f9fecf..31be35a2de1 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -14,7 +14,7 @@ static void spanWrapper(String[] args) throws ExecutionException, InterruptedExc calc = new demoExecutorService(); calc.computeFibonacci(10); } else if (arg.equalsIgnoreCase("forkJoin")) { - calc = new demoForkJoin(); + calc = new DemoForkJoin(); calc.computeFibonacci(10); } } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java similarity index 91% rename from dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java rename to dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java index be4180f3694..e41b4dc1670 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoExecutorService.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java @@ -9,9 +9,9 @@ import java.util.concurrent.TimeUnit; public class DemoExecutorService implements FibonacciCalculator { - private static ExecutorService executorService; + private ExecutorService executorService; - public demoExecutorService() { + public DemoExecutorService() { executorService = Executors.newFixedThreadPool(10); } @@ -59,7 +59,7 @@ public void shutdown() { } public static void main(String[] args) throws ExecutionException, InterruptedException { - demoExecutorService demoService = new demoExecutorService(); + DemoExecutorService demoService = new DemoExecutorService(); demoService.computeFibonacci(10); demoService.shutdown(); } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java similarity index 84% rename from dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java rename to dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java index 739c2ec9d6a..fda53d7f67d 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/demoForkJoin.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java @@ -5,9 +5,9 @@ import java.util.concurrent.RecursiveTask; public class DemoForkJoin implements FibonacciCalculator { - private static ForkJoinPool forkJoinPool; + private ForkJoinPool forkJoinPool; - public demoForkJoin() { + public DemoForkJoin() { forkJoinPool = new ForkJoinPool(); } @@ -37,13 +37,13 @@ protected Long compute() { } } - public static void shutdown() { + public void shutdown() { forkJoinPool.shutdown(); } public static void main(String[] args) { - demoForkJoin demoService = new demoForkJoin(); + DemoForkJoin demoService = new DemoForkJoin(); demoService.computeFibonacci(10); - demoForkJoin.shutdown(); + demoService.shutdown(); } } From 65411ad1c0c3cd7d87c75e148b536b1b426ffb0c Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 7 Mar 2025 15:33:09 -0500 Subject: [PATCH 14/23] Clean build.gradle. --- dd-smoke-tests/concurrent/build.gradle | 8 -------- .../java/datadog/smoketest/concurrent/ConcurrentApp.java | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/dd-smoke-tests/concurrent/build.gradle b/dd-smoke-tests/concurrent/build.gradle index 6a4b3a3a914..b95668127e6 100644 --- a/dd-smoke-tests/concurrent/build.gradle +++ b/dd-smoke-tests/concurrent/build.gradle @@ -25,14 +25,6 @@ test { useJUnitPlatform() } -jar { - manifest { - attributes( - 'Main-Class': 'datadog.smoketest.concurrent.ConcurrentApp' - ) - } -} - tasks.withType(Test).configureEach { dependsOn "shadowJar" diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index 31be35a2de1..47dfaaf1c2b 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -11,7 +11,7 @@ static void spanWrapper(String[] args) throws ExecutionException, InterruptedExc FibonacciCalculator calc; for (String arg : args) { if (arg.equalsIgnoreCase("executorService")) { - calc = new demoExecutorService(); + calc = new DemoExecutorService(); calc.computeFibonacci(10); } else if (arg.equalsIgnoreCase("forkJoin")) { calc = new DemoForkJoin(); From b4c1cd39344eb2050cabc05c8d32dfc3ed8faa8b Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 7 Mar 2025 15:53:54 -0500 Subject: [PATCH 15/23] Format tests. --- .../datadog/smoketest/DemoExecutorServiceTest.groovy | 11 +++++++++-- .../groovy/datadog/smoketest/DemoForkJoinTest.groovy | 11 +++++++++-- .../datadog/smoketest/DemoMixedConcurrencyTest.groovy | 11 +++++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index c5f46c3f34f..642efca3777 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -33,10 +33,17 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { } def 'receive one expected trace for ExecutorService'() { - expect: - waitForSpan(new PollingConditions(timeout: TIMEOUT_SECS), checkSpanName()) + given: + def poll = new PollingConditions(timeout: TIMEOUT_SECS) + + when: + waitForTraceCount(1) + + then: + waitForSpan(poll, checkSpanName()) traceCount.get() == 1 + and: assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index 6471cb11894..80aa577acc1 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -31,10 +31,17 @@ class DemoForkJoinTest extends AbstractSmokeTest { } def 'receive one expected trace for ForkJoin'() { - expect: - waitForSpan(new PollingConditions(timeout: TIMEOUT_SECS), checkSpanName()) + given: + def poll = new PollingConditions(timeout: TIMEOUT_SECS) + + when: + waitForTraceCount(1) + + then: + waitForSpan(poll, checkSpanName()) traceCount.get() == 1 + and: assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index ca43b331313..36ab86555f3 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -31,10 +31,17 @@ class DemoMixedConcurrencyTest extends AbstractSmokeTest { } def 'receive one expected trace for ExecutorService and ForkJoin'() { - expect: - waitForSpan(new PollingConditions(timeout: TIMEOUT_SECS), checkSpanName()) + given: + def poll = new PollingConditions(timeout: TIMEOUT_SECS) + + when: + waitForTraceCount(1) + + then: + waitForSpan(poll, checkSpanName()) traceCount.get() == 1 + and: assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) assert testedProcess.exitValue() == 0 } From ad0693a057ec2a6637b725c25e36bb36bbc7c2b4 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 7 Mar 2025 16:56:09 -0500 Subject: [PATCH 16/23] Implement close method. --- .../smoketest/concurrent/ConcurrentApp.java | 20 ++++++++++--------- .../concurrent/DemoExecutorService.java | 7 ++++++- .../smoketest/concurrent/DemoForkJoin.java | 5 +++++ .../concurrent/FibonacciCalculator.java | 5 ++++- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index 47dfaaf1c2b..ed3c1f3c2ab 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -8,14 +8,18 @@ public class ConcurrentApp { @WithSpan static void spanWrapper(String[] args) throws ExecutionException, InterruptedException { // calculate fibonacci using concurrent strategies - FibonacciCalculator calc; + FibonacciCalculator calc = null; for (String arg : args) { - if (arg.equalsIgnoreCase("executorService")) { - calc = new DemoExecutorService(); - calc.computeFibonacci(10); - } else if (arg.equalsIgnoreCase("forkJoin")) { - calc = new DemoForkJoin(); - calc.computeFibonacci(10); + try { + if (arg.equalsIgnoreCase("executorService")) { + calc = new DemoExecutorService(); + calc.computeFibonacci(10); + } else if (arg.equalsIgnoreCase("forkJoin")) { + calc = new DemoForkJoin(); + calc.computeFibonacci(10); + } + } finally { + calc.close(); } } } @@ -23,7 +27,5 @@ static void spanWrapper(String[] args) throws ExecutionException, InterruptedExc public static void main(String[] args) throws InterruptedException, ExecutionException { // wrap calculations in a span spanWrapper(args); - - System.exit(0); } } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java index e41b4dc1670..dee97579410 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java @@ -18,11 +18,16 @@ public DemoExecutorService() { @WithSpan @Override public long computeFibonacci(int n) throws ExecutionException, InterruptedException { - FibonacciTask task = new FibonacciTask(10); + FibonacciTask task = new FibonacciTask(n); Future future = executorService.submit(task); return future.get(); } + @Override + public void close() { + shutdown(); + } + private static class FibonacciTask implements Callable { private final int n; diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java index fda53d7f67d..e8fec3eceb0 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java @@ -17,6 +17,11 @@ public long computeFibonacci(int n) { return forkJoinPool.invoke(new FibonacciTask(n)); } + @Override + public void close() { + shutdown(); + } + private static class FibonacciTask extends RecursiveTask { private final int n; diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/FibonacciCalculator.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/FibonacciCalculator.java index 27c5fd1a984..73974d7b135 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/FibonacciCalculator.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/FibonacciCalculator.java @@ -2,6 +2,9 @@ import java.util.concurrent.ExecutionException; -public interface FibonacciCalculator { +public interface FibonacciCalculator extends AutoCloseable { long computeFibonacci(int n) throws ExecutionException, InterruptedException; + + @Override + void close(); } From b255c274a21c8e22e87f0bc30c1f8d9a03ef1a1d Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 7 Mar 2025 17:08:43 -0500 Subject: [PATCH 17/23] Organize methods in demo classes and add child span tests (but no child spans right now??). --- .../concurrent/DemoExecutorService.java | 15 ++++--------- .../smoketest/concurrent/DemoForkJoin.java | 12 +++------- .../smoketest/DemoExecutorServiceTest.groovy | 22 +++++++++++++++---- .../datadog/smoketest/DemoForkJoinTest.groovy | 22 +++++++++++++++---- .../smoketest/DemoMixedConcurrencyTest.groovy | 22 +++++++++++++++---- 5 files changed, 61 insertions(+), 32 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java index dee97579410..421112fe3a4 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java @@ -18,16 +18,10 @@ public DemoExecutorService() { @WithSpan @Override public long computeFibonacci(int n) throws ExecutionException, InterruptedException { - FibonacciTask task = new FibonacciTask(n); - Future future = executorService.submit(task); + Future future = executorService.submit(new FibonacciTask(n)); return future.get(); } - @Override - public void close() { - shutdown(); - } - private static class FibonacciTask implements Callable { private final int n; @@ -63,9 +57,8 @@ public void shutdown() { } } - public static void main(String[] args) throws ExecutionException, InterruptedException { - DemoExecutorService demoService = new DemoExecutorService(); - demoService.computeFibonacci(10); - demoService.shutdown(); + @Override + public void close() { + shutdown(); } } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java index e8fec3eceb0..106e308d57a 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java @@ -17,11 +17,6 @@ public long computeFibonacci(int n) { return forkJoinPool.invoke(new FibonacciTask(n)); } - @Override - public void close() { - shutdown(); - } - private static class FibonacciTask extends RecursiveTask { private final int n; @@ -46,9 +41,8 @@ public void shutdown() { forkJoinPool.shutdown(); } - public static void main(String[] args) { - DemoForkJoin demoService = new DemoForkJoin(); - demoService.computeFibonacci(10); - demoService.shutdown(); + @Override + public void close() { + shutdown(); } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 642efca3777..24e7e01c8ac 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -1,6 +1,6 @@ package datadog.smoketest -import datadog.trace.test.agent.decoder.DecodedSpan +import datadog.trace.test.agent.decoder.DecodedTrace import spock.util.concurrent.PollingConditions import java.util.function.Function @@ -28,8 +28,22 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { return {} // force traces decoding } - private static Function checkSpanName() { - return { span -> span.getName() == "ConcurrentApp.spanWrapper" } + private static Function checkTrace() { + return { trace -> + def parentSpanCount = 0 + def parentSpanId = -1 + def childSpanCount = 0 + + trace.spans.findAll {span -> (span.getName() == "ConcurrentApp.spanWrapper" || span.getParentId() == parentSpanId) }.each { innerSpan -> + if (innerSpan.getName() == "ConcurrentApp.spanWrapper") { + parentSpanCount++ + parentSpanId = innerSpan.getParentId() + } else { + childSpanCount++ + } + } + parentSpanCount == 1 && childSpanCount == 0 + } } def 'receive one expected trace for ExecutorService'() { @@ -40,7 +54,7 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { waitForTraceCount(1) then: - waitForSpan(poll, checkSpanName()) + waitForTrace(poll, checkTrace()) traceCount.get() == 1 and: diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index 80aa577acc1..d4bf94cf6cc 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -1,6 +1,6 @@ package datadog.smoketest -import datadog.trace.test.agent.decoder.DecodedSpan +import datadog.trace.test.agent.decoder.DecodedTrace import spock.util.concurrent.PollingConditions import java.util.function.Function import static java.util.concurrent.TimeUnit.SECONDS @@ -26,8 +26,22 @@ class DemoForkJoinTest extends AbstractSmokeTest { return {} // force traces decoding } - private static Function checkSpanName() { - return { span -> span.getName() == "ConcurrentApp.spanWrapper" } + private static Function checkTrace() { + return { trace -> + def parentSpanCount = 0 + def parentSpanId = -1 + def childSpanCount = 0 + + trace.spans.findAll {span -> (span.getName() == "ConcurrentApp.spanWrapper" || span.getParentId() == parentSpanId) }.each { innerSpan -> + if (innerSpan.getName() == "ConcurrentApp.spanWrapper") { + parentSpanCount++ + parentSpanId = innerSpan.getParentId() + } else { + childSpanCount++ + } + } + parentSpanCount == 1 && childSpanCount == 0 + } } def 'receive one expected trace for ForkJoin'() { @@ -38,7 +52,7 @@ class DemoForkJoinTest extends AbstractSmokeTest { waitForTraceCount(1) then: - waitForSpan(poll, checkSpanName()) + waitForTrace(poll, checkTrace()) traceCount.get() == 1 and: diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index 36ab86555f3..734ccddda91 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -1,6 +1,6 @@ package datadog.smoketest -import datadog.trace.test.agent.decoder.DecodedSpan +import datadog.trace.test.agent.decoder.DecodedTrace import spock.util.concurrent.PollingConditions import java.util.function.Function import static java.util.concurrent.TimeUnit.SECONDS @@ -26,8 +26,22 @@ class DemoMixedConcurrencyTest extends AbstractSmokeTest { return {} // force traces decoding } - private static Function checkSpanName() { - return { span -> span.getName() == "ConcurrentApp.spanWrapper" } + private static Function checkTrace() { + return { trace -> + def parentSpanCount = 0 + def parentSpanId = -1 + def childSpanCount = 0 + + trace.spans.findAll {span -> (span.getName() == "ConcurrentApp.spanWrapper" || span.getParentId() == parentSpanId) }.each { innerSpan -> + if (innerSpan.getName() == "ConcurrentApp.spanWrapper") { + parentSpanCount++ + parentSpanId = innerSpan.getParentId() + } else { + childSpanCount++ + } + } + parentSpanCount == 1 && childSpanCount == 0 + } } def 'receive one expected trace for ExecutorService and ForkJoin'() { @@ -38,7 +52,7 @@ class DemoMixedConcurrencyTest extends AbstractSmokeTest { waitForTraceCount(1) then: - waitForSpan(poll, checkSpanName()) + waitForTrace(poll, checkTrace()) traceCount.get() == 1 and: From e0d9c911eef6ccdea4d460fa7fcf0a485ff99fbb Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 7 Mar 2025 22:58:53 -0500 Subject: [PATCH 18/23] Edit tests. --- .../smoketest/DemoExecutorServiceTest.groovy | 18 +++++++++++------- .../datadog/smoketest/DemoForkJoinTest.groovy | 18 +++++++++++------- .../smoketest/DemoMixedConcurrencyTest.groovy | 18 +++++++++++------- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 24e7e01c8ac..2c54d69a1e7 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -31,18 +31,22 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { private static Function checkTrace() { return { trace -> def parentSpanCount = 0 - def parentSpanId = -1 + // def parentSpanId = -1 def childSpanCount = 0 + def otherSpanCount = 0 - trace.spans.findAll {span -> (span.getName() == "ConcurrentApp.spanWrapper" || span.getParentId() == parentSpanId) }.each { innerSpan -> - if (innerSpan.getName() == "ConcurrentApp.spanWrapper") { + trace.spans.each { span -> + if (span.getName() == "ConcurrentApp.spanWrapper") { parentSpanCount++ - parentSpanId = innerSpan.getParentId() - } else { - childSpanCount++ + // parentSpanId = span.getSpanId() } + // else if (parentSpanId != -1 && span.getParentId() == parentSpanId) { + // childSpanCount++ + // } else { + // otherSpanCount++ + // } } - parentSpanCount == 1 && childSpanCount == 0 + parentSpanCount == 1 && childSpanCount == 0 && otherSpanCount == 0 } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index d4bf94cf6cc..a143a162771 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -29,18 +29,22 @@ class DemoForkJoinTest extends AbstractSmokeTest { private static Function checkTrace() { return { trace -> def parentSpanCount = 0 - def parentSpanId = -1 + // def parentSpanId = -1 def childSpanCount = 0 + def otherSpanCount = 0 - trace.spans.findAll {span -> (span.getName() == "ConcurrentApp.spanWrapper" || span.getParentId() == parentSpanId) }.each { innerSpan -> - if (innerSpan.getName() == "ConcurrentApp.spanWrapper") { + trace.spans.each { span -> + if (span.getName() == "ConcurrentApp.spanWrapper") { parentSpanCount++ - parentSpanId = innerSpan.getParentId() - } else { - childSpanCount++ + // parentSpanId = span.getSpanId() } + // else if (parentSpanId != -1 && span.getParentId() == parentSpanId) { + // childSpanCount++ + // } else { + // otherSpanCount++ + // } } - parentSpanCount == 1 && childSpanCount == 0 + parentSpanCount == 1 && childSpanCount == 0 && otherSpanCount == 0 } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index 734ccddda91..57612494b21 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -29,18 +29,22 @@ class DemoMixedConcurrencyTest extends AbstractSmokeTest { private static Function checkTrace() { return { trace -> def parentSpanCount = 0 - def parentSpanId = -1 + // def parentSpanId = -1 def childSpanCount = 0 + def otherSpanCount = 0 - trace.spans.findAll {span -> (span.getName() == "ConcurrentApp.spanWrapper" || span.getParentId() == parentSpanId) }.each { innerSpan -> - if (innerSpan.getName() == "ConcurrentApp.spanWrapper") { + trace.spans.each { span -> + if (span.getName() == "ConcurrentApp.spanWrapper") { parentSpanCount++ - parentSpanId = innerSpan.getParentId() - } else { - childSpanCount++ + // parentSpanId = span.getSpanId() } + // else if (parentSpanId != -1 && span.getParentId() == parentSpanId) { + // childSpanCount++ + // } else { + // otherSpanCount++ + // } } - parentSpanCount == 1 && childSpanCount == 0 + parentSpanCount == 1 && childSpanCount == 0 && otherSpanCount == 0 } } From 23805ed6f594a3003014ae823aac8156f129cff2 Mon Sep 17 00:00:00 2001 From: Bruce Bujon Date: Mon, 10 Mar 2025 17:21:13 +0100 Subject: [PATCH 19/23] feat: Update executor app and checks --- .../smoketest/concurrent/ConcurrentApp.java | 30 +++++++-------- .../concurrent/DemoExecutorService.java | 35 ++++++----------- .../smoketest/DemoExecutorServiceTest.groovy | 38 +++++++++++-------- 3 files changed, 47 insertions(+), 56 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index ed3c1f3c2ab..125b5bad804 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -4,28 +4,24 @@ import java.util.concurrent.ExecutionException; public class ConcurrentApp { - - @WithSpan - static void spanWrapper(String[] args) throws ExecutionException, InterruptedException { + @WithSpan("main") + public static void main(String[] args) { // calculate fibonacci using concurrent strategies - FibonacciCalculator calc = null; for (String arg : args) { - try { - if (arg.equalsIgnoreCase("executorService")) { - calc = new DemoExecutorService(); - calc.computeFibonacci(10); - } else if (arg.equalsIgnoreCase("forkJoin")) { - calc = new DemoForkJoin(); - calc.computeFibonacci(10); - } - } finally { - calc.close(); + try (FibonacciCalculator calc = getCalculator(arg)) { + calc.computeFibonacci(10); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException("Failed to compute", e); } } } - public static void main(String[] args) throws InterruptedException, ExecutionException { - // wrap calculations in a span - spanWrapper(args); + private static FibonacciCalculator getCalculator(String name) { + if (name.equalsIgnoreCase("executorService")) { + return new DemoExecutorService(); + } else if (name.equalsIgnoreCase("forkJoin")) { + return new DemoForkJoin(); + } + throw new IllegalArgumentException("Unknown calculator: " + name); } } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java index 421112fe3a4..f17584b7336 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java @@ -1,64 +1,53 @@ package datadog.smoketest.concurrent; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + import io.opentelemetry.instrumentation.annotations.WithSpan; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; public class DemoExecutorService implements FibonacciCalculator { - private ExecutorService executorService; + private final ExecutorService executorService; public DemoExecutorService() { executorService = Executors.newFixedThreadPool(10); } - @WithSpan + @WithSpan("compute") @Override public long computeFibonacci(int n) throws ExecutionException, InterruptedException { - Future future = executorService.submit(new FibonacciTask(n)); + Future future = executorService.submit(new FibonacciTask(n)); return future.get(); } - private static class FibonacciTask implements Callable { + private class FibonacciTask implements Callable { private final int n; public FibonacciTask(int n) { this.n = n; } - @WithSpan @Override - public Integer call() { - if (n <= 1) { - return n; - } - return fibonacci(n); - } - - private int fibonacci(int n) { + public Long call() throws ExecutionException, InterruptedException { if (n <= 1) { - return n; + return (long) n; } - return fibonacci(n - 1) + fibonacci(n - 2); + return computeFibonacci(n - 1) + computeFibonacci(n - 2); } } - public void shutdown() { + @Override + public void close() { executorService.shutdown(); try { - if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) { + if (!executorService.awaitTermination(800, MILLISECONDS)) { executorService.shutdownNow(); } } catch (InterruptedException e) { executorService.shutdownNow(); } } - - @Override - public void close() { - shutdown(); - } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 2c54d69a1e7..7b7903fa106 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -1,5 +1,6 @@ package datadog.smoketest +import datadog.trace.test.agent.decoder.DecodedSpan import datadog.trace.test.agent.decoder.DecodedTrace import spock.util.concurrent.PollingConditions @@ -29,24 +30,29 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { } private static Function checkTrace() { - return { trace -> - def parentSpanCount = 0 - // def parentSpanId = -1 - def childSpanCount = 0 - def otherSpanCount = 0 - - trace.spans.each { span -> - if (span.getName() == "ConcurrentApp.spanWrapper") { - parentSpanCount++ - // parentSpanId = span.getSpanId() + return { + trace -> + // Get root span + def rootSpan = trace.spans.find { it.name == 'main' } + if (!rootSpan) { + return false + } + // Check every compute span is either a child of the root span or another compute span + def computeSpans = trace.spans.findAll { it.name == 'compute' } + if (computeSpans.isEmpty()) { + return false + } + return computeSpans.every { + // Check same trace + if (it.traceId != rootSpan.traceId) { + return false + } + // Check parent + if (it.parentId != rootSpan.spanId && trace.spans.find(s -> s.spanId == it.parentId).name != 'compute') { + return false } - // else if (parentSpanId != -1 && span.getParentId() == parentSpanId) { - // childSpanCount++ - // } else { - // otherSpanCount++ - // } + return true } - parentSpanCount == 1 && childSpanCount == 0 && otherSpanCount == 0 } } From a9b09707d63cdf9dd94598b2379c00d96ccea1da Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Mon, 10 Mar 2025 16:46:52 -0400 Subject: [PATCH 20/23] Propagate changes. --- .../smoketest/concurrent/ConcurrentApp.java | 4 +- .../smoketest/concurrent/DemoForkJoin.java | 13 ++---- .../smoketest/DemoExecutorServiceTest.groovy | 10 +++-- .../datadog/smoketest/DemoForkJoinTest.groovy | 42 ++++++++++++------- .../smoketest/DemoMixedConcurrencyTest.groovy | 42 ++++++++++++------- 5 files changed, 64 insertions(+), 47 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java index 125b5bad804..c17d84a8887 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/ConcurrentApp.java @@ -6,12 +6,12 @@ public class ConcurrentApp { @WithSpan("main") public static void main(String[] args) { - // calculate fibonacci using concurrent strategies + // Calculate fibonacci using concurrent strategies for (String arg : args) { try (FibonacciCalculator calc = getCalculator(arg)) { calc.computeFibonacci(10); } catch (ExecutionException | InterruptedException e) { - throw new RuntimeException("Failed to compute", e); + throw new RuntimeException("Failed to compute fibonacci number.", e); } } } diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java index 106e308d57a..edf9d32289c 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java @@ -5,26 +5,25 @@ import java.util.concurrent.RecursiveTask; public class DemoForkJoin implements FibonacciCalculator { - private ForkJoinPool forkJoinPool; + private final ForkJoinPool forkJoinPool; public DemoForkJoin() { forkJoinPool = new ForkJoinPool(); } - @WithSpan + @WithSpan("compute") @Override public long computeFibonacci(int n) { return forkJoinPool.invoke(new FibonacciTask(n)); } - private static class FibonacciTask extends RecursiveTask { + private class FibonacciTask extends RecursiveTask { private final int n; public FibonacciTask(int n) { this.n = n; } - @WithSpan @Override protected Long compute() { if (n <= 1) { @@ -37,12 +36,8 @@ protected Long compute() { } } - public void shutdown() { - forkJoinPool.shutdown(); - } - @Override public void close() { - shutdown(); + forkJoinPool.shutdown(); } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 7b7903fa106..152cee24f14 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -1,11 +1,8 @@ package datadog.smoketest -import datadog.trace.test.agent.decoder.DecodedSpan import datadog.trace.test.agent.decoder.DecodedTrace import spock.util.concurrent.PollingConditions - import java.util.function.Function - import static java.util.concurrent.TimeUnit.SECONDS class DemoExecutorServiceTest extends AbstractSmokeTest { @@ -37,7 +34,12 @@ class DemoExecutorServiceTest extends AbstractSmokeTest { if (!rootSpan) { return false } - // Check every compute span is either a child of the root span or another compute span + // Check that there are only 'main' and 'compute' spans + def otherSpans = trace.spans.findAll { it.name != 'main' && it.name != 'compute' } + if (!otherSpans.isEmpty()) { + return false + } + // Check every 'compute' span is either a child of the root span or another 'compute' span def computeSpans = trace.spans.findAll { it.name == 'compute' } if (computeSpans.isEmpty()) { return false diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index a143a162771..83294a6ebdd 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -27,24 +27,34 @@ class DemoForkJoinTest extends AbstractSmokeTest { } private static Function checkTrace() { - return { trace -> - def parentSpanCount = 0 - // def parentSpanId = -1 - def childSpanCount = 0 - def otherSpanCount = 0 - - trace.spans.each { span -> - if (span.getName() == "ConcurrentApp.spanWrapper") { - parentSpanCount++ - // parentSpanId = span.getSpanId() + return { + trace -> + // Get root span + def rootSpan = trace.spans.find { it.name == 'main' } + if (!rootSpan) { + return false + } + // Check that there are only 'main' and 'compute' spans + def otherSpans = trace.spans.findAll { it.name != 'main' && it.name != 'compute' } + if (!otherSpans.isEmpty()) { + return false + } + // Check every 'compute' span is either a child of the root span or another 'compute' span + def computeSpans = trace.spans.findAll { it.name == 'compute' } + if (computeSpans.isEmpty()) { + return false + } + return computeSpans.every { + // Check same trace + if (it.traceId != rootSpan.traceId) { + return false + } + // Check parent + if (it.parentId != rootSpan.spanId && trace.spans.find(s -> s.spanId == it.parentId).name != 'compute') { + return false } - // else if (parentSpanId != -1 && span.getParentId() == parentSpanId) { - // childSpanCount++ - // } else { - // otherSpanCount++ - // } + return true } - parentSpanCount == 1 && childSpanCount == 0 && otherSpanCount == 0 } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index 57612494b21..29d4ade0c4c 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -27,24 +27,34 @@ class DemoMixedConcurrencyTest extends AbstractSmokeTest { } private static Function checkTrace() { - return { trace -> - def parentSpanCount = 0 - // def parentSpanId = -1 - def childSpanCount = 0 - def otherSpanCount = 0 - - trace.spans.each { span -> - if (span.getName() == "ConcurrentApp.spanWrapper") { - parentSpanCount++ - // parentSpanId = span.getSpanId() + return { + trace -> + // Get root span + def rootSpan = trace.spans.find { it.name == 'main' } + if (!rootSpan) { + return false + } + // Check that there are only 'main' and 'compute' spans + def otherSpans = trace.spans.findAll { it.name != 'main' && it.name != 'compute' } + if (!otherSpans.isEmpty()) { + return false + } + // Check every 'compute' span is either a child of the root span or another 'compute' span + def computeSpans = trace.spans.findAll { it.name == 'compute' } + if (computeSpans.isEmpty()) { + return false + } + return computeSpans.every { + // Check same trace + if (it.traceId != rootSpan.traceId) { + return false + } + // Check parent + if (it.parentId != rootSpan.spanId && trace.spans.find(s -> s.spanId == it.parentId).name != 'compute') { + return false } - // else if (parentSpanId != -1 && span.getParentId() == parentSpanId) { - // childSpanCount++ - // } else { - // otherSpanCount++ - // } + return true } - parentSpanCount == 1 && childSpanCount == 0 && otherSpanCount == 0 } } From f45451258c78b507f3bfb28698593933a98bc090 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Mon, 10 Mar 2025 18:51:22 -0400 Subject: [PATCH 21/23] Refactor tests. --- .../datadog/smoketest/AbstractDemoTest.groovy | 61 ++++++++++++++++++ .../smoketest/DemoExecutorServiceTest.groovy | 62 ++---------------- .../datadog/smoketest/DemoForkJoinTest.groovy | 64 ++----------------- .../smoketest/DemoMixedConcurrencyTest.groovy | 64 ++----------------- .../smoketest/AbstractSmokeTest.groovy | 12 ++-- 5 files changed, 81 insertions(+), 182 deletions(-) create mode 100644 dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/AbstractDemoTest.groovy diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/AbstractDemoTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/AbstractDemoTest.groovy new file mode 100644 index 00000000000..63a2d8bac67 --- /dev/null +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/AbstractDemoTest.groovy @@ -0,0 +1,61 @@ +package datadog.smoketest + +import datadog.trace.test.agent.decoder.DecodedTrace + +import java.util.function.Function + +abstract class AbstractDemoTest extends AbstractSmokeTest { + protected static final int TIMEOUT_SECS = 10 + protected abstract List getTestArguments() + + @Override + ProcessBuilder createProcessBuilder() { + def jarPath = System.getProperty("datadog.smoketest.shadowJar.path") + def command = new ArrayList() + command.add(javaPath()) + command.addAll(defaultJavaProperties) + command.add("-Ddd.trace.otel.enabled=true") + command.addAll(["-jar", jarPath]) + command.addAll(getTestArguments()) + + ProcessBuilder processBuilder = new ProcessBuilder(command) + processBuilder.directory(new File(buildDirectory)) + } + + @Override + Closure decodedTracesCallback() { + return {} // force traces decoding + } + + protected static Function checkTrace() { + return { + trace -> + // Get root span + def rootSpan = trace.spans.find { it.name == 'main' } + if (!rootSpan) { + return false + } + // Check that there are only 'main' and 'compute' spans + def otherSpans = trace.spans.findAll { it.name != 'main' && it.name != 'compute' } + if (!otherSpans.isEmpty()) { + return false + } + // Check every 'compute' span is either a child of the root span or another 'compute' span + def computeSpans = trace.spans.findAll { it.name == 'compute' } + if (computeSpans.isEmpty()) { + return false + } + return computeSpans.every { + // Check same trace + if (it.traceId != rootSpan.traceId) { + return false + } + // Check parent + if (it.parentId != rootSpan.spanId && trace.spans.find(s -> s.spanId == it.parentId).name != 'compute') { + return false + } + return true + } + } + } +} diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 152cee24f14..0d2e41a763f 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -1,72 +1,18 @@ package datadog.smoketest -import datadog.trace.test.agent.decoder.DecodedTrace -import spock.util.concurrent.PollingConditions -import java.util.function.Function import static java.util.concurrent.TimeUnit.SECONDS -class DemoExecutorServiceTest extends AbstractSmokeTest { - public static final int TIMEOUT_SECS = 10 - - @Override - ProcessBuilder createProcessBuilder() { - def jarPath = System.getProperty("datadog.smoketest.shadowJar.path") - def command = new ArrayList() - command.add(javaPath()) - command.addAll(defaultJavaProperties) - command.add("-Ddd.trace.otel.enabled=true") - command.addAll(["-jar", jarPath, "executorService"]) - - ProcessBuilder processBuilder = new ProcessBuilder(command) - processBuilder.directory(new File(buildDirectory)) - } - +class DemoExecutorServiceTest extends AbstractDemoTest { @Override - Closure decodedTracesCallback() { - return {} // force traces decoding - } - - private static Function checkTrace() { - return { - trace -> - // Get root span - def rootSpan = trace.spans.find { it.name == 'main' } - if (!rootSpan) { - return false - } - // Check that there are only 'main' and 'compute' spans - def otherSpans = trace.spans.findAll { it.name != 'main' && it.name != 'compute' } - if (!otherSpans.isEmpty()) { - return false - } - // Check every 'compute' span is either a child of the root span or another 'compute' span - def computeSpans = trace.spans.findAll { it.name == 'compute' } - if (computeSpans.isEmpty()) { - return false - } - return computeSpans.every { - // Check same trace - if (it.traceId != rootSpan.traceId) { - return false - } - // Check parent - if (it.parentId != rootSpan.spanId && trace.spans.find(s -> s.spanId == it.parentId).name != 'compute') { - return false - } - return true - } - } + protected List getTestArguments() { + return ["executorService"] } def 'receive one expected trace for ExecutorService'() { - given: - def poll = new PollingConditions(timeout: TIMEOUT_SECS) - when: - waitForTraceCount(1) + waitForTrace(DEFAULT_POLL, checkTrace()) then: - waitForTrace(poll, checkTrace()) traceCount.get() == 1 and: diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index 83294a6ebdd..108a0fcaab3 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -1,72 +1,18 @@ package datadog.smoketest -import datadog.trace.test.agent.decoder.DecodedTrace -import spock.util.concurrent.PollingConditions -import java.util.function.Function import static java.util.concurrent.TimeUnit.SECONDS -class DemoForkJoinTest extends AbstractSmokeTest { - public static final int TIMEOUT_SECS = 10 - - @Override - ProcessBuilder createProcessBuilder() { - def jarPath = System.getProperty("datadog.smoketest.shadowJar.path") - def command = new ArrayList() - command.add(javaPath()) - command.addAll(defaultJavaProperties) - command.add("-Ddd.trace.otel.enabled=true") - command.addAll(["-jar", jarPath, "forkJoin"]) - - ProcessBuilder processBuilder = new ProcessBuilder(command) - processBuilder.directory(new File(buildDirectory)) - } - +class DemoForkJoinTest extends AbstractDemoTest { @Override - Closure decodedTracesCallback() { - return {} // force traces decoding - } - - private static Function checkTrace() { - return { - trace -> - // Get root span - def rootSpan = trace.spans.find { it.name == 'main' } - if (!rootSpan) { - return false - } - // Check that there are only 'main' and 'compute' spans - def otherSpans = trace.spans.findAll { it.name != 'main' && it.name != 'compute' } - if (!otherSpans.isEmpty()) { - return false - } - // Check every 'compute' span is either a child of the root span or another 'compute' span - def computeSpans = trace.spans.findAll { it.name == 'compute' } - if (computeSpans.isEmpty()) { - return false - } - return computeSpans.every { - // Check same trace - if (it.traceId != rootSpan.traceId) { - return false - } - // Check parent - if (it.parentId != rootSpan.spanId && trace.spans.find(s -> s.spanId == it.parentId).name != 'compute') { - return false - } - return true - } - } + protected List getTestArguments() { + return ["forkJoin"] } - def 'receive one expected trace for ForkJoin'() { - given: - def poll = new PollingConditions(timeout: TIMEOUT_SECS) - + def 'receive one expected trace for ExecutorService'() { when: - waitForTraceCount(1) + waitForTrace(DEFAULT_POLL, checkTrace()) then: - waitForTrace(poll, checkTrace()) traceCount.get() == 1 and: diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index 29d4ade0c4c..1dc405817ff 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -1,72 +1,18 @@ package datadog.smoketest -import datadog.trace.test.agent.decoder.DecodedTrace -import spock.util.concurrent.PollingConditions -import java.util.function.Function import static java.util.concurrent.TimeUnit.SECONDS -class DemoMixedConcurrencyTest extends AbstractSmokeTest { - public static final int TIMEOUT_SECS = 10 - - @Override - ProcessBuilder createProcessBuilder() { - def jarPath = System.getProperty("datadog.smoketest.shadowJar.path") - def command = new ArrayList() - command.add(javaPath()) - command.addAll(defaultJavaProperties) - command.add("-Ddd.trace.otel.enabled=true") - command.addAll(["-jar", jarPath, "executorService", "forkJoin"]) - - ProcessBuilder processBuilder = new ProcessBuilder(command) - processBuilder.directory(new File(buildDirectory)) - } - +class DemoMixedConcurrencyTest extends AbstractDemoTest { @Override - Closure decodedTracesCallback() { - return {} // force traces decoding - } - - private static Function checkTrace() { - return { - trace -> - // Get root span - def rootSpan = trace.spans.find { it.name == 'main' } - if (!rootSpan) { - return false - } - // Check that there are only 'main' and 'compute' spans - def otherSpans = trace.spans.findAll { it.name != 'main' && it.name != 'compute' } - if (!otherSpans.isEmpty()) { - return false - } - // Check every 'compute' span is either a child of the root span or another 'compute' span - def computeSpans = trace.spans.findAll { it.name == 'compute' } - if (computeSpans.isEmpty()) { - return false - } - return computeSpans.every { - // Check same trace - if (it.traceId != rootSpan.traceId) { - return false - } - // Check parent - if (it.parentId != rootSpan.spanId && trace.spans.find(s -> s.spanId == it.parentId).name != 'compute') { - return false - } - return true - } - } + protected List getTestArguments() { + return ["executorService", "forkJoin"] } - def 'receive one expected trace for ExecutorService and ForkJoin'() { - given: - def poll = new PollingConditions(timeout: TIMEOUT_SECS) - + def 'receive one expected trace for ExecutorService'() { when: - waitForTraceCount(1) + waitForTrace(DEFAULT_POLL, checkTrace()) then: - waitForTrace(poll, checkTrace()) traceCount.get() == 1 and: diff --git a/dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy b/dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy index 0d1192696f5..ead0c9716f1 100644 --- a/dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy +++ b/dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy @@ -50,6 +50,9 @@ abstract class AbstractSmokeTest extends ProcessManager { @Shared protected TestHttpServer.Headers lastTraceRequestHeaders = null + @Shared + protected final PollingConditions DEFAULT_POLL = new PollingConditions(timeout: 30, initialDelay: 0, delay: 1, factor: 1) + @Shared @AutoCleanup protected TestHttpServer server = httpServer { @@ -292,8 +295,7 @@ abstract class AbstractSmokeTest extends ProcessManager { } int waitForTraceCount(int count) { - def conditions = new PollingConditions(timeout: 30, initialDelay: 0, delay: 0.5, factor: 1) - return waitForTraceCount(count, conditions) + return waitForTraceCount(count, DEFAULT_POLL) } int waitForTraceCount(int count, PollingConditions conditions) { @@ -325,8 +327,7 @@ abstract class AbstractSmokeTest extends ProcessManager { } void waitForTelemetryCount(final int count) { - def conditions = new PollingConditions(timeout: 30, initialDelay: 0, delay: 1, factor: 1) - waitForTelemetryCount(conditions, count) + waitForTelemetryCount(DEFAULT_POLL, count) } void waitForTelemetryCount(final PollingConditions poll, final int count) { @@ -336,8 +337,7 @@ abstract class AbstractSmokeTest extends ProcessManager { } void waitForTelemetryFlat(final Function, Boolean> predicate) { - def conditions = new PollingConditions(timeout: 30, initialDelay: 0, delay: 1, factor: 1) - waitForTelemetryFlat(conditions, predicate) + waitForTelemetryFlat(DEFAULT_POLL, predicate) } void waitForTelemetryFlat(final PollingConditions poll, final Function, Boolean> predicate) { From 0023c3a006cda4dd4498ca0d5a37b1d8b162a8a3 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Mon, 10 Mar 2025 20:16:25 -0400 Subject: [PATCH 22/23] Fix variable name. --- .../datadog/smoketest/DemoExecutorServiceTest.groovy | 2 +- .../test/groovy/datadog/smoketest/DemoForkJoinTest.groovy | 2 +- .../datadog/smoketest/DemoMixedConcurrencyTest.groovy | 2 +- .../groovy/datadog/smoketest/AbstractSmokeTest.groovy | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 0d2e41a763f..9c5551d2dbe 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -10,7 +10,7 @@ class DemoExecutorServiceTest extends AbstractDemoTest { def 'receive one expected trace for ExecutorService'() { when: - waitForTrace(DEFAULT_POLL, checkTrace()) + waitForTrace(defaultPoll, checkTrace()) then: traceCount.get() == 1 diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index 108a0fcaab3..d743be6445a 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -10,7 +10,7 @@ class DemoForkJoinTest extends AbstractDemoTest { def 'receive one expected trace for ExecutorService'() { when: - waitForTrace(DEFAULT_POLL, checkTrace()) + waitForTrace(defaultPoll, checkTrace()) then: traceCount.get() == 1 diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy index 1dc405817ff..52d79aab04a 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy @@ -10,7 +10,7 @@ class DemoMixedConcurrencyTest extends AbstractDemoTest { def 'receive one expected trace for ExecutorService'() { when: - waitForTrace(DEFAULT_POLL, checkTrace()) + waitForTrace(defaultPoll, checkTrace()) then: traceCount.get() == 1 diff --git a/dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy b/dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy index ead0c9716f1..e5d1c70f019 100644 --- a/dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy +++ b/dd-smoke-tests/src/main/groovy/datadog/smoketest/AbstractSmokeTest.groovy @@ -51,7 +51,7 @@ abstract class AbstractSmokeTest extends ProcessManager { protected TestHttpServer.Headers lastTraceRequestHeaders = null @Shared - protected final PollingConditions DEFAULT_POLL = new PollingConditions(timeout: 30, initialDelay: 0, delay: 1, factor: 1) + protected final PollingConditions defaultPoll = new PollingConditions(timeout: 30, initialDelay: 0, delay: 1, factor: 1) @Shared @AutoCleanup @@ -295,7 +295,7 @@ abstract class AbstractSmokeTest extends ProcessManager { } int waitForTraceCount(int count) { - return waitForTraceCount(count, DEFAULT_POLL) + return waitForTraceCount(count, defaultPoll) } int waitForTraceCount(int count, PollingConditions conditions) { @@ -327,7 +327,7 @@ abstract class AbstractSmokeTest extends ProcessManager { } void waitForTelemetryCount(final int count) { - waitForTelemetryCount(DEFAULT_POLL, count) + waitForTelemetryCount(defaultPoll, count) } void waitForTelemetryCount(final PollingConditions poll, final int count) { @@ -337,7 +337,7 @@ abstract class AbstractSmokeTest extends ProcessManager { } void waitForTelemetryFlat(final Function, Boolean> predicate) { - waitForTelemetryFlat(DEFAULT_POLL, predicate) + waitForTelemetryFlat(defaultPoll, predicate) } void waitForTelemetryFlat(final PollingConditions poll, final Function, Boolean> predicate) { From 6a0fae5eef14fe476725be51907d620c3c55f2e7 Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Tue, 11 Mar 2025 13:50:00 -0400 Subject: [PATCH 23/23] Adjust tests again. --- .../concurrent/DemoExecutorService.java | 4 ++-- .../smoketest/concurrent/DemoForkJoin.java | 2 +- .../datadog/smoketest/AbstractDemoTest.groovy | 23 +++++++++++-------- .../smoketest/DemoExecutorServiceTest.groovy | 16 +++---------- .../datadog/smoketest/DemoForkJoinTest.groovy | 16 +++---------- .../smoketest/DemoMixedConcurrencyTest.groovy | 22 ------------------ .../DemoMultipleConcurrenciesTest.groovy | 12 ++++++++++ 7 files changed, 35 insertions(+), 60 deletions(-) delete mode 100644 dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy create mode 100644 dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMultipleConcurrenciesTest.groovy diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java index f17584b7336..2de2b76ccf3 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoExecutorService.java @@ -1,6 +1,6 @@ package datadog.smoketest.concurrent; -import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; import io.opentelemetry.instrumentation.annotations.WithSpan; import java.util.concurrent.Callable; @@ -43,7 +43,7 @@ public Long call() throws ExecutionException, InterruptedException { public void close() { executorService.shutdown(); try { - if (!executorService.awaitTermination(800, MILLISECONDS)) { + if (!executorService.awaitTermination(10, SECONDS)) { executorService.shutdownNow(); } } catch (InterruptedException e) { diff --git a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java index edf9d32289c..dd77f86f324 100644 --- a/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java +++ b/dd-smoke-tests/concurrent/src/main/java/datadog/smoketest/concurrent/DemoForkJoin.java @@ -11,7 +11,6 @@ public DemoForkJoin() { forkJoinPool = new ForkJoinPool(); } - @WithSpan("compute") @Override public long computeFibonacci(int n) { return forkJoinPool.invoke(new FibonacciTask(n)); @@ -24,6 +23,7 @@ public FibonacciTask(int n) { this.n = n; } + @WithSpan("compute") @Override protected Long compute() { if (n <= 1) { diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/AbstractDemoTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/AbstractDemoTest.groovy index 63a2d8bac67..1628d0459df 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/AbstractDemoTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/AbstractDemoTest.groovy @@ -1,7 +1,7 @@ package datadog.smoketest +import static java.util.concurrent.TimeUnit.SECONDS import datadog.trace.test.agent.decoder.DecodedTrace - import java.util.function.Function abstract class AbstractDemoTest extends AbstractSmokeTest { @@ -30,9 +30,9 @@ abstract class AbstractDemoTest extends AbstractSmokeTest { protected static Function checkTrace() { return { trace -> - // Get root span - def rootSpan = trace.spans.find { it.name == 'main' } - if (!rootSpan) { + // Check for 'main' span + def mainSpan = trace.spans.find { it.name == 'main' } + if (!mainSpan) { return false } // Check that there are only 'main' and 'compute' spans @@ -40,22 +40,27 @@ abstract class AbstractDemoTest extends AbstractSmokeTest { if (!otherSpans.isEmpty()) { return false } - // Check every 'compute' span is either a child of the root span or another 'compute' span + // Check that every 'compute' span is in the same trace and is either a child of the 'main' span or another 'compute' span def computeSpans = trace.spans.findAll { it.name == 'compute' } if (computeSpans.isEmpty()) { return false } return computeSpans.every { - // Check same trace - if (it.traceId != rootSpan.traceId) { + if (it.traceId != mainSpan.traceId) { return false } - // Check parent - if (it.parentId != rootSpan.spanId && trace.spans.find(s -> s.spanId == it.parentId).name != 'compute') { + if (it.parentId != mainSpan.spanId && trace.spans.find(s -> s.spanId == it.parentId).name != 'compute') { return false } return true } } } + + protected void receivedCorrectTrace() { + waitForTrace(defaultPoll, checkTrace()) + assert traceCount.get() == 1 + assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) + assert testedProcess.exitValue() == 0 + } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy index 9c5551d2dbe..b99891b89bb 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoExecutorServiceTest.groovy @@ -1,22 +1,12 @@ package datadog.smoketest -import static java.util.concurrent.TimeUnit.SECONDS - class DemoExecutorServiceTest extends AbstractDemoTest { - @Override protected List getTestArguments() { return ["executorService"] } - def 'receive one expected trace for ExecutorService'() { - when: - waitForTrace(defaultPoll, checkTrace()) - - then: - traceCount.get() == 1 - - and: - assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) - assert testedProcess.exitValue() == 0 + def 'receive one correct trace when using ExecutorService'() { + expect: + receivedCorrectTrace() } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy index d743be6445a..00994a6ef4f 100644 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoForkJoinTest.groovy @@ -1,22 +1,12 @@ package datadog.smoketest -import static java.util.concurrent.TimeUnit.SECONDS - class DemoForkJoinTest extends AbstractDemoTest { - @Override protected List getTestArguments() { return ["forkJoin"] } - def 'receive one expected trace for ExecutorService'() { - when: - waitForTrace(defaultPoll, checkTrace()) - - then: - traceCount.get() == 1 - - and: - assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) - assert testedProcess.exitValue() == 0 + def 'receive one correct trace when using ForkJoin'() { + expect: + receivedCorrectTrace() } } diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy deleted file mode 100644 index 52d79aab04a..00000000000 --- a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMixedConcurrencyTest.groovy +++ /dev/null @@ -1,22 +0,0 @@ -package datadog.smoketest - -import static java.util.concurrent.TimeUnit.SECONDS - -class DemoMixedConcurrencyTest extends AbstractDemoTest { - @Override - protected List getTestArguments() { - return ["executorService", "forkJoin"] - } - - def 'receive one expected trace for ExecutorService'() { - when: - waitForTrace(defaultPoll, checkTrace()) - - then: - traceCount.get() == 1 - - and: - assert testedProcess.waitFor(TIMEOUT_SECS, SECONDS) - assert testedProcess.exitValue() == 0 - } -} diff --git a/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMultipleConcurrenciesTest.groovy b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMultipleConcurrenciesTest.groovy new file mode 100644 index 00000000000..06ec5dc67b2 --- /dev/null +++ b/dd-smoke-tests/concurrent/src/test/groovy/datadog/smoketest/DemoMultipleConcurrenciesTest.groovy @@ -0,0 +1,12 @@ +package datadog.smoketest + +class DemoMultipleConcurrenciesTest extends AbstractDemoTest { + protected List getTestArguments() { + return ["executorService", "forkJoin"] + } + + def 'receive one correct trace when using multiple concurrency strategies (ExecutorService and ForkJoin)'() { + expect: + receivedCorrectTrace() + } +}