Stores the command line arguements within the task repository

Resolves spring-cloud/spring-cloud-task#62

Code Review Polishing
This commit is contained in:
Michael Minella
2016-01-19 17:02:37 -06:00
committed by Glenn Renfro
parent 1a7cd94721
commit 846eb3fad9
4 changed files with 174 additions and 35 deletions

View File

@@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.cloud.task.listener.TaskLifecycleListener;
import org.springframework.cloud.task.repository.TaskNameResolver;
import org.springframework.cloud.task.repository.TaskRepository;
@@ -60,6 +61,9 @@ public class SimpleTaskConfiguration {
@Autowired
private ResourceLoader resourceLoader;
@Autowired(required = false)
private ApplicationArguments applicationArguments;
@Value("${spring.class.initialize.enable:true}")
private boolean taskInitializationEnable;
@@ -78,7 +82,7 @@ public class SimpleTaskConfiguration {
@Bean
public TaskLifecycleListener taskLifecycleListener() {
return new TaskLifecycleListener(taskRepository(), taskNameResolver());
return new TaskLifecycleListener(taskRepository(), taskNameResolver(), this.applicationArguments);
}
@Bean

View File

@@ -18,11 +18,14 @@ package org.springframework.cloud.task.listener;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.cloud.task.repository.TaskNameResolver;
@@ -63,16 +66,20 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
private TaskNameResolver taskNameResolver;
private ApplicationArguments applicationArguments;
/**
* @param taskRepository The repository to record executions in.
*/
public TaskLifecycleListener(TaskRepository taskRepository,
TaskNameResolver taskNameResolver) {
TaskNameResolver taskNameResolver,
ApplicationArguments applicationArguments) {
Assert.notNull(taskRepository, "A taskRepository is required");
Assert.notNull(taskNameResolver, "A taskNameResolver is required");
this.taskRepository = taskRepository;
this.taskNameResolver = taskNameResolver;
this.applicationArguments = applicationArguments;
}
/**
@@ -142,9 +149,15 @@ public class TaskLifecycleListener implements ApplicationListener<ApplicationEve
private void doTaskStart() {
if(!started) {
List<String> args = new ArrayList<>(0);
if(this.applicationArguments != null) {
args = Arrays.asList(this.applicationArguments.getSourceArgs());
}
this.taskExecution = new TaskExecution(this.taskRepository.getNextExecutionId(),
0, this.taskNameResolver.getTaskName(), new Date(), null, null, null,
new ArrayList<String>(0), null);
args, null);
this.taskRepository.createTaskExecution(this.taskExecution);
}

View File

@@ -17,21 +17,35 @@
package org.springframework.cloud.task.listener;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import ch.qos.logback.core.Appender;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.cloud.task.repository.TaskExplorer;
import org.springframework.cloud.task.util.TestDefaultConfiguration;
import org.springframework.cloud.task.util.TestVerifierUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
/**
* Verifies that the TaskLifecycleListener Methods record the appropriate log header entries and
@@ -42,14 +56,14 @@ import org.springframework.context.event.ContextClosedEvent;
*/
public class TaskLifecycleListenerTests {
@Autowired
private TaskLifecycleListener listener;
private AnnotationConfigApplicationContext context;
private TaskExplorer taskExplorer;
@Before
public void setUp() {
context = new AnnotationConfigApplicationContext();
context.setId("testTask");
context.register(TestDefaultConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
}
@@ -60,41 +74,131 @@ public class TaskLifecycleListenerTests {
@Test
public void testTaskCreate() {
final Appender mockAppender = TestVerifierUtils.getMockAppender();
context.refresh();
this.listener = context.getBean(TaskLifecycleListener.class);
TestVerifierUtils.verifyLogEntryExists(mockAppender,
"Creating: TaskExecution{executionId=" +
listener.getTaskExecution().getExecutionId());
assertEquals("Create should report that exit code is zero",
0, listener.getTaskExecution().getExitCode());
verifyTaskExecution(0, false, 0, null);
}
@Test
public void testTaskCreateWithArgs() {
context.register(ArgsConfiguration.class);
context.refresh();
verifyTaskExecution(2, false, 0, null);
}
@Test
public void testTaskUpdate() {
context.refresh();
final Appender mockAppender = TestVerifierUtils.getMockAppender();
this.listener = context.getBean(TaskLifecycleListener.class);
this.listener.onApplicationEvent(new ContextClosedEvent(context));
TestVerifierUtils.verifyLogEntryExists(mockAppender,
"Updating: TaskExecution{executionId=" +
listener.getTaskExecution().getExecutionId());
assertEquals("Update should report that exit code is zero",
0, listener.getTaskExecution().getExitCode());
context.publishEvent(new ContextClosedEvent(context));
verifyTaskExecution(0, true, 0, null);
}
@Test
public void testTaskFailedUpdate() {
context.refresh();
final Appender mockAppender = TestVerifierUtils.getMockAppender();
this.listener = context.getBean(TaskLifecycleListener.class);
listener.onApplicationEvent(new ApplicationFailedEvent(new SpringApplication(), new String[]{}, context, new RuntimeException("This was expected")));
TestVerifierUtils.verifyLogEntryExists(mockAppender,
"Updating: TaskExecution{executionId=" +
listener.getTaskExecution().getExecutionId());
assertEquals("Update should report that exit code is one",
1, listener.getTaskExecution().getExitCode());
assertTrue("Stack trace missing from exit message", listener.getTaskExecution().getExitMessage().startsWith("java.lang.RuntimeException: This was expected"));
RuntimeException exception = new RuntimeException("This was expected");
context.publishEvent(new ApplicationFailedEvent(new SpringApplication(), new String[0], context, exception));
verifyTaskExecution(0, true, 1, exception);
}
private static String stackTraceToString(Throwable exception) {
StringWriter writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
exception.printStackTrace(printWriter);
return writer.toString();
}
private void verifyTaskExecution(int numberOfParams, boolean update, int exitCode, Throwable exception) {
this.taskExplorer = context.getBean(TaskExplorer.class);
Sort sort = new Sort("id");
PageRequest request = new PageRequest(0, Integer.MAX_VALUE, sort);
Page<TaskExecution> taskExecutionsByName = this.taskExplorer.findTaskExecutionsByName("testTask",
request);
assertTrue(taskExecutionsByName.iterator().hasNext());
TaskExecution taskExecution = taskExecutionsByName.iterator().next();
assertEquals(numberOfParams, taskExecution.getParameters().size());
assertEquals(exitCode, taskExecution.getExitCode());
if(exception != null) {
assertTrue(taskExecution.getExitMessage().length() > exception.getStackTrace().length);
}
else {
assertNull(taskExecution.getExitMessage());
}
if(update) {
assertTrue(taskExecution.getEndTime().getTime() >= taskExecution.getStartTime().getTime());
}
else {
assertNull(taskExecution.getEndTime());
}
assertNull(taskExecution.getExternalExecutionID());
assertNull(taskExecution.getStatusCode());
assertEquals("testTask", taskExecution.getTaskName());
}
@Configuration
public static class ArgsConfiguration {
@Bean
public ApplicationArguments args() {
Map<String, String> args = new HashMap<>(2);
args.put("foo", "bar");
args.put("baz", "qux");
return new SimpleApplicationArgs(args);
}
}
private static class SimpleApplicationArgs implements ApplicationArguments {
private Map<String, String> args;
public SimpleApplicationArgs(Map<String, String> args) {
this.args = args;
}
@Override
public String[] getSourceArgs() {
String [] sourceArgs = new String[this.args.size()];
int i = 0;
for (Map.Entry<String, String> stringStringEntry : args.entrySet()) {
sourceArgs[i] = "--" + stringStringEntry.getKey() + "=" + stringStringEntry.getValue();
i++;
}
return sourceArgs;
}
@Override
public Set<String> getOptionNames() {
return this.args.keySet();
}
@Override
public boolean containsOption(String s) {
return this.args.containsKey(s);
}
@Override
public List<String> getOptionValues(String s) {
return Arrays.asList(this.args.get(s));
}
@Override
public List<String> getNonOptionArgs() {
throw new UnsupportedOperationException("Not supported at this time.");
}
}
}

View File

@@ -16,10 +16,14 @@
package org.springframework.cloud.task.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.cloud.task.listener.TaskLifecycleListener;
import org.springframework.cloud.task.repository.TaskExplorer;
import org.springframework.cloud.task.repository.TaskNameResolver;
import org.springframework.cloud.task.repository.TaskRepository;
import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao;
import org.springframework.cloud.task.repository.support.SimpleTaskExplorer;
import org.springframework.cloud.task.repository.support.SimpleTaskNameResolver;
import org.springframework.cloud.task.repository.support.SimpleTaskRepository;
import org.springframework.context.annotation.Bean;
@@ -33,9 +37,18 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class TestDefaultConfiguration {
private MapTaskExecutionDao dao;
@Autowired(required = false)
private ApplicationArguments applicationArguments;
public TestDefaultConfiguration() {
this.dao = new MapTaskExecutionDao();
}
@Bean
public TaskRepository taskRepository(){
return new SimpleTaskRepository(new MapTaskExecutionDao());
return new SimpleTaskRepository(this.dao);
}
@Bean
@@ -45,6 +58,11 @@ public class TestDefaultConfiguration {
@Bean
public TaskLifecycleListener taskHandler(){
return new TaskLifecycleListener(taskRepository(), taskNameResolver());
return new TaskLifecycleListener(taskRepository(), taskNameResolver(), applicationArguments);
}
@Bean
public TaskExplorer taskExplorer() {
return new SimpleTaskExplorer(this.dao);
}
}