/* * Copyright 2006-2013 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.batch.core.launch.support; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Properties; import java.util.Set; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobInstance; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.converter.DefaultJobParametersConverter; import org.springframework.batch.core.converter.JobParametersConverter; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.NoSuchJobException; import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; import org.springframework.batch.core.step.JobRepositorySupport; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.util.ClassUtils; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Lucas Ward * */ public class CommandLineJobRunnerTests { private String jobPath = ClassUtils.addResourcePathToPackagePath(CommandLineJobRunnerTests.class, "launcher-with-environment.xml"); private String jobName = "test-job"; private String jobKey = "job.Key=myKey"; private String scheduleDate = "schedule.Date=01/23/2008"; private String vendorId = "vendor.id=33243243"; private String[] args = new String[] { jobPath, jobName, jobKey, scheduleDate, vendorId }; private InputStream stdin; @Before public void setUp() throws Exception { JobExecution jobExecution = new JobExecution(null, new Long(1), null, null); ExitStatus exitStatus = ExitStatus.COMPLETED; jobExecution.setExitStatus(exitStatus); StubJobLauncher.jobExecution = jobExecution; stdin = System.in; System.setIn(new InputStream() { @Override public int read() { return -1; } }); } @After public void tearDown() throws Exception { System.setIn(stdin); StubJobLauncher.tearDown(); } @Test public void testMain() throws Exception { CommandLineJobRunner.main(args); assertTrue("Injected JobParametersConverter not used instead of default", StubJobParametersConverter.called); assertEquals(0, StubSystemExiter.getStatus()); } @Test public void testWithJobLocator() throws Exception { jobPath = ClassUtils.addResourcePathToPackagePath(CommandLineJobRunnerTests.class, "launcher-with-locator.xml"); CommandLineJobRunner.main(new String[] { jobPath, jobName, jobKey }); assertTrue("Injected JobParametersConverter not used instead of default", StubJobParametersConverter.called); assertEquals(0, StubSystemExiter.getStatus()); } @Test public void testJobAlreadyRunning() throws Throwable { StubJobLauncher.throwExecutionRunningException = true; CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); } @Test public void testInvalidArgs() throws Exception { String[] args = new String[] {}; CommandLineJobRunner.presetSystemExiter(new StubSystemExiter()); CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); String errorMessage = CommandLineJobRunner.getErrorMessage(); assertTrue("Wrong error message: " + errorMessage, errorMessage.contains("At least 2 arguments are required: JobPath/JobClass and jobIdentifier.")); } @Test public void testWrongJobName() throws Exception { String[] args = new String[] { jobPath, "no-such-job" }; CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); String errorMessage = CommandLineJobRunner.getErrorMessage(); assertTrue("Wrong error message: " + errorMessage, (errorMessage .contains("No bean named 'no-such-job' is defined") || (errorMessage .contains("No bean named 'no-such-job' available")))); } @Test public void testWithNoParameters() throws Throwable { String[] args = new String[] { jobPath, jobName }; CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); assertEquals(new JobParameters(), StubJobLauncher.jobParameters); } @Test public void testWithInvalidStdin() throws Throwable { System.setIn(new InputStream() { @Override public int available() throws IOException { throw new IOException("Planned"); } @Override public int read() { return -1; } }); CommandLineJobRunner.main(new String[] { jobPath, jobName }); assertEquals(0, StubSystemExiter.status); assertEquals(0, StubJobLauncher.jobParameters.getParameters().size()); } @Test public void testWithStdinCommandLine() throws Throwable { System.setIn(new InputStream() { char[] input = (jobPath+"\n"+jobName+"\nfoo=bar\nspam=bucket").toCharArray(); int index = 0; @Override public int available() { return input.length - index; } @Override public int read() { return index<input.length-1 ? (int) input[index++] : -1; } }); CommandLineJobRunner.main(new String[0]); assertEquals(0, StubSystemExiter.status); assertEquals(2, StubJobLauncher.jobParameters.getParameters().size()); } @Test public void testWithStdinCommandLineWithEmptyLines() throws Throwable { System.setIn(new InputStream() { char[] input = (jobPath+"\n"+jobName+"\nfoo=bar\n\nspam=bucket\n\n").toCharArray(); int index = 0; @Override public int available() { return input.length - index; } @Override public int read() { return index<input.length-1 ? (int) input[index++] : -1; } }); CommandLineJobRunner.main(new String[0]); assertEquals(0, StubSystemExiter.status); assertEquals(2, StubJobLauncher.jobParameters.getParameters().size()); } @Test public void testWithStdinParameters() throws Throwable { String[] args = new String[] { jobPath, jobName }; System.setIn(new InputStream() { char[] input = ("foo=bar\nspam=bucket").toCharArray(); int index = 0; @Override public int available() { return input.length - index; } @Override public int read() { return index<input.length-1 ? (int) input[index++] : -1; } }); CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); assertEquals(2, StubJobLauncher.jobParameters.getParameters().size()); } @Test public void testWithInvalidParameters() throws Throwable { String[] args = new String[] { jobPath, jobName, "foo" }; CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); String errorMessage = CommandLineJobRunner.getErrorMessage(); assertTrue("Wrong error message: " + errorMessage, errorMessage.contains("in the form name=value")); } @Test public void testStop() throws Throwable { String[] args = new String[] { jobPath, "-stop", jobName }; StubJobExplorer.jobInstances = Arrays.asList(new JobInstance(3L, jobName)); CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); } @Test public void testStopFailed() throws Throwable { String[] args = new String[] { jobPath, "-stop", jobName }; StubJobExplorer.jobInstances = Arrays.asList(new JobInstance(0L, jobName)); CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); } @Test public void testStopFailedAndRestarted() throws Throwable { String[] args = new String[] { jobPath, "-stop", jobName }; StubJobExplorer.jobInstances = Arrays.asList(new JobInstance(5L, jobName)); CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); } @Test public void testStopRestarted() throws Throwable { String[] args = new String[] { jobPath, "-stop", jobName }; JobInstance jobInstance = new JobInstance(3L, jobName); StubJobExplorer.jobInstances = Arrays.asList(jobInstance); CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); } @Test public void testAbandon() throws Throwable { String[] args = new String[] { jobPath, "-abandon", jobName }; StubJobExplorer.jobInstances = Arrays.asList(new JobInstance(2L, jobName)); CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); } @Test public void testAbandonRunning() throws Throwable { String[] args = new String[] { jobPath, "-abandon", jobName }; StubJobExplorer.jobInstances = Arrays.asList(new JobInstance(3L, jobName)); CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); } @Test public void testAbandonAbandoned() throws Throwable { String[] args = new String[] { jobPath, "-abandon", jobName }; StubJobExplorer.jobInstances = Arrays.asList(new JobInstance(4L, jobName)); CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); } @Test public void testRestart() throws Throwable { String[] args = new String[] { jobPath, "-restart", jobName }; JobParameters jobParameters = new JobParametersBuilder().addString("foo", "bar").toJobParameters(); JobInstance jobInstance = new JobInstance(0L, jobName); StubJobExplorer.jobInstances = Arrays.asList(jobInstance); StubJobExplorer.jobParameters = jobParameters; CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); assertEquals(jobParameters, StubJobLauncher.jobParameters); StubJobExplorer.jobParameters = new JobParameters(); } @Test public void testRestartExecution() throws Throwable { String[] args = new String[] { jobPath, "-restart", "11" }; JobParameters jobParameters = new JobParametersBuilder().addString("foo", "bar").toJobParameters(); JobExecution jobExecution = new JobExecution(new JobInstance(0L, jobName), 11L, jobParameters, null); jobExecution.setStatus(BatchStatus.FAILED); StubJobExplorer.jobExecution = jobExecution; CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); assertEquals(jobParameters, StubJobLauncher.jobParameters); } @Test public void testRestartExecutionNotFailed() throws Throwable { String[] args = new String[] { jobPath, "-restart", "11" }; JobParameters jobParameters = new JobParametersBuilder().addString("foo", "bar").toJobParameters(); JobExecution jobExecution = new JobExecution(new JobInstance(0L, jobName), 11L, jobParameters, null); jobExecution.setStatus(BatchStatus.COMPLETED); StubJobExplorer.jobExecution = jobExecution; CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); assertEquals(null, StubJobLauncher.jobParameters); } @Test public void testRestartNotFailed() throws Throwable { String[] args = new String[] { jobPath, "-restart", jobName }; StubJobExplorer.jobInstances = Arrays.asList(new JobInstance(123L, jobName)); CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); String errorMessage = CommandLineJobRunner.getErrorMessage(); assertTrue("Wrong error message: " + errorMessage, errorMessage .contains("No failed or stopped execution found")); } @Test public void testNext() throws Throwable { String[] args = new String[] { jobPath, "-next", jobName, "bar=foo" }; JobParameters jobParameters = new JobParametersBuilder().addString("foo", "bar").addString("bar", "foo") .toJobParameters(); StubJobExplorer.jobInstances = Arrays.asList(new JobInstance(2L, jobName)); CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); jobParameters = new JobParametersBuilder().addString("foo", "spam").addString("bar", "foo").toJobParameters(); assertEquals(jobParameters, StubJobLauncher.jobParameters); } @Test public void testNextFirstInSequence() throws Throwable { String[] args = new String[] { jobPath, "-next", jobName }; StubJobExplorer.jobInstances = new ArrayList<JobInstance>(); CommandLineJobRunner.main(args); assertEquals(0, StubSystemExiter.status); JobParameters jobParameters = new JobParametersBuilder().addString("foo", "spam").toJobParameters(); assertEquals(jobParameters, StubJobLauncher.jobParameters); } @Test public void testNextWithNoParameters() throws Exception { jobPath = ClassUtils.addResourcePathToPackagePath(CommandLineJobRunnerTests.class, "launcher-with-locator.xml"); CommandLineJobRunner.main(new String[] { jobPath, "-next", "test-job2", jobKey }); assertEquals(1, StubSystemExiter.getStatus()); String errorMessage = CommandLineJobRunner.getErrorMessage(); assertTrue("Wrong error message: " + errorMessage, errorMessage .contains(" No job parameters incrementer found")); } @Test public void testDestroyCallback() throws Throwable { String[] args = new String[] { jobPath, jobName }; CommandLineJobRunner.main(args); assertTrue(StubJobLauncher.destroyed); } @Test public void testJavaConfig() throws Exception { String[] args = new String[] { "org.springframework.batch.core.launch.support.CommandLineJobRunnerTests$Configuration1", "invalidJobName"}; CommandLineJobRunner.presetSystemExiter(new StubSystemExiter()); CommandLineJobRunner.main(args); assertEquals(1, StubSystemExiter.status); String errorMessage = CommandLineJobRunner.getErrorMessage(); assertTrue("Wrong error message: " + errorMessage, errorMessage.contains("A JobLauncher must be provided. Please add one to the configuration.")); } public static class StubSystemExiter implements SystemExiter { private static int status; @Override public void exit(int status) { StubSystemExiter.status = status; } public static int getStatus() { return status; } } public static class StubJobLauncher implements JobLauncher { public static JobExecution jobExecution; public static boolean throwExecutionRunningException = false; public static JobParameters jobParameters; private static boolean destroyed = false; @Override public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException { StubJobLauncher.jobParameters = jobParameters; if (throwExecutionRunningException) { throw new JobExecutionAlreadyRunningException(""); } return jobExecution; } public void destroy() { destroyed = true; } public static void tearDown() { jobExecution = null; throwExecutionRunningException = false; jobParameters = null; destroyed = false; } } public static class StubJobRepository extends JobRepositorySupport { } public static class StubJobExplorer implements JobExplorer { static List<JobInstance> jobInstances = new ArrayList<JobInstance>(); static JobExecution jobExecution; static JobParameters jobParameters = new JobParameters(); @Override public Set<JobExecution> findRunningJobExecutions(String jobName) { throw new UnsupportedOperationException(); } @Override public JobExecution getJobExecution(Long executionId) { if (jobExecution != null) { return jobExecution; } throw new UnsupportedOperationException(); } @Override public List<JobExecution> getJobExecutions(JobInstance jobInstance) { if (jobInstance.getId() == 0) { return Arrays.asList(createJobExecution(jobInstance, BatchStatus.FAILED)); } if (jobInstance.getId() == 1) { return null; } if (jobInstance.getId() == 2) { return Arrays.asList(createJobExecution(jobInstance, BatchStatus.STOPPED)); } if (jobInstance.getId() == 3) { return Arrays.asList(createJobExecution(jobInstance, BatchStatus.STARTED)); } if (jobInstance.getId() == 4) { return Arrays.asList(createJobExecution(jobInstance, BatchStatus.ABANDONED)); } if (jobInstance.getId() == 5) { return Arrays.asList(createJobExecution(jobInstance, BatchStatus.STARTED), createJobExecution( jobInstance, BatchStatus.FAILED)); } return Arrays.asList(createJobExecution(jobInstance, BatchStatus.COMPLETED)); } private JobExecution createJobExecution(JobInstance jobInstance, BatchStatus status) { JobExecution jobExecution = new JobExecution(jobInstance, 1L, jobParameters, null); jobExecution.setStatus(status); jobExecution.setStartTime(new Date()); if (status != BatchStatus.STARTED) { jobExecution.setEndTime(new Date()); } return jobExecution; } @Override public JobInstance getJobInstance(Long instanceId) { throw new UnsupportedOperationException(); } @Override public List<JobInstance> getJobInstances(String jobName, int start, int count) { if (jobInstances == null) { return new ArrayList<JobInstance>(); } List<JobInstance> result = jobInstances; jobInstances = null; return result; } @Override public StepExecution getStepExecution(Long jobExecutionId, Long stepExecutionId) { throw new UnsupportedOperationException(); } @Override public List<String> getJobNames() { throw new UnsupportedOperationException(); } @Override public List<JobInstance> findJobInstancesByJobName(String jobName, int start, int count) { throw new UnsupportedOperationException(); } @Override public int getJobInstanceCount(String jobName) throws NoSuchJobException { int count = 0; for (JobInstance jobInstance : jobInstances) { if(jobInstance.getJobName().equals(jobName)) { count++; } } if(count == 0) { throw new NoSuchJobException("Unable to find job instances for " + jobName); } else { return count; } } } public static class StubJobParametersConverter implements JobParametersConverter { JobParametersConverter delegate = new DefaultJobParametersConverter(); static boolean called = false; @Override public JobParameters getJobParameters(Properties properties) { called = true; return delegate.getJobParameters(properties); } @Override public Properties getProperties(JobParameters params) { throw new UnsupportedOperationException(); } } @Configuration public static class Configuration1 { @Bean public String bean1() { return "bean1"; } } }