diff --git a/README.adoc b/README.adoc
index bd7f9822..19654571 100644
--- a/README.adoc
+++ b/README.adoc
@@ -20,13 +20,26 @@ $ mvn -s settings.xml clean install
[source,java,indent=2]
----
-@Task("imSampleB")
-public class SampleB implements CommandLineRunner {
+@SpringBootApplication
+@EnableTask
+public class MyApp {
- @Override
- public void run(String... args) {
- System.out.println("hello world");
- }
+ @Bean
+ public MyTask myTask() {
+ return new MyTask();
+ }
+ public static void main(String[] args) {
+ SpringApplication.run(MyApp.class);
+ }
+
+ @Task("HelloWorldTask")
+ public static class MyTask implements CommandLineRunner {
+
+ @Override
+ public void run(String... strings) throws Exception {
+ System.out.println("Hello World");
+ }
+ }
}
----
diff --git a/pom.xml b/pom.xml
index 6455388d..1bdd0c46 100755
--- a/pom.xml
+++ b/pom.xml
@@ -29,4 +29,37 @@
spring-cloud-task-samples
+
+ UTF-8
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.12.4
+
+
+ **/*Tests.java
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.3
+
+ 1.7
+ 1.7
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.10.3
+
+
+
+
diff --git a/spring-cloud-task-core/pom.xml b/spring-cloud-task-core/pom.xml
index 3a5c3455..dd1a6acb 100755
--- a/spring-cloud-task-core/pom.xml
+++ b/spring-cloud-task-core/pom.xml
@@ -25,7 +25,38 @@
org.springframework.boot
- spring-boot-starter-aop
+ spring-boot
+
+
+ org.springframework
+ spring-context
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ org.springframework
+ spring-aop
+
+
+ org.aspectj
+ aspectjweaver
+
+
+ junit
+ junit
+ test
+
+
+ org.springframework
+ spring-test
+ test
+
+
+ org.mockito
+ mockito-core
+ test
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/annotation/EnableTask.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/annotation/EnableTask.java
new file mode 100644
index 00000000..ad871440
--- /dev/null
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/annotation/EnableTask.java
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright 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
+ *
+ * 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 org.springframework.cloud.task.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.cloud.task.configuration.DefaultTaskConfigurer;
+import org.springframework.cloud.task.configuration.SimpleTaskConfiguration;
+import org.springframework.cloud.task.configuration.TaskConfigurer;
+import org.springframework.cloud.task.repository.TaskRepository;
+import org.springframework.context.annotation.Import;
+
+/**
+ *
+ * Enable Spring Task features and provide a base configuration for setting up
+ * {@link Task} objects in an @Configuration class.
+ *
+ *
+ * @Configuration
+ * @EnableTask
+ * public class AppConfig {
+ *
+ * @Bean
+ * public MyCommandLineRunner myCommandLineRunner() {
+ * return new MyCommandLineRunner()
+ * }
+ * }
+ *
+ *
+ * Note that only one of your configuration classes needs to have the @EnableTask
+ * annotation. Once you have an @EnableTask class in your configuration
+ * you will have an instance of {@link TaskConfigurer}. If one is not specified then the
+ * {@link DefaultTaskConfigurer} will be used.
+ * You will also be able to @Autowired some useful stuff into your context:
+ *
+ *
+ *
a {@link TaskRepository} (bean name "taskRepository").
+ *
+ *
+ * @author Glenn Renfro
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Import(SimpleTaskConfiguration.class)
+public @interface EnableTask {
+}
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/annotation/Task.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/annotation/Task.java
index 0437b854..1293b4d2 100644
--- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/annotation/Task.java
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/annotation/Task.java
@@ -23,10 +23,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import org.springframework.cloud.task.configuration.DefaultTaskConfigurer;
-import org.springframework.context.annotation.Import;
-import org.springframework.stereotype.Component;
-
/**
* Annotation that identifies a class as a task. This annotation will serve as the
* main “hook” to activate the various Spring Cloud Task features.
@@ -37,12 +33,11 @@ import org.springframework.stereotype.Component;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
-@Component
-@Import({ DefaultTaskConfigurer.class })
public @interface Task {
/**
* Establishes the name associated with the task. The default is empty.
+ * @return returns name associated with the task or an empty string.
*/
public String value() default "";
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurer.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurer.java
index 05bb8a38..874eb1f5 100644
--- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurer.java
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/DefaultTaskConfigurer.java
@@ -16,28 +16,26 @@
package org.springframework.cloud.task.configuration;
-import org.springframework.cloud.task.repository.support.LoggerTaskRepository;
import org.springframework.cloud.task.repository.TaskRepository;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Scope;
+import org.springframework.cloud.task.repository.support.LoggerTaskRepository;
/**
- * If no TaskConfigurer is present this configuration will be used.
+ * If no {@link TaskConfigurer} is present, then this configuration will be used.
+ * The following defaults will be used:
+ *
+ *
+ *
{@link LoggerTaskRepository} will be the default {@link TaskRepository}.
+ *
+ *
+ *
* @author Glenn Renfro
*/
-@Configuration
-public class DefaultTaskConfigurer {
+public class DefaultTaskConfigurer implements TaskConfigurer{
- @Bean
- @Scope("prototype")
- public TaskHandler taskHandler() {
- return new TaskHandler();
+ public DefaultTaskConfigurer(){
}
-
- @Bean
- public TaskRepository taskRepository() {
+ public TaskRepository getTaskRepository() {
return new LoggerTaskRepository();
}
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java
new file mode 100644
index 00000000..f61d22d9
--- /dev/null
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 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
+ *
+ * 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 org.springframework.cloud.task.configuration;
+
+import java.util.Collection;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.task.repository.TaskRepository;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Scope;
+
+/**
+ * Base {@code Configuration} class providing common structure for enabling and using
+ * Spring Task. Customization is
+ * available by implementing the {@link TaskConfigurer} interface.
+ *
+ * @author Glenn Renfro
+ */
+@Configuration
+public class SimpleTaskConfiguration {
+
+ @Autowired
+ private ApplicationContext context;
+
+ private boolean initialized = false;
+
+ private TaskRepository taskRepository;
+
+ private TaskConfigurer configurer;
+
+ @Bean
+ @Scope("prototype")
+ public TaskHandler taskHandler() {
+ return new TaskHandler();
+ }
+
+ @Bean
+ public TaskRepository taskRepository(){
+ return taskRepository;
+ }
+
+ /**
+ * Sets up the basic components by extracting them from the {@link TaskConfigurer}, defaulting to some
+ * sensible values as long as a unique DataSource is available.
+ */
+ @PostConstruct
+ private void initialize() {
+ if (initialized) {
+ return;
+ }
+ TaskConfigurer configurer = getConfigurer(context.getBeansOfType(TaskConfigurer.class).values());
+ taskRepository = configurer.getTaskRepository();
+ initialized = true;
+ }
+
+ private TaskConfigurer getConfigurer(Collection configurers) {
+ if (this.configurer != null) {
+ return this.configurer;
+ }
+ if (configurers == null || configurers.isEmpty()) {
+ DefaultTaskConfigurer configurer = new DefaultTaskConfigurer();
+ this.configurer = configurer;
+ return configurer;
+ }
+ if (configurers.size() > 1) {
+ throw new IllegalStateException(
+ "To use a custom TaskConfigurer the context must contain precisely one, found "
+ + configurers.size());
+ }
+ this.configurer = configurers.iterator().next();
+ return this.configurer;
+ }
+}
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskConfigurer.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskConfigurer.java
index 3faf4855..b77cb94f 100644
--- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskConfigurer.java
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskConfigurer.java
@@ -31,6 +31,6 @@ public interface TaskConfigurer {
*
* @return A TaskRepository
*/
- public TaskRepository taskRepository();
+ public TaskRepository getTaskRepository();
}
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskHandler.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskHandler.java
index a32a2acd..db4460bf 100644
--- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskHandler.java
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/TaskHandler.java
@@ -26,6 +26,8 @@ import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.cloud.task.annotation.Task;
import org.springframework.cloud.task.repository.TaskExecution;
@@ -33,8 +35,9 @@ import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.context.ApplicationContext;
/**
- * Offers the advice on how to record tasks to the repository for both applicationrunner
- * and commandlinerunner spring boot applications.
+ * Offers the advice on how to record tasks to the repository for both
+ * {@link org.springframework.boot.ApplicationRunner} and
+ * {@link org.springframework.boot.CommandLineRunner} spring boot applications.
*
* @author Glenn Renfro
*/
@@ -54,11 +57,12 @@ public class TaskHandler {
private TaskExecution taskExecution;
/**
- * Looks for any CommandLineRunner.run method with its class annotated with @Task
+ * Looks for any {@link CommandLineRunner}.run method with its class annotated with @Task
* and calls the repository implementation to store the start of the task in the repo
* before the run starts.
*
- * @param joinPoint
+ * @param joinPoint the point where the run method in a {@link CommandLineRunner} or
+ * {@link ApplicationRunner} is executed
*/
@Before("within( @org.springframework.cloud.task.annotation.Task *) && (execution(* org.springframework.boot.CommandLineRunner.run(..)) || execution(* org.springframework.boot.ApplicationRunner.run(..)))")
public void beforeCommandLineRunner(JoinPoint joinPoint) {
@@ -78,11 +82,12 @@ public class TaskHandler {
}
/**
- * Looks for any CommandLineRunner.run method with its class annotated with @Task
+ * Looks for any {@link CommandLineRunner}.run method with its class annotated with @Task
* and calls repository implementation to store the exit of the task in the repo after
* run returns result.
*
- * @param joinPoint
+ * @param joinPoint the point where the run method in a {@link CommandLineRunner} or
+ * {@link ApplicationRunner} is executed
*/
@AfterReturning("within( @org.springframework.cloud.task.annotation.Task *) && (execution(* org.springframework.boot.CommandLineRunner.run(..)) || execution(* org.springframework.boot.ApplicationRunner.run(..)))")
public void afterReturnCommandLineRunner(JoinPoint joinPoint) {
@@ -99,11 +104,12 @@ public class TaskHandler {
}
/**
- * Looks for any CommandLineRunner. run method with its class annotated with @Task
+ * Looks for any {@link CommandLineRunner}.run method with its class annotated with @Task
* and calls the repository implementation to store the exitCode of 1
* for the task in the repo in the case of an exception.
*
- * @param joinPoint
+ * @param joinPoint the point where the run method in a {@link CommandLineRunner} or
+ * {@link ApplicationRunner} is executed
*/
@AfterThrowing("within( @org.springframework.cloud.task.annotation.Task *) && (execution(* org.springframework.boot.CommandLineRunner.run(..)) || execution(* org.springframework.boot.ApplicationRunner.run(..)))")
public void logExceptionCommandLineRunner(JoinPoint joinPoint) {
@@ -112,4 +118,7 @@ public class TaskHandler {
repository.update(taskExecution);
}
+ public TaskExecution getTaskExecution() {
+ return taskExecution;
+ }
}
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskRepository.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskRepository.java
index f416c8eb..75737010 100644
--- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskRepository.java
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/TaskRepository.java
@@ -18,7 +18,7 @@ package org.springframework.cloud.task.repository;
/**
* TaskRepository interface offers methods that create and update task execution
- * information. The interface will support the following methods:
+ * information.
*
* @author Glenn Renfro
*/
diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/LoggerTaskRepository.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/LoggerTaskRepository.java
index c7197681..ef6ba1bc 100644
--- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/LoggerTaskRepository.java
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/support/LoggerTaskRepository.java
@@ -24,6 +24,8 @@ import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.cloud.task.repository.TaskRepository;
/**
+ * {@link TaskRepository} implementation that will log the task execution information.
+ *
* @author Glenn Renfro
*/
public class LoggerTaskRepository implements TaskRepository {
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/LoggerTaskRepositoryTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/LoggerTaskRepositoryTests.java
new file mode 100644
index 00000000..d52505e4
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/LoggerTaskRepositoryTests.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 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
+ *
+ * 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 org.springframework.cloud.task;
+
+import java.util.UUID;
+
+import ch.qos.logback.core.Appender;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.task.repository.TaskExecution;
+import org.springframework.cloud.task.repository.TaskRepository;
+import org.springframework.cloud.task.util.LoggerTestUtils;
+import org.springframework.cloud.task.util.TestDefaultConfiguration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * Verifies that the LoggerRepository has correct prefixes written to logs.
+ * @author Glenn Renfro
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = TestDefaultConfiguration.class)
+public class LoggerTaskRepositoryTests {
+
+ @Autowired
+ private TaskRepository taskRepository;
+
+ private TaskExecution taskExecution;
+
+ private String uuId;
+
+ @Before
+ public void setup(){
+ taskExecution = new TaskExecution();
+ uuId = UUID.randomUUID().toString();
+ taskExecution.setExecutionId(uuId);
+ }
+
+ @Test
+ public void testCreateTaskExecution() {
+ final Appender mockAppender = LoggerTestUtils.getMockAppender();
+ taskRepository.createTaskExecution(taskExecution);
+ LoggerTestUtils.verifyLogEntryExists(mockAppender,
+ "Creating: TaskExecution{executionId='" + uuId);
+ }
+
+ @Test
+ public void testTaskUpdate() {
+ final Appender mockAppender = LoggerTestUtils.getMockAppender();
+ taskRepository.update(taskExecution);
+ LoggerTestUtils.verifyLogEntryExists(mockAppender,
+ "Updating: TaskExecution{executionId='" + uuId);
+ }
+
+}
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java
new file mode 100644
index 00000000..8ad62029
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 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
+ *
+ * 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 org.springframework.cloud.task;
+
+import static junit.framework.TestCase.assertNotNull;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.task.configuration.SimpleTaskConfiguration;
+import org.springframework.cloud.task.repository.support.LoggerTaskRepository;
+import org.springframework.cloud.task.repository.TaskRepository;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * Verifies that the beans created by the SimpleTaskConfiguration.
+ *
+ * @author Glenn Renfro
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = SimpleTaskConfiguration.class)
+public class SimpleTaskConfigurationTests {
+
+ @Autowired
+ private TaskRepository taskRepository;
+
+ @Test
+ public void testRepository() {
+ assertNotNull("testRepository should not be null", taskRepository);
+ assertThat(taskRepository, instanceOf(LoggerTaskRepository.class));
+ }
+}
+
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskHandlerDefaultTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskHandlerDefaultTests.java
new file mode 100644
index 00000000..89025747
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskHandlerDefaultTests.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 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
+ *
+ * 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 org.springframework.cloud.task;
+
+import static org.junit.Assert.assertEquals;
+
+import ch.qos.logback.core.Appender;
+import org.aspectj.lang.JoinPoint;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.task.configuration.TaskHandler;
+import org.springframework.cloud.task.repository.TaskExecution;
+import org.springframework.cloud.task.util.LoggerTestUtils;
+import org.springframework.cloud.task.util.TestDefaultConfiguration;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * Verifies that the TaskHandler Methods record the appropriate log header entries and
+ * result codes.
+ *
+ * @author Glenn Renfro
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = TestDefaultConfiguration.class)
+public class TaskHandlerDefaultTests {
+
+ @Autowired
+ private TaskHandler taskHandler;
+
+ @Autowired
+ private JoinPoint joinPoint;
+
+ @Test
+ public void testTaskException() {
+ taskHandler.beforeCommandLineRunner(joinPoint);
+ final Appender mockAppender = LoggerTestUtils.getMockAppender();
+ taskHandler.logExceptionCommandLineRunner(joinPoint);
+ LoggerTestUtils.verifyLogEntryExists(mockAppender,
+ "Updating: TaskExecution{executionId='" +
+ taskHandler.getTaskExecution().getExecutionId());
+ TaskExecution taskExecution = taskHandler.getTaskExecution();
+ assertEquals("exit code for exception should be 1", taskExecution.getExitCode(),
+ 1);
+ }
+
+ @Test
+ public void testTaskCreate() {
+ final Appender mockAppender = LoggerTestUtils.getMockAppender();
+ taskHandler.beforeCommandLineRunner(joinPoint);
+ LoggerTestUtils.verifyLogEntryExists(mockAppender,
+ "Creating: TaskExecution{executionId='" +
+ taskHandler.getTaskExecution().getExecutionId());
+ assertEquals("Create should report that exit code is zero",
+ 0, taskHandler.getTaskExecution().getExitCode());
+
+ }
+
+ @Test
+ public void testTaskUpdate() {
+ taskHandler.beforeCommandLineRunner(joinPoint);
+ final Appender mockAppender = LoggerTestUtils.getMockAppender();
+ taskHandler.afterReturnCommandLineRunner(joinPoint);
+ LoggerTestUtils.verifyLogEntryExists(mockAppender,
+ "Updating: TaskExecution{executionId='" +
+ taskHandler.getTaskExecution().getExecutionId());
+ assertEquals("Update should report that exit code is zero",
+ 0, taskHandler.getTaskExecution().getExitCode());
+ }
+
+}
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/NoOpTaskExplorerTest.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/NoOpTaskExplorerTests.java
similarity index 97%
rename from spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/NoOpTaskExplorerTest.java
rename to spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/NoOpTaskExplorerTests.java
index c0321931..5d657586 100644
--- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/NoOpTaskExplorerTest.java
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/NoOpTaskExplorerTests.java
@@ -23,7 +23,7 @@ import org.junit.Test;
import org.springframework.cloud.task.repository.TaskExplorer;
-public class NoOpTaskExplorerTest {
+public class NoOpTaskExplorerTests {
private TaskExplorer taskExplorer;
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/LoggerTestUtils.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/LoggerTestUtils.java
new file mode 100644
index 00000000..c77dad11
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/LoggerTestUtils.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 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
+ *
+ * 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 org.springframework.cloud.task.util;
+
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.core.Appender;
+import org.mockito.ArgumentMatcher;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Offers utils to test the log results produced by the code being tested.
+ *
+ * @author Glenn Renfro
+ */
+public class LoggerTestUtils {
+
+ /**
+ * Creates a mock {@link Appender} to be added to the root logger.
+ * @return reference to the mock appender.
+ */
+ public static Appender getMockAppender(){
+ ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
+ final Appender mockAppender = mock(Appender.class);
+ when(mockAppender.getName()).thenReturn("MOCK");
+ root.addAppender(mockAppender);
+ return mockAppender;
+ }
+
+ /**
+ * Verifies that the log sample is contained within the content that was written
+ * to the mock appender.
+ * @param mockAppender The appender that is associated with the test.
+ * @param logSample The string to search for in the log entry.
+ */
+ public static void verifyLogEntryExists(Appender mockAppender, final String logSample){
+ verify(mockAppender).doAppend(argThat(new ArgumentMatcher() {
+ @Override
+ public boolean matches(final Object argument) {
+ return ((LoggingEvent)argument).getFormattedMessage().contains(logSample);
+ }
+ }));
+ }
+}
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TaskBasic.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TaskBasic.java
new file mode 100644
index 00000000..901f5341
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TaskBasic.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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
+ *
+ * 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 org.springframework.cloud.task.util;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.cloud.task.annotation.Task;
+import org.springframework.stereotype.Component;
+
+/**
+ * Basic {@link CommandLineRunner} implementation, with task annotation.
+ * @author Glenn Renfro
+ */
+@Task
+@Component
+public class TaskBasic implements CommandLineRunner{
+
+
+ @Override
+ public void run(String... args) {
+ //noop
+ }
+}
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java
new file mode 100644
index 00000000..82cddd65
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 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
+ *
+ * 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 org.springframework.cloud.task.util;
+
+import org.aspectj.lang.JoinPoint;
+import org.springframework.cloud.task.configuration.TaskHandler;
+import org.springframework.cloud.task.repository.support.LoggerTaskRepository;
+import org.springframework.cloud.task.repository.TaskRepository;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Initializes the beans needed to test default task behavior.
+ *
+ * @author Glenn Renfro
+ */
+@Configuration
+public class TestDefaultConfiguration {
+
+ @Bean
+ public TaskRepository taskRepository(){
+ return new LoggerTaskRepository();
+ }
+
+ @Bean
+ public TaskHandler taskHandler(){
+ return new TaskHandler();
+ }
+
+ @Bean
+ public JoinPoint joinPoint(){
+ return new TestJoinPoint();
+ }
+
+
+}
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestJoinPoint.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestJoinPoint.java
new file mode 100644
index 00000000..676de5d1
--- /dev/null
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestJoinPoint.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 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
+ *
+ * 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 org.springframework.cloud.task.util;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.reflect.SourceLocation;
+
+/**
+ * Stubbed out join point for testing purposes.
+ *
+ * @author Glenn Renfro
+ */
+public class TestJoinPoint implements JoinPoint {
+ public String toShortString() {
+ return null;
+ }
+
+ public String toLongString() {
+ return null;
+ }
+
+ public Object getThis() {
+ return null;
+ }
+
+ public Object getTarget() {
+ return new TaskBasic();
+ }
+
+ public Object[] getArgs() {
+ return new Object[0];
+ }
+
+ public Signature getSignature() {
+ return null;
+ }
+
+ public SourceLocation getSourceLocation() {
+ return null;
+ }
+
+ public String getKind() {
+ return null;
+ }
+
+ public StaticPart getStaticPart() {
+ return null;
+ }
+}