/*
* Copyright 2013-2014 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.explore.support;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.dbcp.BasicDataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.UnexpectedJobExecutionException;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.xml.DummyStep;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowStep;
import org.springframework.batch.core.job.flow.support.SimpleFlow;
import org.springframework.batch.core.job.flow.support.StateTransition;
import org.springframework.batch.core.job.flow.support.state.EndState;
import org.springframework.batch.core.job.flow.support.state.StepState;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import test.jdbc.datasource.DataSourceInitializer;
/**
* Integration test for the BATCH-2034 issue.
* The {@link FlowStep} execution should not fail in the remote partitioning use case because the {@link SimpleJobExplorer}
* doesn't retrieve the {@link JobInstance} from the {@link JobRepository}.
* To illustrate the issue the test simulates the behavior of the {@code StepExecutionRequestHandler}
* from the spring-batch-integration project.
*
* @author Sergey Shcherbakov
*/
@ContextConfiguration(classes={SimpleJobExplorerIntegrationTests.Config.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class SimpleJobExplorerIntegrationTests {
@Configuration
@EnableBatchProcessing
static class Config {
@Autowired
private StepBuilderFactory steps;
@Bean
public JobExplorer jobExplorer() throws Exception {
return jobExplorerFactoryBean().getObject();
}
@Bean
public JobExplorerFactoryBean jobExplorerFactoryBean() {
JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
jobExplorerFactoryBean.setDataSource(dataSource());
return jobExplorerFactoryBean;
}
@Bean
public Step flowStep() throws Exception {
return steps.get("flowStep").flow(simpleFlow()).build();
}
@Bean
public Step dummyStep() {
return new DummyStep();
}
@Bean
public SimpleFlow simpleFlow() {
SimpleFlow simpleFlow = new SimpleFlow("simpleFlow");
List<StateTransition> transitions = new ArrayList<StateTransition>();
transitions.add(StateTransition.createStateTransition(new StepState(dummyStep()), "end0"));
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end0")));
simpleFlow.setStateTransitions(transitions);
return simpleFlow;
}
@Bean
public BasicDataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true;hsqldb.tx=mvcc");
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
}
@Bean
public DataSourceInitializer dataSourceInitializer() {
DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
dataSourceInitializer.setDataSource(dataSource());
dataSourceInitializer.setInitScripts(new Resource[] {
new ClassPathResource("org/springframework/batch/core/schema-drop-hsqldb.sql"),
new ClassPathResource("org/springframework/batch/core/schema-hsqldb.sql")
});
return dataSourceInitializer;
}
}
@Autowired
private JobRepository jobRepository;
@Autowired
private JobExplorer jobExplorer;
@Autowired
private FlowStep flowStep;
@Test
public void testGetStepExecution() throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobInterruptedException, UnexpectedJobExecutionException {
// Prepare the jobRepository for the test
JobExecution jobExecution = jobRepository.createJobExecution("myJob", new JobParameters());
StepExecution stepExecution = jobExecution.createStepExecution("flowStep");
jobRepository.add(stepExecution);
// Executed on the remote end in remote partitioning use case
StepExecution jobExplorerStepExecution = jobExplorer.getStepExecution(jobExecution.getId(), stepExecution.getId());
flowStep.execute(jobExplorerStepExecution);
assertEquals(BatchStatus.COMPLETED, jobExplorerStepExecution.getStatus());
}
}