/** * Copyright 2017-2019 The OpenTracing 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 * * http://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. */ package io.opentracing.contrib.spring.cloud.async.instrument; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import io.opentracing.Tracer; import io.opentracing.contrib.concurrent.TracedCallable; import io.opentracing.contrib.concurrent.TracedRunnable; import io.opentracing.contrib.spring.cloud.async.TracedExecutorTest; import java.lang.reflect.Field; import java.time.Duration; import java.time.Instant; import java.util.Date; import java.util.concurrent.Callable; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.util.ErrorHandler; import org.springframework.util.ReflectionUtils; /** * Unit tests all API surface area for TracedThreadPoolTaskScheduler. There is value in integration testing these * via {@code SpringBootTest} but due to the amount of methods we rely on unit tests as a whole and then run a * couple of the methods through integration tests in {@link TracedThreadPoolTaskSchedulerIntegrationTest}. The * thinking is that the plumping that makes it all work is the wrapping in TracedRunnable/TracedCallable so * long as we verify that in unit tests all should be good. * * @author cbono */ public class TracedThreadPoolTaskSchedulerTest { private static final Field TRACED_RUNNABLE_DELEGATE_FIELD = ReflectionUtils.findField(TracedRunnable.class, "delegate"); private static final Field TRACED_RUNNABLE_TRACER_FIELD = ReflectionUtils.findField(TracedRunnable.class, "tracer"); private static final Field TRACED_CALLABLE_DELEGATE_FIELD = ReflectionUtils.findField(TracedCallable.class, "delegate"); private static final Field TRACED_CALLABLE_TRACER_FIELD = ReflectionUtils.findField(TracedCallable.class, "tracer"); static { ReflectionUtils.makeAccessible(TRACED_RUNNABLE_DELEGATE_FIELD); ReflectionUtils.makeAccessible(TRACED_RUNNABLE_TRACER_FIELD); ReflectionUtils.makeAccessible(TRACED_CALLABLE_DELEGATE_FIELD); ReflectionUtils.makeAccessible(TRACED_CALLABLE_TRACER_FIELD); } private final Runnable mockRunnable = mock(Runnable.class); private final Callable mockCallable = mock(Callable.class); private final Tracer mockTracer = mock(Tracer.class); private final ThreadPoolTaskScheduler delegate = mock(ThreadPoolTaskScheduler.class); private final TracedThreadPoolTaskScheduler scheduler = new TracedThreadPoolTaskScheduler( mockTracer, delegate); @Test public void setPoolSize() { scheduler.setPoolSize(10); verify(delegate).setPoolSize(10); } @Test public void setRemoveOnCancelPolicy() { scheduler.setRemoveOnCancelPolicy(true); verify(delegate).setRemoveOnCancelPolicy(true); } @Test public void setErrorHandler() { final ErrorHandler errorHandler = mock(ErrorHandler.class); scheduler.setErrorHandler(errorHandler); verify(delegate).setErrorHandler(errorHandler); } @Test public void getScheduledExecutor() { scheduler.getScheduledExecutor(); verify(delegate).getScheduledExecutor(); } @Test public void getScheduledThreadPoolExecutor() { scheduler.getScheduledThreadPoolExecutor(); verify(delegate).getScheduledThreadPoolExecutor(); } @Test public void getPoolSize() { scheduler.getPoolSize(); verify(delegate).getPoolSize(); } @Test public void isRemoveOnCancelPolicy() { scheduler.isRemoveOnCancelPolicy(); verify(delegate).isRemoveOnCancelPolicy(); } @Test public void getActiveCount() { scheduler.getActiveCount(); verify(delegate).getActiveCount(); } @Test public void execute() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); scheduler.execute(mockRunnable); verify(delegate).execute(argumentCaptor.capture()); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void executeWithTimeout() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); scheduler.execute(mockRunnable, 1000L); verify(delegate).execute(argumentCaptor.capture(), eq(1000L)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void submitRunnable() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); scheduler.submit(mockRunnable); verify(delegate).submit(argumentCaptor.capture()); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void submitCallable() { final ArgumentCaptor<TracedCallable> argumentCaptor = ArgumentCaptor.forClass(TracedCallable.class); scheduler.submit(mockCallable); verify(delegate).submit(argumentCaptor.capture()); verifyTracedCallable(argumentCaptor.getValue(), mockCallable, mockTracer); } @Test public void submitListenableRunnable() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); scheduler.submitListenable(mockRunnable); verify(delegate).submitListenable(argumentCaptor.capture()); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void submitListenableCallable() { final ArgumentCaptor<TracedCallable> argumentCaptor = ArgumentCaptor.forClass(TracedCallable.class); scheduler.submitListenable(mockCallable); verify(delegate).submitListenable(argumentCaptor.capture()); verifyTracedCallable(argumentCaptor.getValue(), mockCallable, mockTracer); } @Test public void scheduleWithTrigger() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); final Trigger trigger = mock(Trigger.class); scheduler.schedule(mockRunnable, trigger); verify(delegate).schedule(argumentCaptor.capture(), eq(trigger)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleWithDate() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); final Date date = mock(Date.class); scheduler.schedule(mockRunnable, date); verify(delegate).schedule(argumentCaptor.capture(), eq(date)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleWithInstant() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); final Instant instant = Instant.now(); scheduler.schedule(mockRunnable, instant); verify(delegate).schedule(argumentCaptor.capture(), eq(instant)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleAtFixedRateWithDateAndLong() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); final Date date = new Date(); scheduler.scheduleAtFixedRate(mockRunnable, date, 1000L); verify(delegate).scheduleAtFixedRate(argumentCaptor.capture(), eq(date), eq(1000L)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleAtFixedRateWithInstantAndDuration() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); final Instant instant = Instant.now(); final Duration duration = Duration.ofMinutes(1); scheduler.scheduleAtFixedRate(mockRunnable, instant, duration); verify(delegate).scheduleAtFixedRate(argumentCaptor.capture(), eq(instant), eq(duration)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleAtFixedRateWithLong() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); scheduler.scheduleAtFixedRate(mockRunnable, 1000L); verify(delegate).scheduleAtFixedRate(argumentCaptor.capture(), eq(1000L)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleAtFixedRateWithDuration() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); final Duration duration = Duration.ofMinutes(5); scheduler.scheduleAtFixedRate(mockRunnable, duration); verify(delegate).scheduleAtFixedRate(argumentCaptor.capture(), eq(duration)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleWithFixedDelayWithDateAndLong() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); final Date date = new Date(); scheduler.scheduleWithFixedDelay(mockRunnable, date, 1000L); verify(delegate).scheduleWithFixedDelay(argumentCaptor.capture(), eq(date), eq(1000L)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleWithFixedDelayWithLong() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); scheduler.scheduleWithFixedDelay(mockRunnable, 1000L); verify(delegate).scheduleWithFixedDelay(argumentCaptor.capture(), eq(1000L)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleWithFixedDelayWithInstantAndDuration() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); final Instant instant = Instant.now(); final Duration duration = Duration.ofMinutes(1); scheduler.scheduleWithFixedDelay(mockRunnable, instant, duration); verify(delegate).scheduleWithFixedDelay(argumentCaptor.capture(), eq(instant), eq(duration)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } @Test public void scheduleWithFixedDelayWithDuration() { final ArgumentCaptor<TracedRunnable> argumentCaptor = ArgumentCaptor.forClass(TracedRunnable.class); final Duration duration = Duration.ofMinutes(5); scheduler.scheduleWithFixedDelay(mockRunnable, duration); verify(delegate).scheduleWithFixedDelay(argumentCaptor.capture(), eq(duration)); verifyTracedRunnable(argumentCaptor.getValue(), mockRunnable, mockTracer); } private void verifyTracedRunnable(final TracedRunnable tracedRunnable, final Runnable task, final Tracer tracer) { final Runnable actualTask = (Runnable) ReflectionUtils.getField(TRACED_RUNNABLE_DELEGATE_FIELD, tracedRunnable); final Tracer actualTracer = (Tracer) ReflectionUtils.getField(TRACED_RUNNABLE_TRACER_FIELD, tracedRunnable); assertThat(actualTask).isEqualTo(task); assertThat(actualTracer).isEqualTo(tracer); } private void verifyTracedCallable(final TracedCallable tracedCallable, final Callable task, final Tracer tracer) { final Callable actualTask = (Callable) ReflectionUtils.getField(TRACED_CALLABLE_DELEGATE_FIELD, tracedCallable); final Tracer actualTracer = (Tracer) ReflectionUtils.getField(TRACED_CALLABLE_TRACER_FIELD, tracedCallable); assertThat(actualTask).isEqualTo(task); assertThat(actualTracer).isEqualTo(tracer); } @Test public void setThreadFactory() { final ThreadFactory threadFactory = mock(ThreadFactory.class); scheduler.setThreadFactory(threadFactory); verify(delegate).setThreadFactory(threadFactory); } @Test public void setThreadNamePrefix() { final String threadNamePrefix = "c137"; scheduler.setThreadNamePrefix(threadNamePrefix); verify(delegate).setThreadNamePrefix(threadNamePrefix); } @Test public void setRejectedExecutionHandler() { final RejectedExecutionHandler rejectedExecutionHandler = mock(RejectedExecutionHandler.class); scheduler.setRejectedExecutionHandler(rejectedExecutionHandler); verify(delegate).setRejectedExecutionHandler(rejectedExecutionHandler); } @Test public void setWaitForTasksToCompleteOnShutdown() { scheduler.setWaitForTasksToCompleteOnShutdown(true); verify(delegate).setWaitForTasksToCompleteOnShutdown(true); } @Test public void setAwaitTerminationSeconds() { scheduler.setAwaitTerminationSeconds(5); verify(delegate).setAwaitTerminationSeconds(5); } @Test public void setBeanName() { final String name = "gazorp"; scheduler.setBeanName(name); verify(delegate).setBeanName(name); } @Test public void afterPropertiesSet() { scheduler.afterPropertiesSet(); verify(delegate).afterPropertiesSet(); } @Test public void initialize() { scheduler.initialize(); verify(delegate).initialize(); } @Test public void destroy() { scheduler.destroy(); verify(delegate).destroy(); } @Test public void shutdown() { scheduler.shutdown(); verify(delegate).shutdown(); } @Test public void newThread() { final Runnable runnable = mock(Runnable.class); scheduler.newThread(runnable); verify(delegate).newThread(runnable); } @Test public void getThreadNamePrefix() { scheduler.getThreadNamePrefix(); verify(delegate).getThreadNamePrefix(); } @Test public void setThreadPriority() { final int threadPriority = 5150; scheduler.setThreadPriority(threadPriority); verify(delegate).setThreadPriority(threadPriority); } @Test public void getThreadPriority() { scheduler.getThreadPriority(); verify(delegate).getThreadPriority(); } @Test public void setDaemon() { scheduler.setDaemon(true); verify(delegate).setDaemon(true); } @Test public void isDaemon() { scheduler.isDaemon(); verify(delegate).isDaemon(); } @Test public void setThreadGroupName() { final String name = "crombopulous"; scheduler.setThreadGroupName(name); verify(delegate).setThreadGroupName(name); } @Test public void setThreadGroup() { final ThreadGroup threadGroup = mock(ThreadGroup.class); scheduler.setThreadGroup(threadGroup); verify(delegate).setThreadGroup(threadGroup); } @Test public void getThreadGroup() { scheduler.getThreadGroup(); verify(delegate).getThreadGroup(); } @Test public void createThread() { final Runnable runnable = mock(Runnable.class); scheduler.createThread(runnable); verify(delegate).createThread(runnable); } @Test public void prefersShortLivedTasks() { scheduler.prefersShortLivedTasks(); verify(delegate).prefersShortLivedTasks(); } }