From 4fefe4c101f174a1b8397285db3b751d68fdd1eb Mon Sep 17 00:00:00 2001 From: Mahmoud Ben Hassine Date: Fri, 13 Nov 2020 21:48:15 +0100 Subject: [PATCH] Fix flaky tests JsrSplitParsingTests#test and DecisionStepTests#testDecisionAfterSplit were failing intermittently with: ``` org.springframework.batch.core.JobExecutionException: Flow execution ended unexpectedly at org.springframework.batch.core.jsr.job.flow.JsrFlowJob.doExecute(JsrFlowJob.java:88) ~[main/:?] at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:320) [main/:?] at org.springframework.batch.core.jsr.launch.JsrJobOperator$2.run(JsrJobOperator.java:674) [main/:?] at java.lang.Thread.run(Thread.java:748) [?:1.8.0_232] Caused by: org.springframework.batch.core.job.flow.FlowExecutionException: Ended flow=flow1.step1 at state=flow1.step1.flow1.step1 with exception at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:178) ~[main/:?] at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:94) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:91) ~[main/:?] at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_232] ... 1 more Caused by: org.springframework.dao.ConcurrencyFailureException: PreparedStatementCallback; SQL [INSERT INTO BATCH_STEP_EXECUTION_CONTEXT (SHORT_CONTEXT, SERIALIZED_CONTEXT, STEP_EXECUTION_ID) VALUES(?, ?, ?)]; transaction rollback: serialization failure; nested exception is java.sql.SQLTransactionRollbackException: transaction rollback: serialization failure at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:73) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1541) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:667) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:960) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:1015) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.persistSerializedContext(JdbcExecutionContextDao.java:236) ~[main/:?] at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.saveExecutionContext(JdbcExecutionContextDao.java:189) ~[main/:?] at org.springframework.batch.core.repository.support.SimpleJobRepository.add(SimpleJobRepository.java:177) ~[main/:?] at sun.reflect.GeneratedMethodAccessor101.invoke(Unknown Source) ~[?:?] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_232] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_232] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:371) ~[spring-tx-5.3.0.jar:5.3.0] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:134) ~[spring-tx-5.3.0.jar:5.3.0] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.0.jar:5.3.0] at com.sun.proxy.$Proxy41.add(Unknown Source) ~[?:?] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:144) ~[main/:?] at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:68) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:68) ~[main/:?] at org.springframework.batch.core.jsr.job.flow.support.state.JsrStepState.handle(JsrStepState.java:53) ~[main/:?] at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169) ~[main/:?] at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:94) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:91) ~[main/:?] at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_232] ... 1 more Caused by: java.sql.SQLTransactionRollbackException: transaction rollback: serialization failure at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.hsqldb.jdbc.JDBCPreparedStatement.executeUpdate(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:136) ~[commons-dbcp2-2.8.0.jar:2.8.0] at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:136) ~[commons-dbcp2-2.8.0.jar:2.8.0] at org.springframework.jdbc.core.JdbcTemplate.lambda$update$2(JdbcTemplate.java:965) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:651) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:960) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:1015) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.persistSerializedContext(JdbcExecutionContextDao.java:236) ~[main/:?] at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.saveExecutionContext(JdbcExecutionContextDao.java:189) ~[main/:?] at org.springframework.batch.core.repository.support.SimpleJobRepository.add(SimpleJobRepository.java:177) ~[main/:?] at sun.reflect.GeneratedMethodAccessor101.invoke(Unknown Source) ~[?:?] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_232] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_232] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:371) ~[spring-tx-5.3.0.jar:5.3.0] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:134) ~[spring-tx-5.3.0.jar:5.3.0] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.0.jar:5.3.0] at com.sun.proxy.$Proxy41.add(Unknown Source) ~[?:?] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:144) ~[main/:?] at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:68) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:68) ~[main/:?] at org.springframework.batch.core.jsr.job.flow.support.state.JsrStepState.handle(JsrStepState.java:53) ~[main/:?] at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169) ~[main/:?] at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:94) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:91) ~[main/:?] at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_232] ... 1 more Caused by: org.hsqldb.HsqlException: transaction rollback: serialization failure at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.hsqldb.Session.handleAbortTransaction(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.hsqldb.Session.executeCompiledStatement(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.hsqldb.Session.execute(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.hsqldb.jdbc.JDBCPreparedStatement.executeUpdate(Unknown Source) ~[hsqldb-2.5.1.jar:2.5.1] at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:136) ~[commons-dbcp2-2.8.0.jar:2.8.0] at org.apache.commons.dbcp2.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:136) ~[commons-dbcp2-2.8.0.jar:2.8.0] at org.springframework.jdbc.core.JdbcTemplate.lambda$update$2(JdbcTemplate.java:965) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:651) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:960) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:1015) ~[spring-jdbc-5.3.0.jar:5.3.0] at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.persistSerializedContext(JdbcExecutionContextDao.java:236) ~[main/:?] at org.springframework.batch.core.repository.dao.JdbcExecutionContextDao.saveExecutionContext(JdbcExecutionContextDao.java:189) ~[main/:?] at org.springframework.batch.core.repository.support.SimpleJobRepository.add(SimpleJobRepository.java:177) ~[main/:?] at sun.reflect.GeneratedMethodAccessor101.invoke(Unknown Source) ~[?:?] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_232] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_232] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:371) ~[spring-tx-5.3.0.jar:5.3.0] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:134) ~[spring-tx-5.3.0.jar:5.3.0] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.0.jar:5.3.0] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215) ~[spring-aop-5.3.0.jar:5.3.0] at com.sun.proxy.$Proxy41.add(Unknown Source) ~[?:?] at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:144) ~[main/:?] at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:68) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:68) ~[main/:?] at org.springframework.batch.core.jsr.job.flow.support.state.JsrStepState.handle(JsrStepState.java:53) ~[main/:?] at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169) ~[main/:?] at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:94) ~[main/:?] at org.springframework.batch.core.job.flow.support.state.SplitState$1.call(SplitState.java:91) ~[main/:?] at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_232] ... 1 more ``` This failure is due to a concurrency issue when executing the split flow with the default SimpleAsyncTaskExecutor. Several attempts have been made to fix this issue with no success: * use `@DirtiesContext` annotation * use a separate db for each test * use `READ_COMMITTED` isolation level in the job repository * downgrade hsqldb from v2.5.1 to v2.4.1 (since v2.5.1 has introduced several changes in the MVCC mode) The issue seems to be related to how the in-memory database is shared between tests *and* how the test context is cached (ie the combination of both). This commit moves these tests to a separate test class which seem to fix the issue. (cherry picked from commit 109073130216b950f3b1201ec6d4764a799d071c) --- .../xml/JsrSplitParsingTests.java | 31 +---- .../core/jsr/step/DecisionStepTests.java | 23 +--- .../batch/core/jsr/step/SplitTests.java | 116 ++++++++++++++++++ ...tTests-testDecisionAfterSplit-context.xml} | 2 +- ...t.xml => SplitTests-testSplit-context.xml} | 6 +- 5 files changed, 122 insertions(+), 56 deletions(-) create mode 100644 spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/SplitTests.java rename spring-batch-core/src/test/resources/META-INF/batch-jobs/{DecisionStepTests-decisionAfterSplit-context.xml => SplitTests-testDecisionAfterSplit-context.xml} (95%) rename spring-batch-core/src/test/resources/META-INF/batch-jobs/{JsrSplitParsingTests-context.xml => SplitTests-testSplit-context.xml} (89%) diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/JsrSplitParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/JsrSplitParsingTests.java index 609a081d2..fb14e3076 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/JsrSplitParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/JsrSplitParsingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-2020 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. @@ -27,14 +27,6 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.task.SimpleAsyncTaskExecutor; -import javax.batch.api.AbstractBatchlet; -import javax.batch.runtime.BatchRuntime; -import javax.batch.runtime.StepExecution; -import javax.batch.runtime.context.JobContext; -import javax.inject.Inject; -import java.util.List; - -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -43,16 +35,6 @@ public class JsrSplitParsingTests extends AbstractJsrTestCase { @Rule public ExpectedException expectedException = ExpectedException.none(); - @Test - public void test() throws Exception { - javax.batch.runtime.JobExecution execution = runJob("JsrSplitParsingTests-context", null, 10000L); - assertEquals(javax.batch.runtime.BatchStatus.COMPLETED, execution.getBatchStatus()); - assertEquals("COMPLETED", execution.getExitStatus()); - - List stepExecutions = BatchRuntime.getJobOperator().getStepExecutions(execution.getExecutionId()); - assertEquals(5, stepExecutions.size()); - } - @Test public void testOneFlowInSplit() { try { @@ -86,15 +68,4 @@ public class JsrSplitParsingTests extends AbstractJsrTestCase { context.close(); } - public static class ExitStatusSettingBatchlet extends AbstractBatchlet { - - @Inject - JobContext jobContext; - - @Override - public String process() throws Exception { - jobContext.setExitStatus("Should be ignored"); - return null; - } - } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/DecisionStepTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/DecisionStepTests.java index 2b4b44948..8a8903283 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/DecisionStepTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/DecisionStepTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2017 the original author or authors. + * Copyright 2013-2020 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. @@ -27,7 +27,6 @@ import javax.batch.runtime.StepExecution; import org.junit.Test; import org.springframework.batch.core.jsr.AbstractJsrTestCase; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.Assert; import static org.junit.Assert.assertEquals; @@ -82,15 +81,6 @@ public class DecisionStepTests extends AbstractJsrTestCase { assertEquals(3, BatchRuntime.getJobOperator().getStepExecutions(execution.getExecutionId()).size()); } - @Test - public void testDecisionAfterSplit() throws Exception { - JobExecution execution = runJob("DecisionStepTests-decisionAfterSplit-context", new Properties(), 10000L); - org.springframework.batch.core.JobExecution jobExecution = (org.springframework.batch.core.JobExecution) ReflectionTestUtils.getField(execution, "execution"); - assertEquals(String.format("Received a %s because of %s", execution.getBatchStatus(), jobExecution.getExitStatus().getExitDescription()), BatchStatus.COMPLETED, execution.getBatchStatus()); - assertEquals(4, BatchRuntime.getJobOperator().getStepExecutions(execution.getExecutionId()).size()); - assertEquals(2, StepExecutionCountingDecider.previousStepCount); - } - @Test public void testDecisionRestart() throws Exception { JobExecution execution = runJob("DecisionStepTests-restart-context", new Properties(), 10000L); @@ -130,17 +120,6 @@ public class DecisionStepTests extends AbstractJsrTestCase { } } - public static class StepExecutionCountingDecider implements Decider { - - static int previousStepCount = 0; - - @Override - public String decide(StepExecution[] executions) throws Exception { - previousStepCount = executions.length; - return "next"; - } - } - public static class NextDecider implements Decider { @Override diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/SplitTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/SplitTests.java new file mode 100644 index 000000000..5e917de0f --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/SplitTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2020 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 + * + * https://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.jsr.step; + +import java.time.Duration; +import java.time.Instant; +import java.util.EnumSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +import javax.batch.api.AbstractBatchlet; +import javax.batch.api.Decider; +import javax.batch.operations.JobOperator; +import javax.batch.runtime.BatchRuntime; +import javax.batch.runtime.BatchStatus; +import javax.batch.runtime.JobExecution; +import javax.batch.runtime.StepExecution; +import javax.batch.runtime.context.JobContext; +import javax.inject.Inject; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author Mahmoud Ben Hassine + */ +public class SplitTests { + + private static final Set END_STATUSES = + EnumSet.of(BatchStatus.COMPLETED, BatchStatus.FAILED, BatchStatus.STOPPED); + private final JobOperator jobOperator = BatchRuntime.getJobOperator(); + + @Test + public void testSplit() { + // given + String jobXMLName = "SplitTests-testSplit-context"; + Properties jobParameters = new Properties(); + + // when + long executionId = jobOperator.start(jobXMLName, jobParameters); + waitFor(executionId, 10); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + List stepExecutions = jobOperator.getStepExecutions(executionId); + + // then + assertEquals(BatchStatus.COMPLETED, jobExecution.getBatchStatus()); + assertEquals("COMPLETED", jobExecution.getExitStatus()); + assertEquals(5, stepExecutions.size()); + } + + @Test + public void testDecisionAfterSplit() { + // given + String jobXMLName = "SplitTests-testDecisionAfterSplit-context"; + Properties jobParameters = new Properties(); + + // when + long executionId = jobOperator.start(jobXMLName, jobParameters); + waitFor(executionId, 10); + JobExecution jobExecution = jobOperator.getJobExecution(executionId); + + // then + assertEquals(BatchStatus.COMPLETED, jobExecution.getBatchStatus()); + assertEquals(4, jobOperator.getStepExecutions(executionId).size()); + assertEquals(2, StepExecutionCountingDecider.previousStepCount); + } + + private void waitFor(long executionId, int timeoutInSeconds) { + Instant startTime = Instant.now(); + while (!END_STATUSES.contains(jobOperator.getJobExecution(executionId).getBatchStatus())) { + if ((Duration.between(Instant.now(), startTime).getSeconds() > timeoutInSeconds)) { + fail("Job processing did not complete in time"); + } + } + } + + public static class StepExecutionCountingDecider implements Decider { + + static int previousStepCount = 0; + + @Override + public String decide(StepExecution[] executions) { + previousStepCount = executions.length; + return "next"; + } + } + + public static class ExitStatusSettingBatchlet extends AbstractBatchlet { + + @Inject + JobContext jobContext; + + @Override + public String process() throws Exception { + jobContext.setExitStatus("Should be ignored"); + return null; + } + } + +} diff --git a/spring-batch-core/src/test/resources/META-INF/batch-jobs/DecisionStepTests-decisionAfterSplit-context.xml b/spring-batch-core/src/test/resources/META-INF/batch-jobs/SplitTests-testDecisionAfterSplit-context.xml similarity index 95% rename from spring-batch-core/src/test/resources/META-INF/batch-jobs/DecisionStepTests-decisionAfterSplit-context.xml rename to spring-batch-core/src/test/resources/META-INF/batch-jobs/SplitTests-testDecisionAfterSplit-context.xml index 27c79a25f..487a762ef 100644 --- a/spring-batch-core/src/test/resources/META-INF/batch-jobs/DecisionStepTests-decisionAfterSplit-context.xml +++ b/spring-batch-core/src/test/resources/META-INF/batch-jobs/SplitTests-testDecisionAfterSplit-context.xml @@ -25,7 +25,7 @@ - + diff --git a/spring-batch-core/src/test/resources/META-INF/batch-jobs/JsrSplitParsingTests-context.xml b/spring-batch-core/src/test/resources/META-INF/batch-jobs/SplitTests-testSplit-context.xml similarity index 89% rename from spring-batch-core/src/test/resources/META-INF/batch-jobs/JsrSplitParsingTests-context.xml rename to spring-batch-core/src/test/resources/META-INF/batch-jobs/SplitTests-testSplit-context.xml index f43b1597c..31591ac19 100644 --- a/spring-batch-core/src/test/resources/META-INF/batch-jobs/JsrSplitParsingTests-context.xml +++ b/spring-batch-core/src/test/resources/META-INF/batch-jobs/SplitTests-testSplit-context.xml @@ -9,17 +9,17 @@ - + - + - +