/*
* 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.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersIncrementer;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.MapJobRegistry;
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.job.AbstractJob;
import org.springframework.batch.core.job.JobSupport;
import org.springframework.batch.core.launch.JobInstanceAlreadyExistsException;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.launch.NoSuchJobExecutionException;
import org.springframework.batch.core.launch.NoSuchJobInstanceException;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.StoppableTasklet;
import org.springframework.batch.core.step.tasklet.TaskletStep;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.batch.support.PropertiesConverter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* @author Dave Syer
* @author Will Schipp
*
*/
public class SimpleJobOperatorTests {
private SimpleJobOperator jobOperator;
protected Job job;
private JobExplorer jobExplorer;
private JobRepository jobRepository;
private JobParameters jobParameters;
@Before
public void setUp() throws Exception {
job = new JobSupport("foo") {
@Override
public JobParametersIncrementer getJobParametersIncrementer() {
return parameters -> jobParameters;
}
};
jobOperator = new SimpleJobOperator();
jobOperator.setJobRegistry(new MapJobRegistry() {
@Override
public Job getJob(String name) throws NoSuchJobException {
if (name.equals("foo")) {
return job;
}
throw new NoSuchJobException("foo");
}
@Override
public Set<String> getJobNames() {
return new HashSet<>(Arrays.asList(new String[] { "foo", "bar" }));
}
});
jobOperator.setJobLauncher((job, jobParameters) -> new JobExecution(new JobInstance(123L, job.getName()), 999L, jobParameters, null));
jobExplorer = mock(JobExplorer.class);
jobOperator.setJobExplorer(jobExplorer);
jobRepository = mock(JobRepository.class);
jobOperator.setJobRepository(jobRepository);
jobOperator.setJobParametersConverter(new DefaultJobParametersConverter() {
@Override
public JobParameters getJobParameters(Properties props) {
assertTrue("Wrong properties", props.containsKey("a"));
return jobParameters;
}
@Override
public Properties getProperties(JobParameters params) {
return PropertiesConverter.stringToProperties("a=b");
}
});
jobOperator.afterPropertiesSet();
}
@Test
public void testMandatoryProperties() throws Exception {
jobOperator = new SimpleJobOperator();
try {
jobOperator.afterPropertiesSet();
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {
// expected
}
}
/**
* Test method for
* {@link org.springframework.batch.core.launch.support.SimpleJobOperator#startNextInstance(java.lang.String)}
* .
*/
@Test
public void testStartNextInstanceSunnyDay() throws Exception {
JobInstance jobInstance = new JobInstance(321L, "foo");
when(jobExplorer.getJobInstances("foo", 0, 1)).thenReturn(Collections.singletonList(jobInstance));
when(jobExplorer.getJobExecutions(jobInstance)).thenReturn(Collections.singletonList(new JobExecution(jobInstance, new JobParameters())));
Long value = jobOperator.startNextInstance("foo");
assertEquals(999, value.longValue());
}
@Test
public void testStartNewInstanceSunnyDay() throws Exception {
jobParameters = new JobParameters();
jobRepository.isJobInstanceExists("foo", jobParameters);
Long value = jobOperator.start("foo", "a=b");
assertEquals(999, value.longValue());
}
@Test
public void testStartNewInstanceAlreadyExists() throws Exception {
jobParameters = new JobParameters();
when(jobRepository.isJobInstanceExists("foo", jobParameters)).thenReturn(true);
jobRepository.isJobInstanceExists("foo", jobParameters);
try {
jobOperator.start("foo", "a=b");
fail("Expected JobInstanceAlreadyExistsException");
}
catch (JobInstanceAlreadyExistsException e) {
// expected
}
}
@Test
public void testResumeSunnyDay() throws Exception {
jobParameters = new JobParameters();
when(jobExplorer.getJobExecution(111L)).thenReturn(new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null));
jobExplorer.getJobExecution(111L);
Long value = jobOperator.restart(111L);
assertEquals(999, value.longValue());
}
@Test
public void testGetSummarySunnyDay() throws Exception {
jobParameters = new JobParameters();
JobExecution jobExecution = new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null);
when(jobExplorer.getJobExecution(111L)).thenReturn(jobExecution);
jobExplorer.getJobExecution(111L);
String value = jobOperator.getSummary(111L);
assertEquals(jobExecution.toString(), value);
}
@Test
public void testGetSummaryNoSuchExecution() throws Exception {
jobParameters = new JobParameters();
jobExplorer.getJobExecution(111L);
try {
jobOperator.getSummary(111L);
fail("Expected NoSuchJobExecutionException");
} catch (NoSuchJobExecutionException e) {
// expected
}
}
@Test
public void testGetStepExecutionSummariesSunnyDay() throws Exception {
jobParameters = new JobParameters();
JobExecution jobExecution = new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null);
jobExecution.createStepExecution("step1");
jobExecution.createStepExecution("step2");
jobExecution.getStepExecutions().iterator().next().setId(21L);
when(jobExplorer.getJobExecution(111L)).thenReturn(jobExecution);
Map<Long, String> value = jobOperator.getStepExecutionSummaries(111L);
assertEquals(2, value.size());
}
@Test
public void testGetStepExecutionSummariesNoSuchExecution() throws Exception {
jobParameters = new JobParameters();
jobExplorer.getJobExecution(111L);
try {
jobOperator.getStepExecutionSummaries(111L);
fail("Expected NoSuchJobExecutionException");
} catch (NoSuchJobExecutionException e) {
// expected
}
}
@Test
public void testFindRunningExecutionsSunnyDay() throws Exception {
jobParameters = new JobParameters();
JobExecution jobExecution = new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null);
when(jobExplorer.findRunningJobExecutions("foo")).thenReturn(Collections.singleton(jobExecution));
Set<Long> value = jobOperator.getRunningExecutions("foo");
assertEquals(111L, value.iterator().next().longValue());
}
@Test
@SuppressWarnings("unchecked")
public void testFindRunningExecutionsNoSuchJob() throws Exception {
jobParameters = new JobParameters();
when(jobExplorer.findRunningJobExecutions("no-such-job")).thenReturn(Collections.EMPTY_SET);
try {
jobOperator.getRunningExecutions("no-such-job");
fail("Expected NoSuchJobException");
} catch (NoSuchJobException e) {
// expected
}
}
@Test
public void testGetJobParametersSunnyDay() throws Exception {
final JobParameters jobParameters = new JobParameters();
when(jobExplorer.getJobExecution(111L)).thenReturn(new JobExecution(new JobInstance(123L, job.getName()), 111L, jobParameters, null));
String value = jobOperator.getParameters(111L);
assertEquals("a=b", value);
}
@Test
public void testGetJobParametersNoSuchExecution() throws Exception {
jobExplorer.getJobExecution(111L);
try {
jobOperator.getParameters(111L);
fail("Expected NoSuchJobExecutionException");
} catch (NoSuchJobExecutionException e) {
// expected
}
}
@Test
public void testGetLastInstancesSunnyDay() throws Exception {
jobParameters = new JobParameters();
JobInstance jobInstance = new JobInstance(123L, job.getName());
when(jobExplorer.getJobInstances("foo", 0, 2)).thenReturn(Collections.singletonList(jobInstance));
jobExplorer.getJobInstances("foo", 0, 2);
List<Long> value = jobOperator.getJobInstances("foo", 0, 2);
assertEquals(123L, value.get(0).longValue());
}
@Test
public void testGetLastInstancesNoSuchJob() throws Exception {
jobParameters = new JobParameters();
jobExplorer.getJobInstances("no-such-job", 0, 2);
try {
jobOperator.getJobInstances("no-such-job", 0, 2);
fail("Expected NoSuchJobException");
}
catch (NoSuchJobException e) {
// expected
}
}
@Test
public void testGetJobNames() throws Exception {
Set<String> names = jobOperator.getJobNames();
assertEquals(2, names.size());
assertTrue("Wrong names: " + names, names.contains("foo"));
}
@Test
public void testGetExecutionsSunnyDay() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
when(jobExplorer.getJobInstance(123L)).thenReturn(jobInstance);
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
when(jobExplorer.getJobExecutions(jobInstance)).thenReturn(Collections.singletonList(jobExecution));
List<Long> value = jobOperator.getExecutions(123L);
assertEquals(111L, value.iterator().next().longValue());
}
@Test
public void testGetExecutionsNoSuchInstance() throws Exception {
jobExplorer.getJobInstance(123L);
try {
jobOperator.getExecutions(123L);
fail("Expected NoSuchJobInstanceException");
}
catch (NoSuchJobInstanceException e) {
// expected
}
}
@Test
public void testStop() throws Exception{
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
when(jobExplorer.getJobExecution(111L)).thenReturn(jobExecution);
jobExplorer.getJobExecution(111L);
jobRepository.update(jobExecution);
jobOperator.stop(111L);
assertEquals(BatchStatus.STOPPING, jobExecution.getStatus());
}
@Test
public void testStopTasklet() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
StoppableTasklet tasklet = mock(StoppableTasklet.class);
TaskletStep taskletStep = new TaskletStep();
taskletStep.setTasklet(tasklet);
MockJob job = new MockJob();
job.taskletStep = taskletStep;
JobRegistry jobRegistry = mock(JobRegistry.class);
TaskletStep step = mock(TaskletStep.class);
when(step.getTasklet()).thenReturn(tasklet);
when(step.getName()).thenReturn("test_job.step1");
when(jobRegistry.getJob(any(String.class))).thenReturn(job);
when(jobExplorer.getJobExecution(111L)).thenReturn(jobExecution);
jobOperator.setJobRegistry(jobRegistry);
jobExplorer.getJobExecution(111L);
jobRepository.update(jobExecution);
jobOperator.stop(111L);
assertEquals(BatchStatus.STOPPING, jobExecution.getStatus());
}
@Test
public void testStopTaskletException() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
StoppableTasklet tasklet = new StoppableTasklet() {
@Override
public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
return null;
}
@Override
public void stop() {
throw new IllegalStateException();
}};
TaskletStep taskletStep = new TaskletStep();
taskletStep.setTasklet(tasklet);
MockJob job = new MockJob();
job.taskletStep = taskletStep;
JobRegistry jobRegistry = mock(JobRegistry.class);
TaskletStep step = mock(TaskletStep.class);
when(step.getTasklet()).thenReturn(tasklet);
when(step.getName()).thenReturn("test_job.step1");
when(jobRegistry.getJob(any(String.class))).thenReturn(job);
when(jobExplorer.getJobExecution(111L)).thenReturn(jobExecution);
jobOperator.setJobRegistry(jobRegistry);
jobExplorer.getJobExecution(111L);
jobRepository.update(jobExecution);
jobOperator.stop(111L);
assertEquals(BatchStatus.STOPPING, jobExecution.getStatus());
}
@Test
public void testAbort() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
jobExecution.setStatus(BatchStatus.STOPPING);
when(jobExplorer.getJobExecution(123L)).thenReturn(jobExecution);
jobRepository.update(jobExecution);
jobOperator.abandon(123L);
assertEquals(BatchStatus.ABANDONED, jobExecution.getStatus());
assertNotNull(jobExecution.getEndTime());
}
@Test(expected = JobExecutionAlreadyRunningException.class)
public void testAbortNonStopping() throws Exception {
JobInstance jobInstance = new JobInstance(123L, job.getName());
JobExecution jobExecution = new JobExecution(jobInstance, 111L, jobParameters, null);
jobExecution.setStatus(BatchStatus.STARTED);
when(jobExplorer.getJobExecution(123L)).thenReturn(jobExecution);
jobRepository.update(jobExecution);
jobOperator.abandon(123L);
}
class MockJob extends AbstractJob {
private TaskletStep taskletStep;
@Override
public Step getStep(String stepName) {
return taskletStep;
}
@Override
public Collection<String> getStepNames() {
return Collections.singletonList("test_job.step1");
}
@Override
protected void doExecute(JobExecution execution) throws JobExecutionException {
}
}
}