Add execution metadata to tasks and scheduled tasks
This commit adds new information about the execution and scheduling of tasks. The `Task` type now exposes the `TaskExecutionOutcome` of the latest execution; this includes the instant the execution started, the execution outcome and any thrown exception. The `ScheduledTask` contract can now provide the time when the next execution is scheduled. Closes gh-24560
This commit is contained in:
@@ -21,7 +21,6 @@ import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
@@ -32,6 +31,7 @@ import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.assertj.core.api.AbstractAssert;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ParameterContext;
|
||||
@@ -116,11 +116,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("fixedDelayTasks");
|
||||
assertThat(fixedDelayTasks).hasSize(1);
|
||||
IntervalTask task = fixedDelayTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("fixedDelay");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("fixedDelay");
|
||||
assertThat(task.getInitialDelayDuration()).isZero();
|
||||
assertThat(task.getIntervalDuration()).isEqualTo(
|
||||
Duration.ofMillis(expectedInterval < 0 ? Long.MAX_VALUE : expectedInterval));
|
||||
@@ -150,11 +146,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
|
||||
assertThat(fixedRateTasks).hasSize(1);
|
||||
IntervalTask task = fixedRateTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("fixedRate");
|
||||
assertSoftly(softly -> {
|
||||
softly.assertThat(task.getInitialDelayDuration()).as("initial delay").isZero();
|
||||
softly.assertThat(task.getIntervalDuration()).as("interval").isEqualTo(Duration.ofMillis(expectedInterval));
|
||||
@@ -185,11 +177,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
|
||||
assertThat(fixedRateTasks).hasSize(1);
|
||||
IntervalTask task = fixedRateTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("fixedRate");
|
||||
assertSoftly(softly -> {
|
||||
softly.assertThat(task.getInitialDelayDuration()).as("initial delay").isEqualTo(Duration.ofMillis(expectedInitialDelay));
|
||||
softly.assertThat(task.getIntervalDuration()).as("interval").isEqualTo(Duration.ofMillis(expectedInterval));
|
||||
@@ -250,19 +238,11 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
|
||||
assertThat(fixedRateTasks).hasSize(2);
|
||||
IntervalTask task1 = fixedRateTasks.get(0);
|
||||
ScheduledMethodRunnable runnable1 = (ScheduledMethodRunnable) task1.getRunnable();
|
||||
Object targetObject = runnable1.getTarget();
|
||||
Method targetMethod = runnable1.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
|
||||
assertThatScheduledRunnable(task1.getRunnable()).hasTarget(target).hasMethodName("fixedRate");
|
||||
assertThat(task1.getInitialDelayDuration()).isZero();
|
||||
assertThat(task1.getIntervalDuration()).isEqualTo(Duration.ofMillis(4_000L));
|
||||
IntervalTask task2 = fixedRateTasks.get(1);
|
||||
ScheduledMethodRunnable runnable2 = (ScheduledMethodRunnable) task2.getRunnable();
|
||||
targetObject = runnable2.getTarget();
|
||||
targetMethod = runnable2.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
|
||||
assertThatScheduledRunnable(task2.getRunnable()).hasTarget(target).hasMethodName("fixedRate");
|
||||
assertThat(task2.getInitialDelayDuration()).isEqualTo(Duration.ofMillis(2_000L));
|
||||
assertThat(task2.getIntervalDuration()).isEqualTo(Duration.ofMillis(4_000L));
|
||||
}
|
||||
@@ -286,11 +266,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("oneTimeTasks");
|
||||
assertThat(oneTimeTasks).hasSize(1);
|
||||
OneTimeTask task = oneTimeTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("oneTimeTask");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("oneTimeTask");
|
||||
assertThat(task.getInitialDelayDuration()).isEqualTo(Duration.ofMillis(2_000L));
|
||||
}
|
||||
|
||||
@@ -313,11 +289,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("cronTasks");
|
||||
assertThat(cronTasks).hasSize(1);
|
||||
CronTask task = cronTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("cron");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("cron");
|
||||
assertThat(task.getExpression()).isEqualTo("*/7 * * * * ?");
|
||||
}
|
||||
|
||||
@@ -340,11 +312,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("cronTasks");
|
||||
assertThat(cronTasks).hasSize(1);
|
||||
CronTask task = cronTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("cron");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("cron");
|
||||
assertThat(task.getExpression()).isEqualTo("0 0 0-4,6-23 * * ?");
|
||||
Trigger trigger = task.getTrigger();
|
||||
assertThat(trigger).isNotNull();
|
||||
@@ -404,11 +372,9 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("cronTasks");
|
||||
assertThat(cronTasks).hasSize(1);
|
||||
CronTask task = cronTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(context.getBean(ScopedProxyUtils.getTargetBeanName("target")));
|
||||
assertThat(targetMethod.getName()).isEqualTo("cron");
|
||||
assertThatScheduledRunnable(task.getRunnable())
|
||||
.hasTarget(context.getBean(ScopedProxyUtils.getTargetBeanName("target")))
|
||||
.hasMethodName("cron");
|
||||
assertThat(task.getExpression()).isEqualTo("*/7 * * * * ?");
|
||||
}
|
||||
|
||||
@@ -431,11 +397,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
|
||||
assertThat(fixedRateTasks).hasSize(1);
|
||||
IntervalTask task = fixedRateTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("checkForUpdates");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("checkForUpdates");
|
||||
assertThat(task.getIntervalDuration()).isEqualTo(Duration.ofMillis(5_000L));
|
||||
}
|
||||
|
||||
@@ -458,11 +420,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
|
||||
assertThat(fixedRateTasks).hasSize(1);
|
||||
IntervalTask task = fixedRateTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("checkForUpdates");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("checkForUpdates");
|
||||
assertThat(task.getIntervalDuration()).isEqualTo(Duration.ofMillis(5_000L));
|
||||
assertThat(task.getInitialDelayDuration()).isEqualTo(Duration.ofMillis(1_000L));
|
||||
}
|
||||
@@ -486,11 +444,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("cronTasks");
|
||||
assertThat(cronTasks).hasSize(1);
|
||||
CronTask task = cronTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("generateReport");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("generateReport");
|
||||
assertThat(task.getExpression()).isEqualTo("0 0 * * * ?");
|
||||
}
|
||||
|
||||
@@ -519,11 +473,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("cronTasks");
|
||||
assertThat(cronTasks).hasSize(1);
|
||||
CronTask task = cronTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("x");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("x");
|
||||
assertThat(task.getExpression()).isEqualTo(businessHoursCronExpression);
|
||||
}
|
||||
|
||||
@@ -578,11 +528,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("fixedDelayTasks");
|
||||
assertThat(fixedDelayTasks).hasSize(1);
|
||||
IntervalTask task = fixedDelayTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("fixedDelay");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("fixedDelay");
|
||||
assertSoftly(softly -> {
|
||||
softly.assertThat(task.getInitialDelayDuration()).as("initial delay").isEqualTo(Duration.ofMillis(expectedInitialDelay));
|
||||
softly.assertThat(task.getIntervalDuration()).as("interval").isEqualTo(Duration.ofMillis(expectedInterval));
|
||||
@@ -622,11 +568,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
|
||||
assertThat(fixedRateTasks).hasSize(1);
|
||||
IntervalTask task = fixedRateTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("fixedRate");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("fixedRate");
|
||||
assertSoftly(softly -> {
|
||||
softly.assertThat(task.getInitialDelayDuration()).as("initial delay").isEqualTo(Duration.ofMillis(expectedInitialDelay));
|
||||
softly.assertThat(task.getIntervalDuration()).as("interval").isEqualTo(Duration.ofMillis(expectedInterval));
|
||||
@@ -656,11 +598,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("cronTasks");
|
||||
assertThat(cronTasks).hasSize(1);
|
||||
CronTask task = cronTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("x");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("x");
|
||||
assertThat(task.getExpression()).isEqualTo(businessHoursCronExpression);
|
||||
}
|
||||
|
||||
@@ -689,11 +627,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("cronTasks");
|
||||
assertThat(cronTasks).hasSize(1);
|
||||
CronTask task = cronTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("y");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("y");
|
||||
assertThat(task.getExpression()).isEqualTo(businessHoursCronExpression);
|
||||
}
|
||||
|
||||
@@ -716,11 +650,7 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
new DirectFieldAccessor(registrar).getPropertyValue("cronTasks");
|
||||
assertThat(cronTasks).hasSize(1);
|
||||
CronTask task = cronTasks.get(0);
|
||||
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||
Object targetObject = runnable.getTarget();
|
||||
Method targetMethod = runnable.getMethod();
|
||||
assertThat(targetObject).isEqualTo(target);
|
||||
assertThat(targetMethod.getName()).isEqualTo("cron");
|
||||
assertThatScheduledRunnable(task.getRunnable()).hasTarget(target).hasMethodName("cron");
|
||||
assertThat(task.getExpression()).isEqualTo("0 0 9-17 * * MON-FRI");
|
||||
}
|
||||
|
||||
@@ -1088,4 +1018,29 @@ class ScheduledAnnotationBeanPostProcessorTests {
|
||||
}
|
||||
}
|
||||
|
||||
static ScheduledMethodRunnableAssert assertThatScheduledRunnable(Runnable runnable) {
|
||||
return new ScheduledMethodRunnableAssert(runnable);
|
||||
}
|
||||
|
||||
static class ScheduledMethodRunnableAssert extends AbstractAssert<ScheduledMethodRunnableAssert, Runnable> {
|
||||
|
||||
public ScheduledMethodRunnableAssert(Runnable actual) {
|
||||
super(actual, ScheduledMethodRunnableAssert.class);
|
||||
assertThat(actual).extracting("runnable").isInstanceOf(ScheduledMethodRunnable.class);
|
||||
}
|
||||
|
||||
public ScheduledMethodRunnableAssert hasTarget(Object target) {
|
||||
isNotNull();
|
||||
assertThat(actual).extracting("runnable.target").isEqualTo(target);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScheduledMethodRunnableAssert hasMethodName(String name) {
|
||||
isNotNull();
|
||||
assertThat(actual).extracting("runnable.method.name").isEqualTo(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.config;
|
||||
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ScheduledTask}.
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class ScheduledTaskTests {
|
||||
|
||||
private CountingRunnable countingRunnable = new CountingRunnable();
|
||||
|
||||
private SimpleAsyncTaskScheduler taskScheduler = new SimpleAsyncTaskScheduler();
|
||||
|
||||
private ScheduledTaskRegistrar taskRegistrar = new ScheduledTaskRegistrar();
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.taskRegistrar.setTaskScheduler(this.taskScheduler);
|
||||
taskScheduler.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
taskScheduler.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnConfiguredTask() {
|
||||
Task task = new Task(countingRunnable);
|
||||
ScheduledTask scheduledTask = new ScheduledTask(task);
|
||||
assertThat(scheduledTask.getTask()).isEqualTo(task);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseTaskToString() {
|
||||
Task task = new Task(countingRunnable);
|
||||
ScheduledTask scheduledTask = new ScheduledTask(task);
|
||||
assertThat(scheduledTask.toString()).isEqualTo(task.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void unscheduledTaskShouldNotHaveNextExecution() {
|
||||
ScheduledTask scheduledTask = new ScheduledTask(new Task(countingRunnable));
|
||||
assertThat(scheduledTask.nextExecution()).isNull();
|
||||
assertThat(countingRunnable.executionCount).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
void scheduledTaskShouldHaveNextExecution() {
|
||||
ScheduledTask scheduledTask = taskRegistrar.scheduleFixedDelayTask(new FixedDelayTask(countingRunnable,
|
||||
Duration.ofSeconds(10), Duration.ofSeconds(10)));
|
||||
assertThat(scheduledTask.nextExecution()).isBefore(Instant.now().plusSeconds(11));
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelledTaskShouldNotHaveNextExecution() {
|
||||
ScheduledTask scheduledTask = taskRegistrar.scheduleFixedDelayTask(new FixedDelayTask(countingRunnable,
|
||||
Duration.ofSeconds(10), Duration.ofSeconds(10)));
|
||||
scheduledTask.cancel(true);
|
||||
assertThat(scheduledTask.nextExecution()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleExecutionShouldNotHaveNextExecution() {
|
||||
ScheduledTask scheduledTask = taskRegistrar.scheduleOneTimeTask(new OneTimeTask(countingRunnable, Duration.ofSeconds(0)));
|
||||
Awaitility.await().atMost(Duration.ofSeconds(5)).until(() -> countingRunnable.executionCount > 0);
|
||||
assertThat(scheduledTask.nextExecution()).isNull();
|
||||
}
|
||||
|
||||
class CountingRunnable implements Runnable {
|
||||
|
||||
int executionCount;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
executionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
package org.springframework.scheduling.config;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.ObjectAssert;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.scheduling.TriggerContext;
|
||||
import org.springframework.scheduling.support.ScheduledMethodRunnable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.type;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -68,11 +69,13 @@ public class ScheduledTasksBeanDefinitionParserTests {
|
||||
List<IntervalTask> tasks = (List<IntervalTask>) new DirectFieldAccessor(
|
||||
this.registrar).getPropertyValue("fixedRateTasks");
|
||||
Runnable runnable = tasks.get(0).getRunnable();
|
||||
assertThat(runnable.getClass()).isEqualTo(ScheduledMethodRunnable.class);
|
||||
Object targetObject = ((ScheduledMethodRunnable) runnable).getTarget();
|
||||
Method targetMethod = ((ScheduledMethodRunnable) runnable).getMethod();
|
||||
assertThat(targetObject).isEqualTo(this.testBean);
|
||||
assertThat(targetMethod.getName()).isEqualTo("test");
|
||||
|
||||
ObjectAssert<ScheduledMethodRunnable> runnableAssert = assertThat(runnable)
|
||||
.extracting("runnable")
|
||||
.isInstanceOf(ScheduledMethodRunnable.class)
|
||||
.asInstanceOf(type(ScheduledMethodRunnable.class));
|
||||
runnableAssert.extracting("target").isEqualTo(testBean);
|
||||
runnableAssert.extracting("method.name").isEqualTo("test");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.config;
|
||||
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link TaskExecutionOutcome}.
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class TaskExecutionOutcomeTests {
|
||||
|
||||
@Test
|
||||
void shouldCreateWithNoneStatus() {
|
||||
TaskExecutionOutcome outcome = TaskExecutionOutcome.create();
|
||||
assertThat(outcome.status()).isEqualTo(TaskExecutionOutcome.Status.NONE);
|
||||
assertThat(outcome.executionTime()).isNull();
|
||||
assertThat(outcome.throwable()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void startedTaskShouldBeOngoing() {
|
||||
TaskExecutionOutcome outcome = TaskExecutionOutcome.create();
|
||||
Instant now = Instant.now();
|
||||
outcome = outcome.start(now);
|
||||
assertThat(outcome.status()).isEqualTo(TaskExecutionOutcome.Status.STARTED);
|
||||
assertThat(outcome.executionTime()).isEqualTo(now);
|
||||
assertThat(outcome.throwable()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectSuccessWhenNotStarted() {
|
||||
TaskExecutionOutcome outcome = TaskExecutionOutcome.create();
|
||||
assertThatIllegalStateException().isThrownBy(outcome::success);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectErrorWhenNotStarted() {
|
||||
TaskExecutionOutcome outcome = TaskExecutionOutcome.create();
|
||||
assertThatIllegalStateException().isThrownBy(() -> outcome.failure(new IllegalArgumentException("test error")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void finishedTaskShouldBeSuccessful() {
|
||||
TaskExecutionOutcome outcome = TaskExecutionOutcome.create();
|
||||
Instant now = Instant.now();
|
||||
outcome = outcome.start(now);
|
||||
outcome = outcome.success();
|
||||
assertThat(outcome.status()).isEqualTo(TaskExecutionOutcome.Status.SUCCESS);
|
||||
assertThat(outcome.executionTime()).isEqualTo(now);
|
||||
assertThat(outcome.throwable()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorTaskShouldBeFailure() {
|
||||
TaskExecutionOutcome outcome = TaskExecutionOutcome.create();
|
||||
Instant now = Instant.now();
|
||||
outcome = outcome.start(now);
|
||||
outcome = outcome.failure(new IllegalArgumentException(("test error")));
|
||||
assertThat(outcome.status()).isEqualTo(TaskExecutionOutcome.Status.ERROR);
|
||||
assertThat(outcome.executionTime()).isEqualTo(now);
|
||||
assertThat(outcome.throwable()).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void newTaskExecutionShouldNotFail() {
|
||||
TaskExecutionOutcome outcome = TaskExecutionOutcome.create();
|
||||
Instant now = Instant.now();
|
||||
outcome = outcome.start(now);
|
||||
outcome = outcome.failure(new IllegalArgumentException(("test error")));
|
||||
|
||||
outcome = outcome.start(now.plusSeconds(2));
|
||||
assertThat(outcome.status()).isEqualTo(TaskExecutionOutcome.Status.STARTED);
|
||||
assertThat(outcome.executionTime()).isAfter(now);
|
||||
assertThat(outcome.throwable()).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
*/
|
||||
|
||||
package org.springframework.scheduling.config;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link Task}.
|
||||
* @author Brian Clozel
|
||||
*/
|
||||
class TaskTests {
|
||||
|
||||
@Test
|
||||
void shouldRejectNullRunnable() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new Task(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void initialStateShouldBeUnknown() {
|
||||
TestRunnable testRunnable = new TestRunnable();
|
||||
Task task = new Task(testRunnable);
|
||||
assertThat(testRunnable.hasRun).isFalse();
|
||||
TaskExecutionOutcome executionOutcome = task.getLastExecutionOutcome();
|
||||
assertThat(executionOutcome.executionTime()).isNull();
|
||||
assertThat(executionOutcome.status()).isEqualTo(TaskExecutionOutcome.Status.NONE);
|
||||
assertThat(executionOutcome.throwable()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void stateShouldUpdateAfterRun() {
|
||||
TestRunnable testRunnable = new TestRunnable();
|
||||
Task task = new Task(testRunnable);
|
||||
task.getRunnable().run();
|
||||
|
||||
assertThat(testRunnable.hasRun).isTrue();
|
||||
TaskExecutionOutcome executionOutcome = task.getLastExecutionOutcome();
|
||||
assertThat(executionOutcome.executionTime()).isInThePast();
|
||||
assertThat(executionOutcome.status()).isEqualTo(TaskExecutionOutcome.Status.SUCCESS);
|
||||
assertThat(executionOutcome.throwable()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void stateShouldUpdateAfterFailingRun() {
|
||||
FailingTestRunnable testRunnable = new FailingTestRunnable();
|
||||
Task task = new Task(testRunnable);
|
||||
assertThatIllegalStateException().isThrownBy(() -> task.getRunnable().run());
|
||||
|
||||
assertThat(testRunnable.hasRun).isTrue();
|
||||
TaskExecutionOutcome executionOutcome = task.getLastExecutionOutcome();
|
||||
assertThat(executionOutcome.executionTime()).isInThePast();
|
||||
assertThat(executionOutcome.status()).isEqualTo(TaskExecutionOutcome.Status.ERROR);
|
||||
assertThat(executionOutcome.throwable()).isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
|
||||
static class TestRunnable implements Runnable {
|
||||
|
||||
boolean hasRun;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.hasRun = true;
|
||||
}
|
||||
}
|
||||
|
||||
static class FailingTestRunnable implements Runnable {
|
||||
|
||||
boolean hasRun;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.hasRun = true;
|
||||
throw new IllegalStateException("test exception");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user