Polish and updated a test to validate the conditions
This commit is contained in:
@@ -26,6 +26,7 @@ import org.springframework.batch.core.step.builder.StepBuilder;
|
||||
import org.springframework.batch.core.step.item.KeyGenerator;
|
||||
import org.springframework.batch.core.step.skip.SkipPolicy;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
@@ -400,4 +401,10 @@ public class RemoteChunkingMasterStepBuilder<I, O> extends FaultTolerantStepBuil
|
||||
super.allowStartIfComplete(allowStartIfComplete);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoteChunkingMasterStepBuilder<I, O> processor(ItemProcessor<? super I, ? extends O> itemProcessor) {
|
||||
super.processor(itemProcessor);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.springframework.context.annotation.Import;
|
||||
* <pre class="code">
|
||||
* @Configuration
|
||||
* @EnableBatchIntegration
|
||||
* @EnableBatchProcessing
|
||||
* public class RemoteChunkingAppConfig {
|
||||
*
|
||||
* @Autowired
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package org.springframework.batch.integration.chunk;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
@@ -23,32 +25,47 @@ import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.batch.core.ChunkListener;
|
||||
import org.springframework.batch.core.ItemReadListener;
|
||||
import org.springframework.batch.core.ItemWriteListener;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.SkipListener;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
|
||||
import org.springframework.batch.core.listener.ChunkListenerSupport;
|
||||
import org.springframework.batch.core.listener.CompositeItemReadListener;
|
||||
import org.springframework.batch.core.listener.CompositeItemWriteListener;
|
||||
import org.springframework.batch.core.listener.SkipListenerSupport;
|
||||
import org.springframework.batch.core.listener.StepExecutionListenerSupport;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.item.ChunkOrientedTasklet;
|
||||
import org.springframework.batch.core.step.item.SimpleChunkProcessor;
|
||||
import org.springframework.batch.core.step.item.SimpleChunkProvider;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemStreamSupport;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.item.support.CompositeItemStream;
|
||||
import org.springframework.batch.item.support.ListItemReader;
|
||||
import org.springframework.batch.repeat.exception.DefaultExceptionHandler;
|
||||
import org.springframework.batch.repeat.support.RepeatTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.retry.RetryListener;
|
||||
import org.springframework.retry.backoff.NoBackOffPolicy;
|
||||
import org.springframework.retry.listener.RetryListenerSupport;
|
||||
import org.springframework.retry.policy.MapRetryContextCache;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
|
||||
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
/**
|
||||
* @author Mahmoud Ben Hassine
|
||||
*/
|
||||
@@ -216,44 +233,136 @@ public class RemoteChunkingMasterStepBuilderTest {
|
||||
* The following test is to cover setters that override those from parent builders.
|
||||
*/
|
||||
@Test
|
||||
public void testSetters() {
|
||||
public void testSetters() throws Exception {
|
||||
// when
|
||||
DefaultTransactionAttribute transactionAttribute = new DefaultTransactionAttribute();
|
||||
|
||||
Object annotatedListener = new Object();
|
||||
MapRetryContextCache retryCache = new MapRetryContextCache();
|
||||
RepeatTemplate stepOperations = new RepeatTemplate();
|
||||
NoBackOffPolicy backOffPolicy = new NoBackOffPolicy();
|
||||
ItemStreamSupport stream = new ItemStreamSupport() {
|
||||
};
|
||||
StepExecutionListener stepExecutionListener = mock(StepExecutionListener.class);
|
||||
ItemReadListener<String> itemReadListener = mock(ItemReadListener.class);
|
||||
ItemWriteListener<String> itemWriteListener = mock(ItemWriteListener.class);
|
||||
ChunkListener chunkListener = mock(ChunkListener.class);
|
||||
SkipListener<String, String> skipListener = mock(SkipListener.class);
|
||||
RetryListener retryListener = mock(RetryListener.class);
|
||||
|
||||
when(retryListener.open(any(), any())).thenReturn(true);
|
||||
|
||||
ItemProcessor<String, String> itemProcessor = item -> {
|
||||
System.out.println("processing item " + item);
|
||||
if(item.equals("b")) {
|
||||
throw new Exception("b was found");
|
||||
}
|
||||
else {
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
ItemReader<String> itemReader = new ItemReader<String>() {
|
||||
|
||||
int count = 0;
|
||||
List<String> items = Arrays.asList("a", "b", "c", "d", "d", "e", "f", "g", "h", "i");
|
||||
|
||||
@Override
|
||||
public String read() throws Exception {
|
||||
System.out.println(">> count == " + count);
|
||||
if(count == 6) {
|
||||
count++;
|
||||
throw new IOException("6th item");
|
||||
}
|
||||
else if(count == 7) {
|
||||
count++;
|
||||
throw new RuntimeException("7th item");
|
||||
}
|
||||
else if(count < items.size()){
|
||||
String item = items.get(count++);
|
||||
System.out.println(">> item read was " + item);
|
||||
return item;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TaskletStep taskletStep = new RemoteChunkingMasterStepBuilder<String, String>("step")
|
||||
.reader(this.itemReader)
|
||||
.reader(itemReader)
|
||||
.readerIsTransactionalQueue()
|
||||
.processor(itemProcessor)
|
||||
.repository(this.jobRepository)
|
||||
.transactionManager(this.transactionManager)
|
||||
.transactionAttribute(new DefaultTransactionAttribute())
|
||||
.transactionAttribute(transactionAttribute)
|
||||
.inputChannel(this.inputChannel)
|
||||
.outputChannel(this.outputChannel)
|
||||
.listener(new Object())
|
||||
.listener(new SkipListenerSupport<>())
|
||||
.listener(new ChunkListenerSupport())
|
||||
.listener(new StepExecutionListenerSupport())
|
||||
.listener(new CompositeItemReadListener<>())
|
||||
.listener(new CompositeItemWriteListener<>())
|
||||
.listener(new RetryListenerSupport())
|
||||
.listener(annotatedListener)
|
||||
.listener(skipListener)
|
||||
.listener(chunkListener)
|
||||
.listener(stepExecutionListener)
|
||||
.listener(itemReadListener)
|
||||
.listener(itemWriteListener)
|
||||
.listener(retryListener)
|
||||
.skip(Exception.class)
|
||||
.noSkip(RuntimeException.class)
|
||||
.skipLimit(10)
|
||||
.retry(Exception.class)
|
||||
.retry(IOException.class)
|
||||
.noRetry(RuntimeException.class)
|
||||
.retryLimit(10)
|
||||
.retryContextCache(new MapRetryContextCache())
|
||||
.retryContextCache(retryCache)
|
||||
.noRollback(Exception.class)
|
||||
.chunk(10)
|
||||
.startLimit(3)
|
||||
.allowStartIfComplete(true)
|
||||
.exceptionHandler(new DefaultExceptionHandler())
|
||||
.stepOperations(new RepeatTemplate())
|
||||
.chunkOperations(new RepeatTemplate())
|
||||
.backOffPolicy(new NoBackOffPolicy())
|
||||
.stream(new ItemStreamSupport() {})
|
||||
.stepOperations(stepOperations)
|
||||
.chunk(3)
|
||||
.backOffPolicy(backOffPolicy)
|
||||
.stream(stream)
|
||||
.keyGenerator(Object::hashCode)
|
||||
.build();
|
||||
|
||||
JobExecution jobExecution = this.jobRepository.createJobExecution("job1", new JobParameters());
|
||||
StepExecution stepExecution = new StepExecution("step1", jobExecution);
|
||||
this.jobRepository.add(stepExecution);
|
||||
|
||||
taskletStep.execute(stepExecution);
|
||||
|
||||
// then
|
||||
Assert.assertNotNull(taskletStep);
|
||||
ChunkOrientedTasklet tasklet = (ChunkOrientedTasklet) ReflectionTestUtils.getField(taskletStep, "tasklet");
|
||||
SimpleChunkProvider provider = (SimpleChunkProvider) ReflectionTestUtils.getField(tasklet, "chunkProvider");
|
||||
SimpleChunkProcessor processor = (SimpleChunkProcessor) ReflectionTestUtils.getField(tasklet, "chunkProcessor");
|
||||
ItemWriter itemWriter = (ItemWriter) ReflectionTestUtils.getField(processor, "itemWriter");
|
||||
MessagingTemplate messagingTemplate = (MessagingTemplate) ReflectionTestUtils.getField(itemWriter, "messagingGateway");
|
||||
CompositeItemStream compositeItemStream = (CompositeItemStream) ReflectionTestUtils.getField(taskletStep, "stream");
|
||||
|
||||
Assert.assertEquals(ReflectionTestUtils.getField(provider, "itemReader"), itemReader);
|
||||
Assert.assertFalse((Boolean) ReflectionTestUtils.getField(tasklet, "buffering"));
|
||||
Assert.assertEquals(ReflectionTestUtils.getField(taskletStep, "jobRepository"), this.jobRepository);
|
||||
Assert.assertEquals(ReflectionTestUtils.getField(taskletStep, "transactionManager"), this.transactionManager);
|
||||
Assert.assertEquals(ReflectionTestUtils.getField(taskletStep, "transactionAttribute"), transactionAttribute);
|
||||
Assert.assertEquals(ReflectionTestUtils.getField(itemWriter, "replyChannel"), this.inputChannel);
|
||||
Assert.assertEquals(ReflectionTestUtils.getField(messagingTemplate, "defaultDestination"), this.outputChannel);
|
||||
Assert.assertEquals(ReflectionTestUtils.getField(processor, "itemProcessor"), itemProcessor);
|
||||
|
||||
Assert.assertEquals((int) ReflectionTestUtils.getField(taskletStep, "startLimit"), 3);
|
||||
Assert.assertTrue((Boolean) ReflectionTestUtils.getField(taskletStep, "allowStartIfComplete"));
|
||||
Object stepOperationsUsed = ReflectionTestUtils.getField(taskletStep, "stepOperations");
|
||||
Assert.assertEquals(stepOperationsUsed, stepOperations);
|
||||
|
||||
Assert.assertEquals(((List)ReflectionTestUtils.getField(compositeItemStream, "streams")).size(), 2);
|
||||
Assert.assertNotNull(ReflectionTestUtils.getField(processor, "keyGenerator"));
|
||||
|
||||
verify(skipListener, atLeastOnce()).onSkipInProcess(any(), any());
|
||||
verify(retryListener, atLeastOnce()).open(any(), any());
|
||||
verify(stepExecutionListener, atLeastOnce()).beforeStep(any());
|
||||
verify(chunkListener, atLeastOnce()).beforeChunk(any());
|
||||
verify(itemReadListener, atLeastOnce()).beforeRead();
|
||||
verify(itemWriteListener, atLeastOnce()).beforeWrite(any());
|
||||
|
||||
Assert.assertEquals(stepExecution.getSkipCount(), 2);
|
||||
Assert.assertEquals(stepExecution.getRollbackCount(), 3);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
Reference in New Issue
Block a user