From ce8854b89e0e2c54d5467b27d6f376cd418bbc5b Mon Sep 17 00:00:00 2001 From: Glenn Renfro Date: Mon, 23 Nov 2015 15:52:03 -0500 Subject: [PATCH] SCT-4 Added SimpleTaskConfiguration * Added unit tests * Introduced @EnableTask * Readme updated to include @EnableTask * Removed warnings from build * Cleanup --- README.adoc | 25 +++-- pom.xml | 33 +++++++ spring-cloud-task-core/pom.xml | 33 ++++++- .../cloud/task/annotation/EnableTask.java | 68 ++++++++++++++ .../cloud/task/annotation/Task.java | 7 +- .../configuration/DefaultTaskConfigurer.java | 26 +++--- .../SimpleTaskConfiguration.java | 91 +++++++++++++++++++ .../task/configuration/TaskConfigurer.java | 2 +- .../cloud/task/configuration/TaskHandler.java | 25 +++-- .../cloud/task/repository/TaskRepository.java | 2 +- .../support/LoggerTaskRepository.java | 2 + .../cloud/task/LoggerTaskRepositoryTests.java | 71 +++++++++++++++ .../task/SimpleTaskConfigurationTests.java | 50 ++++++++++ .../cloud/task/TaskHandlerDefaultTests.java | 86 ++++++++++++++++++ ...erTest.java => NoOpTaskExplorerTests.java} | 2 +- .../cloud/task/util/LoggerTestUtils.java | 62 +++++++++++++ .../cloud/task/util/TaskBasic.java | 36 ++++++++ .../task/util/TestDefaultConfiguration.java | 50 ++++++++++ .../cloud/task/util/TestJoinPoint.java | 64 +++++++++++++ 19 files changed, 697 insertions(+), 38 deletions(-) create mode 100644 spring-cloud-task-core/src/main/java/org/springframework/cloud/task/annotation/EnableTask.java create mode 100644 spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/LoggerTaskRepositoryTests.java create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskHandlerDefaultTests.java rename spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/{NoOpTaskExplorerTest.java => NoOpTaskExplorerTests.java} (97%) create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/LoggerTestUtils.java create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TaskBasic.java create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java create mode 100644 spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestJoinPoint.java 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: + * + * + * + * @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: + * + * + * + * * @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; + } +}