From b21e36159182129ae8e9371652898b3e4f488834 Mon Sep 17 00:00:00 2001 From: heathkd Date: Tue, 21 Jan 2020 17:09:36 -0500 Subject: [PATCH] add test for interval task and trigger task --- .../SpringRepositoryInstrumentation.java | 27 +++---- .../SpringSchedulingDecorator.java | 25 ++++++- .../SpringSchedulingInstrumentation.java | 42 ++++++++--- .../src/test/groovy/ReportTimeTest.groovy | 71 ------------------ .../test/groovy/SpringSchedulingTest.groovy | 60 ++++++++++++++++ .../src/test/java/IntervalTask.java | 41 +++++++++++ .../src/test/java/IntervalTaskConfig.java | 12 ++++ .../src/test/java/ScheduledTasks.java | 72 ------------------- .../src/test/java/ScheduledTasksConfig.java | 10 --- .../src/test/java/TriggerTask.java | 44 ++++++++++++ .../src/test/java/TriggerTaskConfig.java | 12 ++++ 11 files changed, 238 insertions(+), 178 deletions(-) delete mode 100644 dd-java-agent/instrumentation/spring-scheduling/src/test/groovy/ReportTimeTest.groovy create mode 100644 dd-java-agent/instrumentation/spring-scheduling/src/test/groovy/SpringSchedulingTest.groovy create mode 100644 dd-java-agent/instrumentation/spring-scheduling/src/test/java/IntervalTask.java create mode 100644 dd-java-agent/instrumentation/spring-scheduling/src/test/java/IntervalTaskConfig.java delete mode 100644 dd-java-agent/instrumentation/spring-scheduling/src/test/java/ScheduledTasks.java delete mode 100644 dd-java-agent/instrumentation/spring-scheduling/src/test/java/ScheduledTasksConfig.java create mode 100644 dd-java-agent/instrumentation/spring-scheduling/src/test/java/TriggerTask.java create mode 100644 dd-java-agent/instrumentation/spring-scheduling/src/test/java/TriggerTaskConfig.java diff --git a/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringRepositoryInstrumentation.java b/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringRepositoryInstrumentation.java index b06a699291..c56c3c7915 100644 --- a/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringRepositoryInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringRepositoryInstrumentation.java @@ -2,21 +2,10 @@ package datadog.trace.instrumentation.springdata; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; -import static datadog.trace.instrumentation.springdata.SpringDataDecorator.DECORATOR; -import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; - import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; -import datadog.trace.bootstrap.instrumentation.api.AgentScope; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.Map; +import datadog.trace.instrumentation.api.AgentScope; +import datadog.trace.instrumentation.api.AgentSpan; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; @@ -29,6 +18,18 @@ import org.springframework.data.repository.core.RepositoryInformation; import org.springframework.data.repository.core.support.RepositoryFactorySupport; import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Map; + +import static datadog.trace.instrumentation.api.AgentTracer.activateSpan; +import static datadog.trace.instrumentation.api.AgentTracer.startSpan; +import static datadog.trace.instrumentation.springdata.SpringDataDecorator.DECORATOR; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; + @AutoService(Instrumenter.class) public final class SpringRepositoryInstrumentation extends Instrumenter.Default { diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingDecorator.java b/dd-java-agent/instrumentation/spring-scheduling/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingDecorator.java index 0ec3ec801c..16a41b8a67 100644 --- a/dd-java-agent/instrumentation/spring-scheduling/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingDecorator.java +++ b/dd-java-agent/instrumentation/spring-scheduling/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingDecorator.java @@ -3,9 +3,14 @@ package datadog.trace.instrumentation.springscheduling; import datadog.trace.agent.decorator.BaseDecorator; +import datadog.trace.api.DDTags; +import datadog.trace.instrumentation.api.AgentSpan; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.support.ScheduledMethodRunnable; -public final class SpringSchedulingDecorator extends BaseDecorator { - public static final SpringSchedulingDecorator DECORATOR = new SpringSchedulingDecorator(); +@Slf4j +public class SpringSchedulingDecorator extends BaseDecorator { + public static final SpringSchedulingDecorator DECORATE = new SpringSchedulingDecorator(); private SpringSchedulingDecorator() {} @@ -23,4 +28,20 @@ public final class SpringSchedulingDecorator extends BaseDecorator { protected String component() { return "spring-scheduling"; } + + public AgentSpan onRun(final AgentSpan span, final Runnable runnable) { + if (runnable != null) { + String resourceName = ""; + if (runnable instanceof ScheduledMethodRunnable) { + final ScheduledMethodRunnable scheduledMethodRunnable = (ScheduledMethodRunnable) runnable; + resourceName = spanNameForMethod(scheduledMethodRunnable.getMethod()); + } else { + final String className = runnable.getClass().getName(); + final String methodName = "run"; + resourceName = className + "." + methodName; + } + span.setTag(DDTags.RESOURCE_NAME, resourceName); + } + return span; + } } diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingInstrumentation.java b/dd-java-agent/instrumentation/spring-scheduling/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingInstrumentation.java index 3a8c08096f..2fd4add348 100644 --- a/dd-java-agent/instrumentation/spring-scheduling/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-scheduling/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingInstrumentation.java @@ -1,19 +1,26 @@ -// This file includes software developed at SignalFx - package datadog.trace.instrumentation.springscheduling; -import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.*; - import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; -import datadog.trace.api.Trace; -import java.util.Map; +import datadog.trace.instrumentation.api.AgentScope; +import datadog.trace.instrumentation.api.AgentSpan; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import java.util.Map; + +import static datadog.trace.instrumentation.api.AgentTracer.activateSpan; +import static datadog.trace.instrumentation.api.AgentTracer.startSpan; +import static datadog.trace.instrumentation.springscheduling.SpringSchedulingDecorator.DECORATE; +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + @AutoService(Instrumenter.class) public final class SpringSchedulingInstrumentation extends Instrumenter.Default { @@ -39,7 +46,7 @@ public final class SpringSchedulingInstrumentation extends Instrumenter.Default public Map, String> transformers() { return singletonMap( isConstructor().and(takesArgument(0, Runnable.class)), - SpringSchedulingInstrumentation.class.getName() + "$RepositoryFactorySupportAdvice"); + SpringSchedulingInstrumentation.class.getName() + "$SpringSchedulingAdvice"); } public static class SpringSchedulingAdvice { @@ -57,10 +64,25 @@ public final class SpringSchedulingInstrumentation extends Instrumenter.Default this.runnable = runnable; } - @Trace @Override public void run() { - runnable.run(); + final AgentSpan span = startSpan("scheduled.call"); + DECORATE.afterStart(span); + + try (final AgentScope scope = activateSpan(span, false)) { + DECORATE.onRun(span, runnable); + scope.setAsyncPropagation(true); + + try { + runnable.run(); + } catch (final Throwable throwable) { + DECORATE.onError(span, throwable); + throw throwable; + } + } finally { + DECORATE.beforeFinish(span); + span.finish(); + } } public static Runnable wrapIfNeeded(final Runnable task) { diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/test/groovy/ReportTimeTest.groovy b/dd-java-agent/instrumentation/spring-scheduling/src/test/groovy/ReportTimeTest.groovy deleted file mode 100644 index 0960df9909..0000000000 --- a/dd-java-agent/instrumentation/spring-scheduling/src/test/groovy/ReportTimeTest.groovy +++ /dev/null @@ -1,71 +0,0 @@ -import datadog.trace.agent.test.AgentTestRunner -import datadog.trace.agent.test.utils.ConfigUtils -import datadog.trace.instrumentation.api.Tags -import org.springframework.context.annotation.AnnotationConfigApplicationContext - -class ReportTimeTest extends AgentTestRunner { - - static { - ConfigUtils.updateConfig { - System.clearProperty("dd.trace.annotations") - } - } - - def "test method executed"() { - setup: - def scheduledTask = new ScheduledTasks(); - scheduledTask.reportCurrentTime(); - - expect: - assert scheduledTask.reportCurrentTimeExecuted == true; - } - - def "trace fired"() { - setup: - def scheduledTask = new ScheduledTasks(); - scheduledTask.reportCurrentTime(); - - expect: - assertTraces(1) { - trace(0, 1) { - span(0) { - serviceName "test" - resourceName "ScheduledTasks.reportCurrentTime" - operationName "trace.annotation" - parent() - errored false - tags { -// "$Tags.COMPONENT" "scheduled" - "$Tags.COMPONENT" "trace" - defaultTags() - } - } - } - } - } - - def "test with context"() { - setup: - def context = new AnnotationConfigApplicationContext(ScheduledTasksConfig) // provide config as argument - def task = context.getBean(ScheduledTasks) // provide class we are trying to test - task.reportCurrentTime() - - expect: - assertTraces(1) { - trace(0, 1) { - span(0) { - serviceName "test" - resourceName "ScheduledTasks.reportCurrentTime" - operationName "trace.annotation" - parent() - errored false - tags { -// "$Tags.COMPONENT" "scheduled" - "$Tags.COMPONENT" "trace" - defaultTags() - } - } - } - } - } -} diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/test/groovy/SpringSchedulingTest.groovy b/dd-java-agent/instrumentation/spring-scheduling/src/test/groovy/SpringSchedulingTest.groovy new file mode 100644 index 0000000000..2072562a32 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling/src/test/groovy/SpringSchedulingTest.groovy @@ -0,0 +1,60 @@ +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.instrumentation.api.Tags +import org.springframework.context.annotation.AnnotationConfigApplicationContext + +class SpringSchedulingTest extends AgentTestRunner { + + def "schedule interval test"() { + setup: + def context = new AnnotationConfigApplicationContext(IntervalTaskConfig) + def task = context.getBean(IntervalTask) + + TEST_WRITER.clear() + + task.blockUntilExecute(); + + expect: + assert task != null; + assertTraces(1) { + trace(0, 1) { + span(0) { + resourceName "IntervalTask.run" + operationName "scheduled.call" + parent() + errored false + tags { + "$Tags.COMPONENT" "spring-scheduling" + defaultTags() + } + } + } + } + } + + def "schedule trigger test according to cron expression"() { + setup: + def context = new AnnotationConfigApplicationContext(TriggerTaskConfig) + def task = context.getBean(TriggerTask) + + TEST_WRITER.clear() + + task.blockUntilExecute(); + + expect: + assert task != null; + assertTraces(1) { + trace(0, 1) { + span(0) { + resourceName "TriggerTask.run" + operationName "scheduled.call" + parent() + errored false + tags { + "$Tags.COMPONENT" "spring-scheduling" + defaultTags() + } + } + } + } + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/test/java/IntervalTask.java b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/IntervalTask.java new file mode 100644 index 0000000000..ce3e4494d9 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/IntervalTask.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// import datadog.trace.api.DDTags; +// import datadog.trace.instrumentation.api.AgentScope; +// import datadog.trace.instrumentation.api.AgentSpan; + +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +@Component +public class IntervalTask implements Runnable { + + private final CountDownLatch latch = new CountDownLatch(1); + + @Scheduled(initialDelay = 2, fixedRate = 5000) + @Override + public void run() { + latch.countDown(); + } + + public void blockUntilExecute() throws InterruptedException { + latch.await(5, TimeUnit.SECONDS); + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/test/java/IntervalTaskConfig.java b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/IntervalTaskConfig.java new file mode 100644 index 0000000000..58309a70ba --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/IntervalTaskConfig.java @@ -0,0 +1,12 @@ +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class IntervalTaskConfig { + @Bean + public IntervalTask scheduledTasks() { + return new IntervalTask(); + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/test/java/ScheduledTasks.java b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/ScheduledTasks.java deleted file mode 100644 index 8e14e7944e..0000000000 --- a/dd-java-agent/instrumentation/spring-scheduling/src/test/java/ScheduledTasks.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2012-2015 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import datadog.trace.api.DDTags; -import datadog.trace.instrumentation.api.AgentScope; -import datadog.trace.instrumentation.api.AgentSpan; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -import java.text.SimpleDateFormat; - -import static datadog.trace.instrumentation.api.AgentTracer.activateSpan; -import static datadog.trace.instrumentation.api.AgentTracer.activeSpan; -import static datadog.trace.instrumentation.api.AgentTracer.startSpan; -import static datadog.trace.instrumentation.trace_annotation.TraceDecorator.DECORATE; - -@Component -public class ScheduledTasks { - - private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class); - - private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); - - public static boolean reportCurrentTimeExecuted = false; - - @Scheduled(fixedRate = 5000) - // @Trace - public void reportCurrentTime() { - // log.info("The time is now {}", dateFormat.format(new Date())); - // test that the body of method has been executed - // create span - - // activeSpan().setTag(DDTags.SERVICE_NAME, "test"); - reportCurrentTimeExecuted = true; - } - - public void runSpan() { - // create span - final AgentSpan span = startSpan("currentTime"); - DECORATE.afterStart(span); - - try (final AgentScope scope = activateSpan(span, false)) { - activeSpan().setTag(DDTags.SERVICE_NAME, "test"); - DECORATE.afterStart(span); - scope.setAsyncPropagation(true); - - try { - reportCurrentTime(); - } catch (final Throwable throwable) { - DECORATE.onError(span, throwable); - DECORATE.beforeFinish(span); - span.finish(); - throw throwable; - } - } - } -} diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/test/java/ScheduledTasksConfig.java b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/ScheduledTasksConfig.java deleted file mode 100644 index ade9c46d26..0000000000 --- a/dd-java-agent/instrumentation/spring-scheduling/src/test/java/ScheduledTasksConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class ScheduledTasksConfig { - @Bean - public ScheduledTasks scheduledTasks() { - return new ScheduledTasks(); - } -} diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/test/java/TriggerTask.java b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/TriggerTask.java new file mode 100644 index 0000000000..a9bd96c645 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/TriggerTask.java @@ -0,0 +1,44 @@ +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/* + * Copyright 2012-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// import datadog.trace.api.DDTags; +// import datadog.trace.instrumentation.api.AgentScope; +// import datadog.trace.instrumentation.api.AgentSpan; + +@Component +public class TriggerTask implements Runnable { + + public TriggerTask() { + System.out.println("in the ScheduledTasks constructor"); + } + + private final CountDownLatch latch = new CountDownLatch(1); + + @Scheduled(cron = "0/5 * * * * *") + @Override + public void run() { + latch.countDown(); + } + + public void blockUntilExecute() throws InterruptedException { + latch.await(5, TimeUnit.SECONDS); + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling/src/test/java/TriggerTaskConfig.java b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/TriggerTaskConfig.java new file mode 100644 index 0000000000..e032d082d3 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling/src/test/java/TriggerTaskConfig.java @@ -0,0 +1,12 @@ +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class TriggerTaskConfig { + @Bean + public TriggerTask triggerTasks() { + return new TriggerTask(); + } +}