|
24 | 24 | import java.util.concurrent.atomic.AtomicReference;
|
25 | 25 | import java.util.function.Consumer;
|
26 | 26 |
|
| 27 | +import org.assertj.core.api.InstanceOfAssertFactories; |
27 | 28 | import org.junit.jupiter.api.Test;
|
28 | 29 | import org.junit.jupiter.api.condition.EnabledForJreRange;
|
29 | 30 | import org.junit.jupiter.api.condition.JRE;
|
|
46 | 47 | import org.springframework.core.task.SyncTaskExecutor;
|
47 | 48 | import org.springframework.core.task.TaskDecorator;
|
48 | 49 | import org.springframework.core.task.TaskExecutor;
|
| 50 | +import org.springframework.core.task.support.CompositeTaskDecorator; |
49 | 51 | import org.springframework.scheduling.annotation.Async;
|
50 | 52 | import org.springframework.scheduling.annotation.AsyncConfigurer;
|
51 | 53 | import org.springframework.scheduling.annotation.EnableAsync;
|
52 | 54 | import org.springframework.scheduling.annotation.EnableScheduling;
|
53 | 55 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
54 | 56 |
|
55 | 57 | import static org.assertj.core.api.Assertions.assertThat;
|
56 |
| -import static org.mockito.Mockito.mock; |
57 | 58 |
|
58 | 59 | /**
|
59 | 60 | * Tests for {@link TaskExecutionAutoConfiguration}.
|
@@ -127,13 +128,29 @@ void threadPoolTaskExecutorBuilderWhenHasCustomBuilderShouldUseCustomBuilder() {
|
127 | 128 |
|
128 | 129 | @Test
|
129 | 130 | void threadPoolTaskExecutorBuilderShouldUseTaskDecorator() {
|
130 |
| - this.contextRunner.withUserConfiguration(TaskDecoratorConfig.class).run((context) -> { |
| 131 | + this.contextRunner.withBean(TaskDecorator.class, this::createTaskDecorator).run((context) -> { |
131 | 132 | assertThat(context).hasSingleBean(ThreadPoolTaskExecutorBuilder.class);
|
132 | 133 | ThreadPoolTaskExecutor executor = context.getBean(ThreadPoolTaskExecutorBuilder.class).build();
|
133 | 134 | assertThat(executor).extracting("taskDecorator").isSameAs(context.getBean(TaskDecorator.class));
|
134 | 135 | });
|
135 | 136 | }
|
136 | 137 |
|
| 138 | + @Test |
| 139 | + void threadPoolTaskExecutorBuilderShouldUseCompositeTaskDecorator() { |
| 140 | + this.contextRunner.withBean("taskDecorator1", TaskDecorator.class, this::createTaskDecorator) |
| 141 | + .withBean("taskDecorator2", TaskDecorator.class, this::createTaskDecorator) |
| 142 | + .run((context) -> { |
| 143 | + assertThat(context).hasSingleBean(ThreadPoolTaskExecutorBuilder.class); |
| 144 | + ThreadPoolTaskExecutor executor = context.getBean(ThreadPoolTaskExecutorBuilder.class).build(); |
| 145 | + assertThat(executor).extracting("taskDecorator") |
| 146 | + .isInstanceOf(CompositeTaskDecorator.class) |
| 147 | + .extracting("taskDecorators") |
| 148 | + .asInstanceOf(InstanceOfAssertFactories.list(TaskDecorator.class)) |
| 149 | + .containsExactly(context.getBean("taskDecorator1", TaskDecorator.class), |
| 150 | + context.getBean("taskDecorator2", TaskDecorator.class)); |
| 151 | + }); |
| 152 | + } |
| 153 | + |
137 | 154 | @Test
|
138 | 155 | void whenThreadPoolTaskExecutorIsAutoConfiguredThenItIsLazy() {
|
139 | 156 | this.contextRunner.run((context) -> {
|
@@ -184,13 +201,30 @@ void whenVirtualThreadsAreAvailableButNotEnabledThenThreadPoolTaskExecutorIsAuto
|
184 | 201 | @EnabledForJreRange(min = JRE.JAVA_21)
|
185 | 202 | void whenTaskDecoratorIsDefinedThenSimpleAsyncTaskExecutorWithVirtualThreadsUsesIt() {
|
186 | 203 | this.contextRunner.withPropertyValues("spring.threads.virtual.enabled=true")
|
187 |
| - .withUserConfiguration(TaskDecoratorConfig.class) |
| 204 | + .withBean(TaskDecorator.class, this::createTaskDecorator) |
188 | 205 | .run((context) -> {
|
189 | 206 | SimpleAsyncTaskExecutor executor = context.getBean(SimpleAsyncTaskExecutor.class);
|
190 | 207 | assertThat(executor).extracting("taskDecorator").isSameAs(context.getBean(TaskDecorator.class));
|
191 | 208 | });
|
192 | 209 | }
|
193 | 210 |
|
| 211 | + @Test |
| 212 | + @EnabledForJreRange(min = JRE.JAVA_21) |
| 213 | + void whenTaskDecoratorsAreDefinedThenSimpleAsyncTaskExecutorWithVirtualThreadsUsesThem() { |
| 214 | + this.contextRunner.withPropertyValues("spring.threads.virtual.enabled=true") |
| 215 | + .withBean("taskDecorator1", TaskDecorator.class, this::createTaskDecorator) |
| 216 | + .withBean("taskDecorator2", TaskDecorator.class, this::createTaskDecorator) |
| 217 | + .run((context) -> { |
| 218 | + SimpleAsyncTaskExecutor executor = context.getBean(SimpleAsyncTaskExecutor.class); |
| 219 | + assertThat(executor).extracting("taskDecorator") |
| 220 | + .isInstanceOf(CompositeTaskDecorator.class) |
| 221 | + .extracting("taskDecorators") |
| 222 | + .asInstanceOf(InstanceOfAssertFactories.list(TaskDecorator.class)) |
| 223 | + .containsExactly(context.getBean("taskDecorator1", TaskDecorator.class), |
| 224 | + context.getBean("taskDecorator2", TaskDecorator.class)); |
| 225 | + }); |
| 226 | + } |
| 227 | + |
194 | 228 | @Test
|
195 | 229 | void simpleAsyncTaskExecutorBuilderUsesPlatformThreadsByDefault() {
|
196 | 230 | this.contextRunner.run((context) -> {
|
@@ -451,6 +485,10 @@ void shouldNotAliasApplicationTaskExecutorWhenBootstrapExecutorAliasIsDefined()
|
451 | 485 | });
|
452 | 486 | }
|
453 | 487 |
|
| 488 | + private TaskDecorator createTaskDecorator() { |
| 489 | + return (runnable) -> runnable; |
| 490 | + } |
| 491 | + |
454 | 492 | private Executor createCustomAsyncExecutor(String threadNamePrefix) {
|
455 | 493 | SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
|
456 | 494 | executor.setThreadNamePrefix(threadNamePrefix);
|
@@ -501,16 +539,6 @@ ThreadPoolTaskExecutorBuilder customThreadPoolTaskExecutorBuilder() {
|
501 | 539 |
|
502 | 540 | }
|
503 | 541 |
|
504 |
| - @Configuration(proxyBeanMethods = false) |
505 |
| - static class TaskDecoratorConfig { |
506 |
| - |
507 |
| - @Bean |
508 |
| - TaskDecorator mockTaskDecorator() { |
509 |
| - return mock(TaskDecorator.class); |
510 |
| - } |
511 |
| - |
512 |
| - } |
513 |
| - |
514 | 542 | @Configuration(proxyBeanMethods = false)
|
515 | 543 | @EnableAsync
|
516 | 544 | static class AsyncConfiguration {
|
|
0 commit comments