Make TaskExecutor and TaskScheduler tests more robust

This commit is contained in:
Sam Brannen 2020-05-27 15:25:39 +02:00
parent c4ef002392
commit 763f7b9be8
7 changed files with 131 additions and 169 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@ -23,11 +23,13 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.task.AsyncListenableTaskExecutor;
@ -41,24 +43,27 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Sam Brannen
* @since 5.0.5
*/
public abstract class AbstractSchedulingTaskExecutorTests {
abstract class AbstractSchedulingTaskExecutorTests {
static final String THREAD_NAME_PREFIX = "test-";
private AsyncListenableTaskExecutor executor;
protected String testName;
private volatile Object outcome;
@BeforeEach
public void initExecutor() {
executor = buildExecutor();
void setUp(TestInfo testInfo) {
this.testName = testInfo.getTestMethod().get().getName();
this.executor = buildExecutor();
}
protected abstract AsyncListenableTaskExecutor buildExecutor();
@AfterEach
public void shutdownExecutor() throws Exception {
void shutdownExecutor() throws Exception {
if (executor instanceof DisposableBean) {
((DisposableBean) executor).destroy();
}
@ -66,23 +71,28 @@ public abstract class AbstractSchedulingTaskExecutorTests {
@Test
public void executeRunnable() {
TestTask task = new TestTask(1);
void executeRunnable() {
TestTask task = new TestTask(this.testName, 1);
executor.execute(task);
await(task);
assertThreadNamePrefix(task);
}
@Test
public void executeFailingRunnable() {
TestTask task = new TestTask(0);
void executeFailingRunnable() {
TestTask task = new TestTask(this.testName, 0);
executor.execute(task);
// nothing to assert
Awaitility.await()
.dontCatchUncaughtExceptions()
.atMost(1, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> task.exception.get() != null && task.exception.get().getMessage().equals(
"TestTask failure for test 'executeFailingRunnable': expectedRunCount:<0>, actualRunCount:<1>"));
}
@Test
public void submitRunnable() throws Exception {
TestTask task = new TestTask(1);
void submitRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 1);
Future<?> future = executor.submit(task);
Object result = future.get(1000, TimeUnit.MILLISECONDS);
assertThat(result).isNull();
@ -90,8 +100,8 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitFailingRunnable() throws Exception {
TestTask task = new TestTask(0);
void submitFailingRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 0);
Future<?> future = executor.submit(task);
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
future.get(1000, TimeUnit.MILLISECONDS));
@ -99,9 +109,9 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitRunnableWithGetAfterShutdown() throws Exception {
Future<?> future1 = executor.submit(new TestTask(-1));
Future<?> future2 = executor.submit(new TestTask(-1));
void submitRunnableWithGetAfterShutdown() throws Exception {
Future<?> future1 = executor.submit(new TestTask(this.testName, -1));
Future<?> future2 = executor.submit(new TestTask(this.testName, -1));
shutdownExecutor();
assertThatExceptionOfType(CancellationException.class).isThrownBy(() -> {
future1.get(1000, TimeUnit.MILLISECONDS);
@ -110,8 +120,8 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitListenableRunnable() throws Exception {
TestTask task = new TestTask(1);
void submitListenableRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 1);
// Act
ListenableFuture<?> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
@ -125,8 +135,8 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitFailingListenableRunnable() throws Exception {
TestTask task = new TestTask(0);
void submitFailingListenableRunnable() throws Exception {
TestTask task = new TestTask(this.testName, 0);
ListenableFuture<?> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
@ -139,9 +149,9 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitListenableRunnableWithGetAfterShutdown() throws Exception {
ListenableFuture<?> future1 = executor.submitListenable(new TestTask(-1));
ListenableFuture<?> future2 = executor.submitListenable(new TestTask(-1));
void submitListenableRunnableWithGetAfterShutdown() throws Exception {
ListenableFuture<?> future1 = executor.submitListenable(new TestTask(this.testName, -1));
ListenableFuture<?> future2 = executor.submitListenable(new TestTask(this.testName, -1));
shutdownExecutor();
try {
@ -159,16 +169,16 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitCallable() throws Exception {
TestCallable task = new TestCallable(1);
void submitCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 1);
Future<String> future = executor.submit(task);
String result = future.get(1000, TimeUnit.MILLISECONDS);
assertThat(result.substring(0, THREAD_NAME_PREFIX.length())).isEqualTo(THREAD_NAME_PREFIX);
}
@Test
public void submitFailingCallable() throws Exception {
TestCallable task = new TestCallable(0);
void submitFailingCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 0);
Future<String> future = executor.submit(task);
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
future.get(1000, TimeUnit.MILLISECONDS));
@ -176,9 +186,9 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitCallableWithGetAfterShutdown() throws Exception {
Future<?> future1 = executor.submit(new TestCallable(-1));
Future<?> future2 = executor.submit(new TestCallable(-1));
void submitCallableWithGetAfterShutdown() throws Exception {
Future<?> future1 = executor.submit(new TestCallable(this.testName, -1));
Future<?> future2 = executor.submit(new TestCallable(this.testName, -1));
shutdownExecutor();
try {
@ -196,8 +206,8 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitListenableCallable() throws Exception {
TestCallable task = new TestCallable(1);
void submitListenableCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 1);
// Act
ListenableFuture<String> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
@ -210,8 +220,8 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitFailingListenableCallable() throws Exception {
TestCallable task = new TestCallable(0);
void submitFailingListenableCallable() throws Exception {
TestCallable task = new TestCallable(this.testName, 0);
// Act
ListenableFuture<String> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
@ -225,9 +235,9 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
@Test
public void submitListenableCallableWithGetAfterShutdown() throws Exception {
ListenableFuture<?> future1 = executor.submitListenable(new TestCallable(-1));
ListenableFuture<?> future2 = executor.submitListenable(new TestCallable(-1));
void submitListenableCallableWithGetAfterShutdown() throws Exception {
ListenableFuture<?> future1 = executor.submitListenable(new TestCallable(this.testName, -1));
ListenableFuture<?> future2 = executor.submitListenable(new TestCallable(this.testName, -1));
shutdownExecutor();
assertThatExceptionOfType(CancellationException.class).isThrownBy(() -> {
future1.get(1000, TimeUnit.MILLISECONDS);
@ -255,17 +265,22 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
private static class TestTask implements Runnable {
static class TestTask implements Runnable {
private final int expectedRunCount;
private final String testName;
private final AtomicInteger actualRunCount = new AtomicInteger();
private final CountDownLatch latch;
private final AtomicReference<Exception> exception = new AtomicReference<>();
private Thread lastThread;
final CountDownLatch latch;
TestTask(int expectedRunCount) {
Thread lastThread;
TestTask(String testName, int expectedRunCount) {
this.testName = testName;
this.expectedRunCount = expectedRunCount;
this.latch = (expectedRunCount > 0 ? new CountDownLatch(expectedRunCount) : null);
}
@ -280,7 +295,10 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
if (expectedRunCount >= 0) {
if (actualRunCount.incrementAndGet() > expectedRunCount) {
throw new RuntimeException("intentional test failure");
RuntimeException exception = new RuntimeException(String.format("%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
this.exception.set(exception);
throw exception;
}
latch.countDown();
}
@ -288,13 +306,16 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
private static class TestCallable implements Callable<String> {
static class TestCallable implements Callable<String> {
private final String testName;
private final int expectedRunCount;
private final AtomicInteger actualRunCount = new AtomicInteger();
TestCallable(int expectedRunCount) {
TestCallable(String testName, int expectedRunCount) {
this.testName = testName;
this.expectedRunCount = expectedRunCount;
}
@ -307,7 +328,8 @@ public abstract class AbstractSchedulingTaskExecutorTests {
}
if (expectedRunCount >= 0) {
if (actualRunCount.incrementAndGet() > expectedRunCount) {
throw new RuntimeException("intentional test failure");
throw new RuntimeException(String.format("%s failure for test '%s': expectedRunCount:<%d>, actualRunCount:<%d>",
getClass().getSimpleName(), this.testName, expectedRunCount, actualRunCount.get()));
}
}
return Thread.currentThread().getName();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@ -16,7 +16,6 @@
package org.springframework.scheduling.concurrent;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.ThreadPoolExecutor;
@ -28,11 +27,13 @@ import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.NoOpRunnable;
import static org.assertj.core.api.Assertions.assertThatCode;
/**
* @author Rick Evans
* @author Juergen Hoeller
*/
public class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
private final ThreadPoolExecutor concurrentExecutor =
new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
@ -46,9 +47,8 @@ public class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorT
@Override
@AfterEach
public void shutdownExecutor() {
List<Runnable> remainingTasks = concurrentExecutor.shutdownNow();
for (Runnable task : remainingTasks) {
void shutdownExecutor() {
for (Runnable task : concurrentExecutor.shutdownNow()) {
if (task instanceof RunnableFuture) {
((RunnableFuture<?>) task).cancel(true);
}
@ -57,25 +57,22 @@ public class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorT
@Test
public void zeroArgCtorResultsInDefaultTaskExecutorBeingUsed() {
void zeroArgCtorResultsInDefaultTaskExecutorBeingUsed() {
ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor();
// must not throw a NullPointerException
executor.execute(new NoOpRunnable());
assertThatCode(() -> executor.execute(new NoOpRunnable())).doesNotThrowAnyException();
}
@Test
public void passingNullExecutorToCtorResultsInDefaultTaskExecutorBeingUsed() {
void passingNullExecutorToCtorResultsInDefaultTaskExecutorBeingUsed() {
ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor(null);
// must not throw a NullPointerException
executor.execute(new NoOpRunnable());
assertThatCode(() -> executor.execute(new NoOpRunnable())).doesNotThrowAnyException();
}
@Test
public void passingNullExecutorToSetterResultsInDefaultTaskExecutorBeingUsed() {
void passingNullExecutorToSetterResultsInDefaultTaskExecutorBeingUsed() {
ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor();
executor.setConcurrentExecutor(null);
// must not throw a NullPointerException
executor.execute(new NoOpRunnable());
assertThatCode(() -> executor.execute(new NoOpRunnable())).doesNotThrowAnyException();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@ -24,7 +24,7 @@ import org.springframework.scheduling.support.TaskUtils;
* @author Juergen Hoeller
* @since 5.0.5
*/
public class DecoratedThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
class DecoratedThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
@Override
protected AsyncListenableTaskExecutor buildExecutor() {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@ -38,17 +38,17 @@ import static org.springframework.core.testfixture.TestGroup.PERFORMANCE;
* @author Rick Evans
* @author Juergen Hoeller
*/
public class ScheduledExecutorFactoryBeanTests {
class ScheduledExecutorFactoryBeanTests {
@Test
public void testThrowsExceptionIfPoolSizeIsLessThanZero() throws Exception {
void throwsExceptionIfPoolSizeIsLessThanZero() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
assertThatIllegalArgumentException().isThrownBy(() -> factory.setPoolSize(-1));
}
@Test
@SuppressWarnings("serial")
public void testShutdownNowIsPropagatedToTheExecutorOnDestroy() throws Exception {
void shutdownNowIsPropagatedToTheExecutorOnDestroy() throws Exception {
final ScheduledExecutorService executor = mock(ScheduledExecutorService.class);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@ -57,9 +57,7 @@ public class ScheduledExecutorFactoryBeanTests {
return executor;
}
};
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new NoOpScheduledExecutorTask()
});
factory.setScheduledExecutorTasks(new NoOpScheduledExecutorTask());
factory.afterPropertiesSet();
factory.destroy();
@ -68,7 +66,7 @@ public class ScheduledExecutorFactoryBeanTests {
@Test
@SuppressWarnings("serial")
public void testShutdownIsPropagatedToTheExecutorOnDestroy() throws Exception {
void shutdownIsPropagatedToTheExecutorOnDestroy() throws Exception {
final ScheduledExecutorService executor = mock(ScheduledExecutorService.class);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@ -77,9 +75,7 @@ public class ScheduledExecutorFactoryBeanTests {
return executor;
}
};
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new NoOpScheduledExecutorTask()
});
factory.setScheduledExecutorTasks(new NoOpScheduledExecutorTask());
factory.setWaitForTasksToCompleteOnShutdown(true);
factory.afterPropertiesSet();
factory.destroy();
@ -89,13 +85,11 @@ public class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(PERFORMANCE)
public void testOneTimeExecutionIsSetUpAndFiresCorrectly() throws Exception {
void oneTimeExecutionIsSetUpAndFiresCorrectly() throws Exception {
Runnable runnable = mock(Runnable.class);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new ScheduledExecutorTask(runnable)
});
factory.setScheduledExecutorTasks(new ScheduledExecutorTask(runnable));
factory.afterPropertiesSet();
pauseToLetTaskStart(1);
factory.destroy();
@ -105,7 +99,7 @@ public class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(PERFORMANCE)
public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
void fixedRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
Runnable runnable = mock(Runnable.class);
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
@ -113,7 +107,7 @@ public class ScheduledExecutorFactoryBeanTests {
task.setFixedRate(true);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task});
factory.setScheduledExecutorTasks(task);
factory.afterPropertiesSet();
pauseToLetTaskStart(2);
factory.destroy();
@ -123,7 +117,7 @@ public class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(PERFORMANCE)
public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
void fixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
Runnable runnable = mock(Runnable.class);
willThrow(new IllegalStateException()).given(runnable).run();
@ -132,7 +126,7 @@ public class ScheduledExecutorFactoryBeanTests {
task.setFixedRate(true);
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task});
factory.setScheduledExecutorTasks(task);
factory.setContinueScheduledExecutionAfterException(true);
factory.afterPropertiesSet();
pauseToLetTaskStart(2);
@ -143,7 +137,7 @@ public class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(PERFORMANCE)
public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception {
Runnable runnable = mock(Runnable.class);
ScheduledExecutorTask task = new ScheduledExecutorTask(runnable);
@ -151,7 +145,7 @@ public class ScheduledExecutorFactoryBeanTests {
task.setDelay(3000); // nice long wait...
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task});
factory.setScheduledExecutorTasks(task);
factory.afterPropertiesSet();
pauseToLetTaskStart(1);
// invoke destroy before tasks have even been scheduled...
@ -163,7 +157,7 @@ public class ScheduledExecutorFactoryBeanTests {
@Test
@EnabledForTestGroups(PERFORMANCE)
public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
void withInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception {
Runnable runnable = mock(Runnable.class);
willThrow(new IllegalStateException()).given(runnable).run();
@ -172,7 +166,7 @@ public class ScheduledExecutorFactoryBeanTests {
task.setDelay(3000); // nice long wait...
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task});
factory.setScheduledExecutorTasks(task);
factory.setContinueScheduledExecutionAfterException(true);
factory.afterPropertiesSet();
pauseToLetTaskStart(1);
@ -185,7 +179,7 @@ public class ScheduledExecutorFactoryBeanTests {
@Test
@SuppressWarnings("serial")
public void testSettingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
void settingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@Override
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
@ -193,9 +187,7 @@ public class ScheduledExecutorFactoryBeanTests {
return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler);
}
};
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new NoOpScheduledExecutorTask()
});
factory.setScheduledExecutorTasks(new NoOpScheduledExecutorTask());
factory.setThreadFactory(null); // the null must not propagate
factory.afterPropertiesSet();
factory.destroy();
@ -203,7 +195,7 @@ public class ScheduledExecutorFactoryBeanTests {
@Test
@SuppressWarnings("serial")
public void testSettingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
void settingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() {
@Override
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
@ -211,16 +203,14 @@ public class ScheduledExecutorFactoryBeanTests {
return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler);
}
};
factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{
new NoOpScheduledExecutorTask()
});
factory.setScheduledExecutorTasks(new NoOpScheduledExecutorTask());
factory.setRejectedExecutionHandler(null); // the null must not propagate
factory.afterPropertiesSet();
factory.destroy();
}
@Test
public void testObjectTypeReportsCorrectType() throws Exception {
void objectTypeReportsCorrectType() throws Exception {
ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean();
assertThat(factory.getObjectType()).isEqualTo(ScheduledExecutorService.class);
}
@ -237,7 +227,7 @@ public class ScheduledExecutorFactoryBeanTests {
private static class NoOpScheduledExecutorTask extends ScheduledExecutorTask {
public NoOpScheduledExecutorTask() {
NoOpScheduledExecutorTask() {
super(new NoOpRunnable());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@ -31,10 +31,10 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Juergen Hoeller
*/
public class ThreadPoolExecutorFactoryBeanTests {
class ThreadPoolExecutorFactoryBeanTests {
@Test
public void defaultExecutor() throws Exception {
void defaultExecutor() throws Exception {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ExecutorConfig.class);
ExecutorService executor = context.getBean(ExecutorService.class);
@ -46,10 +46,10 @@ public class ThreadPoolExecutorFactoryBeanTests {
@Configuration
public static class ExecutorConfig {
static class ExecutorConfig {
@Bean
public ThreadPoolExecutorFactoryBean executor() {
ThreadPoolExecutorFactoryBean executor() {
return new ThreadPoolExecutorFactoryBean();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2020 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.
@ -22,7 +22,7 @@ import org.springframework.core.task.AsyncListenableTaskExecutor;
* @author Juergen Hoeller
* @since 5.0.5
*/
public class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
@Override
protected AsyncListenableTaskExecutor buildExecutor() {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 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.
@ -17,7 +17,6 @@
package org.springframework.scheduling.concurrent;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@ -37,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Mark Fisher
* @author Juergen Hoeller
* @author Sam Brannen
* @since 3.0
*/
public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests {
@ -53,8 +53,8 @@ public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutor
@Test
public void executeFailingRunnableWithErrorHandler() {
TestTask task = new TestTask(0);
void executeFailingRunnableWithErrorHandler() {
TestTask task = new TestTask(this.testName, 0);
TestErrorHandler errorHandler = new TestErrorHandler(1);
scheduler.setErrorHandler(errorHandler);
scheduler.execute(task);
@ -63,8 +63,8 @@ public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutor
}
@Test
public void submitFailingRunnableWithErrorHandler() throws Exception {
TestTask task = new TestTask(0);
void submitFailingRunnableWithErrorHandler() throws Exception {
TestTask task = new TestTask(this.testName, 0);
TestErrorHandler errorHandler = new TestErrorHandler(1);
scheduler.setErrorHandler(errorHandler);
Future<?> future = scheduler.submit(task);
@ -75,8 +75,8 @@ public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutor
}
@Test
public void submitFailingCallableWithErrorHandler() throws Exception {
TestCallable task = new TestCallable(0);
void submitFailingCallableWithErrorHandler() throws Exception {
TestCallable task = new TestCallable(this.testName, 0);
TestErrorHandler errorHandler = new TestErrorHandler(1);
scheduler.setErrorHandler(errorHandler);
Future<String> future = scheduler.submit(task);
@ -87,8 +87,8 @@ public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutor
}
@Test
public void scheduleOneTimeTask() throws Exception {
TestTask task = new TestTask(1);
void scheduleOneTimeTask() throws Exception {
TestTask task = new TestTask(this.testName, 1);
Future<?> future = scheduler.schedule(task, new Date());
Object result = future.get(1000, TimeUnit.MILLISECONDS);
assertThat(result).isNull();
@ -97,17 +97,16 @@ public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutor
}
@Test
public void scheduleOneTimeFailingTaskWithoutErrorHandler() throws Exception {
TestTask task = new TestTask(0);
void scheduleOneTimeFailingTaskWithoutErrorHandler() throws Exception {
TestTask task = new TestTask(this.testName, 0);
Future<?> future = scheduler.schedule(task, new Date());
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
future.get(1000, TimeUnit.MILLISECONDS));
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() -> future.get(1000, TimeUnit.MILLISECONDS));
assertThat(future.isDone()).isTrue();
}
@Test
public void scheduleOneTimeFailingTaskWithErrorHandler() throws Exception {
TestTask task = new TestTask(0);
void scheduleOneTimeFailingTaskWithErrorHandler() throws Exception {
TestTask task = new TestTask(this.testName, 0);
TestErrorHandler errorHandler = new TestErrorHandler(1);
scheduler.setErrorHandler(errorHandler);
Future<?> future = scheduler.schedule(task, new Date());
@ -118,8 +117,8 @@ public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutor
}
@Test
public void scheduleTriggerTask() throws Exception {
TestTask task = new TestTask(3);
void scheduleTriggerTask() throws Exception {
TestTask task = new TestTask(this.testName, 3);
Future<?> future = scheduler.schedule(task, new TestTrigger(3));
Object result = future.get(1000, TimeUnit.MILLISECONDS);
assertThat(result).isNull();
@ -128,8 +127,8 @@ public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutor
}
@Test
public void scheduleMultipleTriggerTasks() throws Exception {
for (int i = 0; i < 1000; i++) {
void scheduleMultipleTriggerTasks() throws Exception {
for (int i = 0; i < 100; i++) {
scheduleTriggerTask();
}
}
@ -158,52 +157,6 @@ public class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutor
}
private static class TestTask implements Runnable {
private final int expectedRunCount;
private final AtomicInteger actualRunCount = new AtomicInteger();
private final CountDownLatch latch;
private Thread lastThread;
TestTask(int expectedRunCount) {
this.expectedRunCount = expectedRunCount;
this.latch = new CountDownLatch(expectedRunCount);
}
@Override
public void run() {
lastThread = Thread.currentThread();
if (actualRunCount.incrementAndGet() > expectedRunCount) {
throw new RuntimeException("intentional test failure");
}
latch.countDown();
}
}
private static class TestCallable implements Callable<String> {
private final int expectedRunCount;
private final AtomicInteger actualRunCount = new AtomicInteger();
TestCallable(int expectedRunCount) {
this.expectedRunCount = expectedRunCount;
}
@Override
public String call() throws Exception {
if (actualRunCount.incrementAndGet() > expectedRunCount) {
throw new RuntimeException("intentional test failure");
}
return Thread.currentThread().getName();
}
}
private static class TestErrorHandler implements ErrorHandler {
private final CountDownLatch latch;