Batch2 test refactor only (#5823)
* refactoring * test refactor only * spotless * bumping version --------- Co-authored-by: leif stawnyczy <leifstawnyczy@leifs-mbp.home>
This commit is contained in:
parent
620b46dd0a
commit
5d55594a73
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-bom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
<name>HAPI FHIR BOM</name>
|
||||
|
@ -12,7 +12,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-cli</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -20,6 +20,7 @@ import ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity;
|
|||
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.util.JsonUtil;
|
||||
import ca.uhn.hapi.fhir.batch2.test.AbstractIJobPersistenceSpecificationTest;
|
||||
import ca.uhn.hapi.fhir.batch2.test.configs.SpyOverrideConfig;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterators;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
|
@ -30,6 +31,7 @@ import org.junit.jupiter.params.ParameterizedTest;
|
|||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
@ -60,6 +62,7 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
|||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@TestMethodOrder(MethodOrderer.MethodName.class)
|
||||
@Import(SpyOverrideConfig.class)
|
||||
public class JpaJobPersistenceImplTest extends BaseJpaR4Test {
|
||||
|
||||
public static final String JOB_DEFINITION_ID = "definition-id";
|
||||
|
@ -323,14 +326,19 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test {
|
|||
class Batch2SpecTest extends AbstractIJobPersistenceSpecificationTest {
|
||||
|
||||
@Override
|
||||
protected PlatformTransactionManager getTxManager() {
|
||||
public PlatformTransactionManager getTxManager() {
|
||||
return JpaJobPersistenceImplTest.this.getTxManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WorkChunk freshFetchWorkChunk(String chunkId) {
|
||||
public WorkChunk freshFetchWorkChunk(String chunkId) {
|
||||
return JpaJobPersistenceImplTest.this.freshFetchWorkChunk(chunkId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runMaintenancePass() {
|
||||
myBatch2JobHelper.forceRunMaintenancePass();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
@ -21,7 +21,7 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-caching-api</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -20,30 +20,28 @@
|
|||
|
||||
package ca.uhn.hapi.fhir.batch2.test;
|
||||
|
||||
import ca.uhn.fhir.batch2.api.IJobMaintenanceService;
|
||||
import ca.uhn.fhir.batch2.api.IJobPersistence;
|
||||
import ca.uhn.fhir.batch2.api.RunOutcome;
|
||||
import ca.uhn.fhir.batch2.channel.BatchJobSender;
|
||||
import ca.uhn.fhir.batch2.coordinator.JobDefinitionRegistry;
|
||||
import ca.uhn.fhir.batch2.maintenance.JobChunkProgressAccumulator;
|
||||
import ca.uhn.fhir.batch2.maintenance.JobInstanceProcessor;
|
||||
import ca.uhn.fhir.batch2.model.JobDefinition;
|
||||
import ca.uhn.fhir.batch2.model.JobInstance;
|
||||
import ca.uhn.fhir.batch2.model.JobWorkNotification;
|
||||
import ca.uhn.fhir.batch2.model.StatusEnum;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunk;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkCompletionEvent;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkCreateEvent;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkErrorEvent;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.hapi.fhir.batch2.test.support.TestJobParameters;
|
||||
import ca.uhn.hapi.fhir.batch2.test.support.TestJobStep2InputType;
|
||||
import ca.uhn.hapi.fhir.batch2.test.support.TestJobStep3InputType;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import ca.uhn.test.concurrency.PointcutLatch;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -53,580 +51,118 @@ import org.springframework.transaction.TransactionStatus;
|
|||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.emptyString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.theInstance;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* Specification tests for batch2 storage and event system.
|
||||
* These tests are abstract, and do not depend on JPA.
|
||||
* Test setups should use the public batch2 api to create scenarios.
|
||||
*/
|
||||
public abstract class AbstractIJobPersistenceSpecificationTest {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(AbstractIJobPersistenceSpecificationTest.class);
|
||||
public abstract class AbstractIJobPersistenceSpecificationTest implements IInProgressActionsTests, IInstanceStateTransitions, ITestFixture, WorkChunkTestConstants {
|
||||
|
||||
public static final String JOB_DEFINITION_ID = "definition-id";
|
||||
public static final String TARGET_STEP_ID = "step-id";
|
||||
public static final String DEF_CHUNK_ID = "definition-chunkId";
|
||||
public static final String STEP_CHUNK_ID = "step-chunkId";
|
||||
public static final int JOB_DEF_VER = 1;
|
||||
public static final int SEQUENCE_NUMBER = 1;
|
||||
public static final String CHUNK_DATA = "{\"key\":\"value\"}";
|
||||
public static final String ERROR_MESSAGE_A = "This is an error message: A";
|
||||
public static final String ERROR_MESSAGE_B = "This is a different error message: B";
|
||||
public static final String ERROR_MESSAGE_C = "This is a different error message: C";
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(AbstractIJobPersistenceSpecificationTest.class);
|
||||
|
||||
@Autowired
|
||||
private IJobPersistence mySvc;
|
||||
|
||||
@Nested
|
||||
class WorkChunkStorage {
|
||||
@Autowired
|
||||
private JobDefinitionRegistry myJobDefinitionRegistry;
|
||||
|
||||
@Test
|
||||
public void testStoreAndFetchWorkChunk_NoData() {
|
||||
JobInstance instance = createInstance();
|
||||
String instanceId = mySvc.storeNewInstance(instance);
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
||||
String id = storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 0, null);
|
||||
@Autowired
|
||||
private IJobMaintenanceService myMaintenanceService;
|
||||
|
||||
WorkChunk chunk = mySvc.onWorkChunkDequeue(id).orElseThrow(IllegalArgumentException::new);
|
||||
assertNull(chunk.getData());
|
||||
}
|
||||
@Autowired
|
||||
private BatchJobSender myBatchJobSender;
|
||||
|
||||
@Test
|
||||
public void testStoreAndFetchWorkChunk_WithData() {
|
||||
JobInstance instance = createInstance();
|
||||
String instanceId = mySvc.storeNewInstance(instance);
|
||||
|
||||
String id = storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 0, CHUNK_DATA);
|
||||
assertNotNull(id);
|
||||
runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, freshFetchWorkChunk(id).getStatus()));
|
||||
|
||||
WorkChunk chunk = mySvc.onWorkChunkDequeue(id).orElseThrow(IllegalArgumentException::new);
|
||||
assertEquals(36, chunk.getInstanceId().length());
|
||||
assertEquals(JOB_DEFINITION_ID, chunk.getJobDefinitionId());
|
||||
assertEquals(JOB_DEF_VER, chunk.getJobDefinitionVersion());
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus());
|
||||
assertEquals(CHUNK_DATA, chunk.getData());
|
||||
|
||||
runInTransaction(() -> assertEquals(WorkChunkStatusEnum.IN_PROGRESS, freshFetchWorkChunk(id).getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Should match the diagram in batch2_states.md
|
||||
* @see hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/batch2_states.md
|
||||
*/
|
||||
@Nested
|
||||
class StateTransitions {
|
||||
|
||||
private String myInstanceId;
|
||||
private String myChunkId;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
JobInstance jobInstance = createInstance();
|
||||
myInstanceId = mySvc.storeNewInstance(jobInstance);
|
||||
|
||||
}
|
||||
|
||||
private String createChunk() {
|
||||
return storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, myInstanceId, 0, CHUNK_DATA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chunkCreation_isQueued() {
|
||||
|
||||
myChunkId = createChunk();
|
||||
|
||||
WorkChunk fetchedWorkChunk = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.QUEUED, fetchedWorkChunk.getStatus(), "New chunks are QUEUED");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chunkReceived_queuedToInProgress() {
|
||||
|
||||
myChunkId = createChunk();
|
||||
|
||||
// the worker has received the chunk, and marks it started.
|
||||
WorkChunk chunk = mySvc.onWorkChunkDequeue(myChunkId).orElseThrow(IllegalArgumentException::new);
|
||||
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus());
|
||||
assertEquals(CHUNK_DATA, chunk.getData());
|
||||
|
||||
// verify the db was updated too
|
||||
WorkChunk fetchedWorkChunk = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, fetchedWorkChunk.getStatus());
|
||||
}
|
||||
|
||||
@Nested
|
||||
class InProgressActions {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
// setup - the worker has received the chunk, and has marked it IN_PROGRESS.
|
||||
myChunkId = createChunk();
|
||||
mySvc.onWorkChunkDequeue(myChunkId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processingOk_inProgressToSuccess_clearsDataSavesRecordCount() {
|
||||
|
||||
// execution ok
|
||||
mySvc.onWorkChunkCompletion(new WorkChunkCompletionEvent(myChunkId, 3, 0));
|
||||
|
||||
// verify the db was updated
|
||||
var workChunkEntity = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.COMPLETED, workChunkEntity.getStatus());
|
||||
assertNull(workChunkEntity.getData());
|
||||
assertEquals(3, workChunkEntity.getRecordsProcessed());
|
||||
assertNull(workChunkEntity.getErrorMessage());
|
||||
assertEquals(0, workChunkEntity.getErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processingRetryableError_inProgressToError_bumpsCountRecordsMessage() {
|
||||
|
||||
// execution had a retryable error
|
||||
mySvc.onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_A));
|
||||
|
||||
// verify the db was updated
|
||||
var workChunkEntity = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, workChunkEntity.getStatus());
|
||||
assertEquals(ERROR_MESSAGE_A, workChunkEntity.getErrorMessage());
|
||||
assertEquals(1, workChunkEntity.getErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processingFailure_inProgressToFailed() {
|
||||
|
||||
// execution had a failure
|
||||
mySvc.onWorkChunkFailed(myChunkId, "some error");
|
||||
|
||||
// verify the db was updated
|
||||
var workChunkEntity = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.FAILED, workChunkEntity.getStatus());
|
||||
assertEquals("some error", workChunkEntity.getErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
class ErrorActions {
|
||||
public static final String FIRST_ERROR_MESSAGE = ERROR_MESSAGE_A;
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
// setup - the worker has received the chunk, and has marked it IN_PROGRESS.
|
||||
myChunkId = createChunk();
|
||||
mySvc.onWorkChunkDequeue(myChunkId);
|
||||
// execution had a retryable error
|
||||
mySvc.onWorkChunkError(new WorkChunkErrorEvent(myChunkId, FIRST_ERROR_MESSAGE));
|
||||
}
|
||||
|
||||
/**
|
||||
* The consumer will retry after a retryable error is thrown
|
||||
*/
|
||||
@Test
|
||||
void errorRetry_errorToInProgress() {
|
||||
|
||||
// when consumer restarts chunk
|
||||
WorkChunk chunk = mySvc.onWorkChunkDequeue(myChunkId).orElseThrow(IllegalArgumentException::new);
|
||||
|
||||
// then
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus());
|
||||
|
||||
// verify the db state, error message, and error count
|
||||
var workChunkEntity = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, workChunkEntity.getStatus());
|
||||
assertEquals(FIRST_ERROR_MESSAGE, workChunkEntity.getErrorMessage(), "Original error message kept");
|
||||
assertEquals(1, workChunkEntity.getErrorCount(), "error count kept");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorRetry_repeatError_increasesErrorCount() {
|
||||
// setup - the consumer is re-trying, and marks it IN_PROGRESS
|
||||
mySvc.onWorkChunkDequeue(myChunkId);
|
||||
|
||||
|
||||
// when another error happens
|
||||
mySvc.onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_B));
|
||||
|
||||
|
||||
// verify the state, new message, and error count
|
||||
var workChunkEntity = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, workChunkEntity.getStatus());
|
||||
assertEquals(ERROR_MESSAGE_B, workChunkEntity.getErrorMessage(), "new error message");
|
||||
assertEquals(2, workChunkEntity.getErrorCount(), "error count inc");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorThenRetryAndComplete_addsErrorCounts() {
|
||||
// setup - the consumer is re-trying, and marks it IN_PROGRESS
|
||||
mySvc.onWorkChunkDequeue(myChunkId);
|
||||
|
||||
// then it completes ok.
|
||||
mySvc.onWorkChunkCompletion(new WorkChunkCompletionEvent(myChunkId, 3, 1));
|
||||
|
||||
// verify the state, new message, and error count
|
||||
var workChunkEntity = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.COMPLETED, workChunkEntity.getStatus());
|
||||
assertEquals(FIRST_ERROR_MESSAGE, workChunkEntity.getErrorMessage(), "Error message kept.");
|
||||
assertEquals(2, workChunkEntity.getErrorCount(), "error combined with earlier error");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorRetry_maxErrors_movesToFailed() {
|
||||
// we start with 1 error already
|
||||
|
||||
// 2nd try
|
||||
mySvc.onWorkChunkDequeue(myChunkId);
|
||||
mySvc.onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_B));
|
||||
var chunk = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, chunk.getStatus());
|
||||
assertEquals(2, chunk.getErrorCount());
|
||||
|
||||
// 3rd try
|
||||
mySvc.onWorkChunkDequeue(myChunkId);
|
||||
mySvc.onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_B));
|
||||
chunk = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, chunk.getStatus());
|
||||
assertEquals(3, chunk.getErrorCount());
|
||||
|
||||
// 4th try
|
||||
mySvc.onWorkChunkDequeue(myChunkId);
|
||||
mySvc.onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_C));
|
||||
chunk = freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.FAILED, chunk.getStatus());
|
||||
assertEquals(4, chunk.getErrorCount());
|
||||
assertThat("Error message contains last error", chunk.getErrorMessage(), containsString(ERROR_MESSAGE_C));
|
||||
assertThat("Error message contains error count and complaint", chunk.getErrorMessage(), containsString("many errors: 4"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarkChunkAsCompleted_Success() {
|
||||
JobInstance instance = createInstance();
|
||||
String instanceId = mySvc.storeNewInstance(instance);
|
||||
String chunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, CHUNK_DATA);
|
||||
assertNotNull(chunkId);
|
||||
|
||||
runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, freshFetchWorkChunk(chunkId).getStatus()));
|
||||
|
||||
sleepUntilTimeChanges();
|
||||
|
||||
WorkChunk chunk = mySvc.onWorkChunkDequeue(chunkId).orElseThrow(IllegalArgumentException::new);
|
||||
assertEquals(SEQUENCE_NUMBER, chunk.getSequence());
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus());
|
||||
assertNotNull(chunk.getCreateTime());
|
||||
assertNotNull(chunk.getStartTime());
|
||||
assertNull(chunk.getEndTime());
|
||||
assertNull(chunk.getRecordsProcessed());
|
||||
assertNotNull(chunk.getData());
|
||||
runInTransaction(() -> assertEquals(WorkChunkStatusEnum.IN_PROGRESS, freshFetchWorkChunk(chunkId).getStatus()));
|
||||
|
||||
sleepUntilTimeChanges();
|
||||
|
||||
runInTransaction(() -> mySvc.onWorkChunkCompletion(new WorkChunkCompletionEvent(chunkId, 50, 0)));
|
||||
|
||||
WorkChunk entity = freshFetchWorkChunk(chunkId);
|
||||
assertEquals(WorkChunkStatusEnum.COMPLETED, entity.getStatus());
|
||||
assertEquals(50, entity.getRecordsProcessed());
|
||||
assertNotNull(entity.getCreateTime());
|
||||
assertNotNull(entity.getStartTime());
|
||||
assertNotNull(entity.getEndTime());
|
||||
assertNull(entity.getData());
|
||||
assertTrue(entity.getCreateTime().getTime() < entity.getStartTime().getTime());
|
||||
assertTrue(entity.getStartTime().getTime() < entity.getEndTime().getTime());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMarkChunkAsCompleted_Error() {
|
||||
JobInstance instance = createInstance();
|
||||
String instanceId = mySvc.storeNewInstance(instance);
|
||||
String chunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, null);
|
||||
assertNotNull(chunkId);
|
||||
|
||||
runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, freshFetchWorkChunk(chunkId).getStatus()));
|
||||
|
||||
sleepUntilTimeChanges();
|
||||
|
||||
WorkChunk chunk = mySvc.onWorkChunkDequeue(chunkId).orElseThrow(IllegalArgumentException::new);
|
||||
assertEquals(SEQUENCE_NUMBER, chunk.getSequence());
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus());
|
||||
|
||||
sleepUntilTimeChanges();
|
||||
|
||||
WorkChunkErrorEvent request = new WorkChunkErrorEvent(chunkId, ERROR_MESSAGE_A);
|
||||
mySvc.onWorkChunkError(request);
|
||||
runInTransaction(() -> {
|
||||
WorkChunk entity = freshFetchWorkChunk(chunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, entity.getStatus());
|
||||
assertEquals(ERROR_MESSAGE_A, entity.getErrorMessage());
|
||||
assertNotNull(entity.getCreateTime());
|
||||
assertNotNull(entity.getStartTime());
|
||||
assertNotNull(entity.getEndTime());
|
||||
assertEquals(1, entity.getErrorCount());
|
||||
assertTrue(entity.getCreateTime().getTime() < entity.getStartTime().getTime());
|
||||
assertTrue(entity.getStartTime().getTime() < entity.getEndTime().getTime());
|
||||
});
|
||||
|
||||
// Mark errored again
|
||||
|
||||
WorkChunkErrorEvent request2 = new WorkChunkErrorEvent(chunkId, "This is an error message 2");
|
||||
mySvc.onWorkChunkError(request2);
|
||||
runInTransaction(() -> {
|
||||
WorkChunk entity = freshFetchWorkChunk(chunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, entity.getStatus());
|
||||
assertEquals("This is an error message 2", entity.getErrorMessage());
|
||||
assertNotNull(entity.getCreateTime());
|
||||
assertNotNull(entity.getStartTime());
|
||||
assertNotNull(entity.getEndTime());
|
||||
assertEquals(2, entity.getErrorCount());
|
||||
assertTrue(entity.getCreateTime().getTime() < entity.getStartTime().getTime());
|
||||
assertTrue(entity.getStartTime().getTime() < entity.getEndTime().getTime());
|
||||
});
|
||||
|
||||
List<WorkChunk> chunks = ImmutableList.copyOf(mySvc.fetchAllWorkChunksIterator(instanceId, true));
|
||||
assertEquals(1, chunks.size());
|
||||
assertEquals(2, chunks.get(0).getErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarkChunkAsCompleted_Fail() {
|
||||
JobInstance instance = createInstance();
|
||||
String instanceId = mySvc.storeNewInstance(instance);
|
||||
String chunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, null);
|
||||
assertNotNull(chunkId);
|
||||
|
||||
runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, freshFetchWorkChunk(chunkId).getStatus()));
|
||||
|
||||
sleepUntilTimeChanges();
|
||||
|
||||
WorkChunk chunk = mySvc.onWorkChunkDequeue(chunkId).orElseThrow(IllegalArgumentException::new);
|
||||
assertEquals(SEQUENCE_NUMBER, chunk.getSequence());
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus());
|
||||
|
||||
sleepUntilTimeChanges();
|
||||
|
||||
mySvc.onWorkChunkFailed(chunkId, "This is an error message");
|
||||
runInTransaction(() -> {
|
||||
WorkChunk entity = freshFetchWorkChunk(chunkId);
|
||||
assertEquals(WorkChunkStatusEnum.FAILED, entity.getStatus());
|
||||
assertEquals("This is an error message", entity.getErrorMessage());
|
||||
assertNotNull(entity.getCreateTime());
|
||||
assertNotNull(entity.getStartTime());
|
||||
assertNotNull(entity.getEndTime());
|
||||
assertTrue(entity.getCreateTime().getTime() < entity.getStartTime().getTime());
|
||||
assertTrue(entity.getStartTime().getTime() < entity.getEndTime().getTime());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void markWorkChunksWithStatusAndWipeData_marksMultipleChunksWithStatus_asExpected() {
|
||||
JobInstance instance = createInstance();
|
||||
String instanceId = mySvc.storeNewInstance(instance);
|
||||
ArrayList<String> chunkIds = new ArrayList<>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
WorkChunkCreateEvent chunk = new WorkChunkCreateEvent(
|
||||
"defId",
|
||||
1,
|
||||
"stepId",
|
||||
instanceId,
|
||||
0,
|
||||
"{}"
|
||||
);
|
||||
String id = mySvc.onWorkChunkCreate(chunk);
|
||||
chunkIds.add(id);
|
||||
}
|
||||
|
||||
runInTransaction(() -> mySvc.markWorkChunksWithStatusAndWipeData(instance.getInstanceId(), chunkIds, WorkChunkStatusEnum.COMPLETED, null));
|
||||
|
||||
Iterator<WorkChunk> reducedChunks = mySvc.fetchAllWorkChunksIterator(instanceId, true);
|
||||
|
||||
while (reducedChunks.hasNext()) {
|
||||
WorkChunk reducedChunk = reducedChunks.next();
|
||||
assertTrue(chunkIds.contains(reducedChunk.getId()));
|
||||
assertEquals(WorkChunkStatusEnum.COMPLETED, reducedChunk.getStatus());
|
||||
}
|
||||
}
|
||||
public PlatformTransactionManager getTransactionManager() {
|
||||
return myTransactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test
|
||||
* * @see hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/batch2_states.md
|
||||
*/
|
||||
@Nested
|
||||
class InstanceStateTransitions {
|
||||
|
||||
@Test
|
||||
void createInstance_createsInQueuedWithChunk() {
|
||||
// given
|
||||
JobDefinition<?> jd = withJobDefinition();
|
||||
|
||||
// when
|
||||
IJobPersistence.CreateResult createResult =
|
||||
newTxTemplate().execute(status->
|
||||
mySvc.onCreateWithFirstChunk(jd, "{}"));
|
||||
|
||||
// then
|
||||
ourLog.info("job and chunk created {}", createResult);
|
||||
assertNotNull(createResult);
|
||||
assertThat(createResult.jobInstanceId, not(emptyString()));
|
||||
assertThat(createResult.workChunkId, not(emptyString()));
|
||||
|
||||
JobInstance jobInstance = freshFetchJobInstance(createResult.jobInstanceId);
|
||||
assertThat(jobInstance.getStatus(), equalTo(StatusEnum.QUEUED));
|
||||
assertThat(jobInstance.getParameters(), equalTo("{}"));
|
||||
|
||||
WorkChunk firstChunk = freshFetchWorkChunk(createResult.workChunkId);
|
||||
assertThat(firstChunk.getStatus(), equalTo(WorkChunkStatusEnum.QUEUED));
|
||||
assertNull(firstChunk.getData(), "First chunk data is null - only uses parameters");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateInstance_firstChunkDequeued_movesToInProgress() {
|
||||
// given
|
||||
JobDefinition<?> jd = withJobDefinition();
|
||||
IJobPersistence.CreateResult createResult = newTxTemplate().execute(status->
|
||||
mySvc.onCreateWithFirstChunk(jd, "{}"));
|
||||
assertNotNull(createResult);
|
||||
|
||||
// when
|
||||
newTxTemplate().execute(status -> mySvc.onChunkDequeued(createResult.jobInstanceId));
|
||||
|
||||
// then
|
||||
JobInstance jobInstance = freshFetchJobInstance(createResult.jobInstanceId);
|
||||
assertThat(jobInstance.getStatus(), equalTo(StatusEnum.IN_PROGRESS));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(StatusEnum.class)
|
||||
void cancelRequest_cancelsJob_whenNotFinalState(StatusEnum theState) {
|
||||
// given
|
||||
JobInstance cancelledInstance = createInstance();
|
||||
cancelledInstance.setStatus(theState);
|
||||
String instanceId1 = mySvc.storeNewInstance(cancelledInstance);
|
||||
mySvc.cancelInstance(instanceId1);
|
||||
|
||||
JobInstance normalInstance = createInstance();
|
||||
normalInstance.setStatus(theState);
|
||||
String instanceId2 = mySvc.storeNewInstance(normalInstance);
|
||||
|
||||
JobDefinitionRegistry jobDefinitionRegistry = new JobDefinitionRegistry();
|
||||
jobDefinitionRegistry.addJobDefinitionIfNotRegistered(withJobDefinition());
|
||||
|
||||
|
||||
// when
|
||||
runInTransaction(()-> new JobInstanceProcessor(mySvc, null, instanceId1, new JobChunkProgressAccumulator(), null, jobDefinitionRegistry)
|
||||
.process());
|
||||
|
||||
|
||||
// then
|
||||
JobInstance freshInstance1 = mySvc.fetchInstance(instanceId1).orElseThrow();
|
||||
if (theState.isCancellable()) {
|
||||
assertEquals(StatusEnum.CANCELLED, freshInstance1.getStatus(), "cancel request processed");
|
||||
assertThat(freshInstance1.getErrorMessage(), containsString("Job instance cancelled"));
|
||||
} else {
|
||||
assertEquals(theState, freshInstance1.getStatus(), "cancel request ignored - state unchanged");
|
||||
assertNull(freshInstance1.getErrorMessage(), "no error message");
|
||||
}
|
||||
JobInstance freshInstance2 = mySvc.fetchInstance(instanceId2).orElseThrow();
|
||||
assertEquals(theState, freshInstance2.getStatus(), "cancel request ignored - cancelled not set");
|
||||
}
|
||||
public IJobPersistence getSvc() {
|
||||
return mySvc;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeleteChunksAndMarkInstanceAsChunksPurged_doesWhatItSays() {
|
||||
// given
|
||||
JobDefinition<?> jd = withJobDefinition();
|
||||
IJobPersistence.CreateResult createResult = newTxTemplate().execute(status->
|
||||
mySvc.onCreateWithFirstChunk(jd, "{}"));
|
||||
String instanceId = createResult.jobInstanceId;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, i, CHUNK_DATA);
|
||||
}
|
||||
JobInstance readback = freshFetchJobInstance(instanceId);
|
||||
assertFalse(readback.isWorkChunksPurged());
|
||||
assertTrue(mySvc.fetchAllWorkChunksIterator(instanceId, true).hasNext(), "has chunk");
|
||||
|
||||
// when
|
||||
mySvc.deleteChunksAndMarkInstanceAsChunksPurged(instanceId);
|
||||
|
||||
// then
|
||||
readback = freshFetchJobInstance(instanceId);
|
||||
assertTrue(readback.isWorkChunksPurged(), "purged set");
|
||||
assertFalse(mySvc.fetchAllWorkChunksIterator(instanceId, true).hasNext(), "chunks gone");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInstanceUpdate_modifierApplied() {
|
||||
// given
|
||||
String instanceId = mySvc.storeNewInstance(createInstance());
|
||||
|
||||
// when
|
||||
mySvc.updateInstance(instanceId, instance ->{
|
||||
instance.setErrorCount(42);
|
||||
return true;
|
||||
});
|
||||
|
||||
// then
|
||||
JobInstance jobInstance = freshFetchJobInstance(instanceId);
|
||||
assertEquals(42, jobInstance.getErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInstanceUpdate_modifierNotAppliedWhenPredicateReturnsFalse() {
|
||||
// given
|
||||
JobInstance instance1 = createInstance();
|
||||
boolean initialValue = true;
|
||||
instance1.setFastTracking(initialValue);
|
||||
String instanceId = mySvc.storeNewInstance(instance1);
|
||||
|
||||
// when
|
||||
mySvc.updateInstance(instanceId, instance ->{
|
||||
instance.setFastTracking(false);
|
||||
return false;
|
||||
});
|
||||
|
||||
// then
|
||||
JobInstance jobInstance = freshFetchJobInstance(instanceId);
|
||||
assertEquals(initialValue, jobInstance.isFastTracking());
|
||||
}
|
||||
|
||||
private JobDefinition<TestJobParameters> withJobDefinition() {
|
||||
return JobDefinition.newBuilder()
|
||||
.setJobDefinitionId(JOB_DEFINITION_ID)
|
||||
public JobDefinition<TestJobParameters> withJobDefinition(boolean theIsGatedBoolean) {
|
||||
JobDefinition.Builder<TestJobParameters, ?> builder = JobDefinition.newBuilder()
|
||||
.setJobDefinitionId(theIsGatedBoolean ? GATED_JOB_DEFINITION_ID : JOB_DEFINITION_ID)
|
||||
.setJobDefinitionVersion(JOB_DEF_VER)
|
||||
.setJobDescription("A job description")
|
||||
.setParametersType(TestJobParameters.class)
|
||||
.addFirstStep(TARGET_STEP_ID, "the first step", TestJobStep2InputType.class, (theStepExecutionDetails, theDataSink) -> new RunOutcome(0))
|
||||
.addIntermediateStep("2nd-step-id", "the second step", TestJobStep3InputType.class, (theStepExecutionDetails, theDataSink) -> new RunOutcome(0))
|
||||
.addLastStep("last-step-id", "the final step", (theStepExecutionDetails, theDataSink) -> new RunOutcome(0))
|
||||
.build();
|
||||
.addLastStep("last-step-id", "the final step", (theStepExecutionDetails, theDataSink) -> new RunOutcome(0));
|
||||
if (theIsGatedBoolean) {
|
||||
builder.gatedExecution();
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void after() {
|
||||
myJobDefinitionRegistry.removeJobDefinition(JOB_DEFINITION_ID, JOB_DEF_VER);
|
||||
|
||||
// clear invocations on the batch sender from previous jobs that might be
|
||||
// kicking around
|
||||
Mockito.clearInvocations(myBatchJobSender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITestFixture getTestManager() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableMaintenanceRunner(boolean theToEnable) {
|
||||
myMaintenanceService.enableMaintenancePass(theToEnable);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class WorkChunkStorage implements IWorkChunkStorageTests {
|
||||
|
||||
@Override
|
||||
public ITestFixture getTestManager() {
|
||||
return AbstractIJobPersistenceSpecificationTest.this;
|
||||
}
|
||||
|
||||
@Nested
|
||||
class StateTransitions implements IWorkChunkStateTransitions {
|
||||
|
||||
@Override
|
||||
public ITestFixture getTestManager() {
|
||||
return AbstractIJobPersistenceSpecificationTest.this;
|
||||
}
|
||||
|
||||
@Nested
|
||||
class ErrorActions implements IWorkChunkErrorActionsTests {
|
||||
|
||||
@Override
|
||||
public ITestFixture getTestManager() {
|
||||
return AbstractIJobPersistenceSpecificationTest.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private JobInstance createInstance() {
|
||||
public JobInstance createInstance(JobDefinition<?> theJobDefinition) {
|
||||
JobDefinition<?> jobDefinition = theJobDefinition == null ? withJobDefinition(false)
|
||||
: theJobDefinition;
|
||||
if (myJobDefinitionRegistry.getJobDefinition(jobDefinition.getJobDefinitionId(), jobDefinition.getJobDefinitionVersion()).isEmpty()) {
|
||||
myJobDefinitionRegistry.addJobDefinition(jobDefinition);
|
||||
}
|
||||
|
||||
JobInstance instance = new JobInstance();
|
||||
instance.setJobDefinitionId(JOB_DEFINITION_ID);
|
||||
instance.setJobDefinitionId(jobDefinition.getJobDefinitionId());
|
||||
instance.setJobDefinitionVersion(jobDefinition.getJobDefinitionVersion());
|
||||
instance.setStatus(StatusEnum.QUEUED);
|
||||
instance.setJobDefinitionVersion(JOB_DEF_VER);
|
||||
instance.setParameters(CHUNK_DATA);
|
||||
|
@ -634,18 +170,20 @@ public abstract class AbstractIJobPersistenceSpecificationTest {
|
|||
return instance;
|
||||
}
|
||||
|
||||
private String storeWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData) {
|
||||
public String storeWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData) {
|
||||
WorkChunkCreateEvent batchWorkChunk = new WorkChunkCreateEvent(theJobDefinitionId, JOB_DEF_VER, theTargetStepId, theInstanceId, theSequence, theSerializedData);
|
||||
return mySvc.onWorkChunkCreate(batchWorkChunk);
|
||||
}
|
||||
|
||||
public abstract PlatformTransactionManager getTxManager();
|
||||
|
||||
protected abstract PlatformTransactionManager getTxManager();
|
||||
protected abstract WorkChunk freshFetchWorkChunk(String theChunkId);
|
||||
protected JobInstance freshFetchJobInstance(String theInstanceId) {
|
||||
public JobInstance freshFetchJobInstance(String theInstanceId) {
|
||||
return runInTransaction(() -> mySvc.fetchInstance(theInstanceId).orElseThrow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void runMaintenancePass();
|
||||
|
||||
public TransactionTemplate newTxTemplate() {
|
||||
TransactionTemplate retVal = new TransactionTemplate(getTxManager());
|
||||
retVal.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
|
@ -681,6 +219,39 @@ public abstract class AbstractIJobPersistenceSpecificationTest {
|
|||
await().until(() -> sw.getMillis() > 0);
|
||||
}
|
||||
|
||||
public String createAndStoreJobInstance(JobDefinition<?> theJobDefinition) {
|
||||
JobInstance jobInstance = createInstance(theJobDefinition);
|
||||
return mySvc.storeNewInstance(jobInstance);
|
||||
}
|
||||
|
||||
public String createAndDequeueWorkChunk(String theJobInstanceId) {
|
||||
String chunkId = createChunk(theJobInstanceId);
|
||||
mySvc.onWorkChunkDequeue(chunkId);
|
||||
return chunkId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract WorkChunk freshFetchWorkChunk(String theChunkId);
|
||||
|
||||
public String createChunk(String theInstanceId) {
|
||||
return storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, theInstanceId, 0, CHUNK_DATA);
|
||||
}
|
||||
|
||||
public PointcutLatch disableWorkChunkMessageHandler() {
|
||||
PointcutLatch latch = new PointcutLatch(new Exception().getStackTrace()[0].getMethodName());
|
||||
|
||||
doAnswer(a -> {
|
||||
latch.call(1);
|
||||
return Void.class;
|
||||
}).when(myBatchJobSender).sendWorkChannelMessage(any(JobWorkNotification.class));
|
||||
return latch;
|
||||
}
|
||||
|
||||
public void verifyWorkChunkMessageHandlerCalled(PointcutLatch theSendingLatch, int theNumberOfTimes) throws InterruptedException {
|
||||
theSendingLatch.awaitExpected();
|
||||
ArgumentCaptor<JobWorkNotification> notificationCaptor = ArgumentCaptor.forClass(JobWorkNotification.class);
|
||||
|
||||
verify(myBatchJobSender, times(theNumberOfTimes))
|
||||
.sendWorkChannelMessage(notificationCaptor.capture());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package ca.uhn.hapi.fhir.batch2.test;
|
||||
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkCompletionEvent;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkErrorEvent;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public interface IInProgressActionsTests extends IWorkChunkCommon, WorkChunkTestConstants {
|
||||
|
||||
@Test
|
||||
default void processingOk_inProgressToSuccess_clearsDataSavesRecordCount() {
|
||||
String jobId = getTestManager().createAndStoreJobInstance(null);
|
||||
String myChunkId = getTestManager().createAndDequeueWorkChunk(jobId);
|
||||
// execution ok
|
||||
getTestManager().getSvc().onWorkChunkCompletion(new WorkChunkCompletionEvent(myChunkId, 3, 0));
|
||||
|
||||
// verify the db was updated
|
||||
var workChunkEntity = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.COMPLETED, workChunkEntity.getStatus());
|
||||
assertNull(workChunkEntity.getData());
|
||||
assertEquals(3, workChunkEntity.getRecordsProcessed());
|
||||
assertNull(workChunkEntity.getErrorMessage());
|
||||
assertEquals(0, workChunkEntity.getErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
default void processingRetryableError_inProgressToError_bumpsCountRecordsMessage() {
|
||||
String jobId = getTestManager().createAndStoreJobInstance(null);
|
||||
String myChunkId = getTestManager().createAndDequeueWorkChunk(jobId);
|
||||
// execution had a retryable error
|
||||
getTestManager().getSvc().onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_A));
|
||||
|
||||
// verify the db was updated
|
||||
var workChunkEntity = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, workChunkEntity.getStatus());
|
||||
assertEquals(ERROR_MESSAGE_A, workChunkEntity.getErrorMessage());
|
||||
assertEquals(1, workChunkEntity.getErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
default void processingFailure_inProgressToFailed() {
|
||||
String jobId = getTestManager().createAndStoreJobInstance(null);
|
||||
String myChunkId = getTestManager().createAndDequeueWorkChunk(jobId);
|
||||
// execution had a failure
|
||||
getTestManager().getSvc().onWorkChunkFailed(myChunkId, "some error");
|
||||
|
||||
// verify the db was updated
|
||||
var workChunkEntity = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.FAILED, workChunkEntity.getStatus());
|
||||
assertEquals("some error", workChunkEntity.getErrorMessage());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package ca.uhn.hapi.fhir.batch2.test;
|
||||
|
||||
import ca.uhn.fhir.batch2.api.IJobPersistence;
|
||||
import ca.uhn.fhir.batch2.coordinator.JobDefinitionRegistry;
|
||||
import ca.uhn.fhir.batch2.maintenance.JobChunkProgressAccumulator;
|
||||
import ca.uhn.fhir.batch2.maintenance.JobInstanceProcessor;
|
||||
import ca.uhn.fhir.batch2.model.JobDefinition;
|
||||
import ca.uhn.fhir.batch2.model.JobInstance;
|
||||
import ca.uhn.fhir.batch2.model.StatusEnum;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public interface IInstanceStateTransitions extends IWorkChunkCommon, WorkChunkTestConstants {
|
||||
Logger ourLog = LoggerFactory.getLogger(IInstanceStateTransitions.class);
|
||||
|
||||
@Test
|
||||
default void testCreateInstance_firstChunkDequeued_movesToInProgress() {
|
||||
// given
|
||||
JobDefinition<?> jd = getTestManager().withJobDefinition(false);
|
||||
IJobPersistence.CreateResult createResult = getTestManager().newTxTemplate().execute(status->
|
||||
getTestManager().getSvc().onCreateWithFirstChunk(jd, "{}"));
|
||||
assertNotNull(createResult);
|
||||
|
||||
// when
|
||||
getTestManager().newTxTemplate().execute(status -> getTestManager().getSvc().onChunkDequeued(createResult.jobInstanceId));
|
||||
|
||||
// then
|
||||
JobInstance jobInstance = getTestManager().freshFetchJobInstance(createResult.jobInstanceId);
|
||||
assertThat(jobInstance.getStatus(), equalTo(StatusEnum.IN_PROGRESS));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(StatusEnum.class)
|
||||
default void cancelRequest_cancelsJob_whenNotFinalState(StatusEnum theState) {
|
||||
// given
|
||||
JobInstance cancelledInstance = createInstance();
|
||||
cancelledInstance.setStatus(theState);
|
||||
String instanceId1 = getTestManager().getSvc().storeNewInstance(cancelledInstance);
|
||||
getTestManager().getSvc().cancelInstance(instanceId1);
|
||||
|
||||
JobInstance normalInstance = createInstance();
|
||||
normalInstance.setStatus(theState);
|
||||
String instanceId2 = getTestManager().getSvc().storeNewInstance(normalInstance);
|
||||
|
||||
JobDefinitionRegistry jobDefinitionRegistry = new JobDefinitionRegistry();
|
||||
jobDefinitionRegistry.addJobDefinitionIfNotRegistered(getTestManager().withJobDefinition(false));
|
||||
|
||||
// when
|
||||
getTestManager().runInTransaction(()-> {
|
||||
new JobInstanceProcessor(
|
||||
getTestManager().getSvc(),
|
||||
null,
|
||||
instanceId1,
|
||||
new JobChunkProgressAccumulator(),
|
||||
null,
|
||||
jobDefinitionRegistry
|
||||
).process();
|
||||
});
|
||||
|
||||
// then
|
||||
JobInstance freshInstance1 = getTestManager().getSvc().fetchInstance(instanceId1).orElseThrow();
|
||||
if (theState.isCancellable()) {
|
||||
assertEquals(StatusEnum.CANCELLED, freshInstance1.getStatus(), "cancel request processed");
|
||||
assertThat(freshInstance1.getErrorMessage(), containsString("Job instance cancelled"));
|
||||
} else {
|
||||
assertEquals(theState, freshInstance1.getStatus(), "cancel request ignored - state unchanged");
|
||||
assertNull(freshInstance1.getErrorMessage(), "no error message");
|
||||
}
|
||||
JobInstance freshInstance2 = getTestManager().getSvc().fetchInstance(instanceId2).orElseThrow();
|
||||
assertEquals(theState, freshInstance2.getStatus(), "cancel request ignored - cancelled not set");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package ca.uhn.hapi.fhir.batch2.test;
|
||||
|
||||
import ca.uhn.fhir.batch2.api.IJobPersistence;
|
||||
import ca.uhn.fhir.batch2.model.JobDefinition;
|
||||
import ca.uhn.fhir.batch2.model.JobInstance;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunk;
|
||||
import ca.uhn.hapi.fhir.batch2.test.support.TestJobParameters;
|
||||
import ca.uhn.test.concurrency.PointcutLatch;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
public interface ITestFixture {
|
||||
|
||||
String createAndStoreJobInstance(JobDefinition<?> theJobDefinition);
|
||||
|
||||
String createAndDequeueWorkChunk(String theJobInstanceId);
|
||||
|
||||
WorkChunk freshFetchWorkChunk(String theChunkId);
|
||||
|
||||
String storeWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData);
|
||||
|
||||
void runInTransaction(Runnable theRunnable);
|
||||
|
||||
void sleepUntilTimeChanges();
|
||||
|
||||
JobDefinition<TestJobParameters> withJobDefinition(boolean theIsGatedJob);
|
||||
|
||||
TransactionTemplate newTxTemplate();
|
||||
|
||||
JobInstance freshFetchJobInstance(String theInstanceId);
|
||||
|
||||
void runMaintenancePass();
|
||||
|
||||
PlatformTransactionManager getTransactionManager();
|
||||
|
||||
IJobPersistence getSvc();
|
||||
|
||||
/**
|
||||
* This assumes a creation of JOB_DEFINITION already
|
||||
* @param theJobInstanceId
|
||||
* @return
|
||||
*/
|
||||
String createChunk(String theJobInstanceId);
|
||||
|
||||
/**
|
||||
* Enable/disable the maintenance runner (So it doesn't run on a scheduler)
|
||||
*/
|
||||
void enableMaintenanceRunner(boolean theToEnable);
|
||||
|
||||
/**
|
||||
* Disables the workchunk message handler
|
||||
* so that we do not actually send messages to the queue;
|
||||
* useful if mocking state transitions and we don't want to test
|
||||
* dequeuing.
|
||||
* Returns a latch that will fire each time a message is sent.
|
||||
*/
|
||||
PointcutLatch disableWorkChunkMessageHandler();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param theSendingLatch the latch sent back from the disableWorkChunkMessageHandler method above
|
||||
* @param theNumberOfTimes the number of invocations to expect
|
||||
*/
|
||||
void verifyWorkChunkMessageHandlerCalled(PointcutLatch theSendingLatch, int theNumberOfTimes) throws InterruptedException;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package ca.uhn.hapi.fhir.batch2.test;
|
||||
|
||||
import ca.uhn.fhir.batch2.model.JobInstance;
|
||||
import ca.uhn.fhir.batch2.model.StatusEnum;
|
||||
|
||||
public interface IWorkChunkCommon extends WorkChunkTestConstants {
|
||||
|
||||
/**
|
||||
* Returns the concrete class that is implementing this stuff.
|
||||
* Used primarily for structure
|
||||
*/
|
||||
ITestFixture getTestManager();
|
||||
|
||||
default JobInstance createInstance() {
|
||||
JobInstance instance = new JobInstance();
|
||||
instance.setJobDefinitionId(JOB_DEFINITION_ID);
|
||||
instance.setStatus(StatusEnum.QUEUED);
|
||||
instance.setJobDefinitionVersion(JOB_DEF_VER);
|
||||
instance.setParameters(CHUNK_DATA);
|
||||
instance.setReport("TEST");
|
||||
return instance;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package ca.uhn.hapi.fhir.batch2.test;
|
||||
|
||||
import ca.uhn.fhir.batch2.model.WorkChunk;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkCompletionEvent;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkErrorEvent;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public interface IWorkChunkErrorActionsTests extends IWorkChunkCommon, WorkChunkTestConstants {
|
||||
|
||||
|
||||
/**
|
||||
* The consumer will retry after a retryable error is thrown
|
||||
*/
|
||||
@Test
|
||||
default void errorRetry_errorToInProgress() {
|
||||
String jobId = getTestManager().createAndStoreJobInstance(null);
|
||||
String myChunkId = getTestManager().createAndDequeueWorkChunk(jobId);
|
||||
getTestManager().getSvc().onWorkChunkError(new WorkChunkErrorEvent(myChunkId, FIRST_ERROR_MESSAGE));
|
||||
|
||||
// when consumer restarts chunk
|
||||
WorkChunk chunk = getTestManager().getSvc().onWorkChunkDequeue(myChunkId).orElseThrow(IllegalArgumentException::new);
|
||||
|
||||
// then
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus());
|
||||
|
||||
// verify the db state, error message, and error count
|
||||
var workChunkEntity = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, workChunkEntity.getStatus());
|
||||
assertEquals(FIRST_ERROR_MESSAGE, workChunkEntity.getErrorMessage(), "Original error message kept");
|
||||
assertEquals(1, workChunkEntity.getErrorCount(), "error count kept");
|
||||
}
|
||||
|
||||
@Test
|
||||
default void errorRetry_repeatError_increasesErrorCount() {
|
||||
String jobId = getTestManager().createAndStoreJobInstance(null);
|
||||
String myChunkId = getTestManager().createAndDequeueWorkChunk(jobId);
|
||||
getTestManager().getSvc().onWorkChunkError(new WorkChunkErrorEvent(myChunkId, FIRST_ERROR_MESSAGE));
|
||||
|
||||
// setup - the consumer is re-trying, and marks it IN_PROGRESS
|
||||
getTestManager().getSvc().onWorkChunkDequeue(myChunkId);
|
||||
|
||||
|
||||
// when another error happens
|
||||
getTestManager().getSvc().onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_B));
|
||||
|
||||
// verify the state, new message, and error count
|
||||
var workChunkEntity = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, workChunkEntity.getStatus());
|
||||
assertEquals(ERROR_MESSAGE_B, workChunkEntity.getErrorMessage(), "new error message");
|
||||
assertEquals(2, workChunkEntity.getErrorCount(), "error count inc");
|
||||
}
|
||||
|
||||
@Test
|
||||
default void errorThenRetryAndComplete_addsErrorCounts() {
|
||||
String jobId = getTestManager().createAndStoreJobInstance(null);
|
||||
String myChunkId = getTestManager().createAndDequeueWorkChunk(jobId);
|
||||
getTestManager().getSvc().onWorkChunkError(new WorkChunkErrorEvent(myChunkId, FIRST_ERROR_MESSAGE));
|
||||
|
||||
// setup - the consumer is re-trying, and marks it IN_PROGRESS
|
||||
getTestManager().getSvc().onWorkChunkDequeue(myChunkId);
|
||||
|
||||
// then it completes ok.
|
||||
getTestManager().getSvc().onWorkChunkCompletion(new WorkChunkCompletionEvent(myChunkId, 3, 1));
|
||||
|
||||
// verify the state, new message, and error count
|
||||
var workChunkEntity = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.COMPLETED, workChunkEntity.getStatus());
|
||||
assertEquals(FIRST_ERROR_MESSAGE, workChunkEntity.getErrorMessage(), "Error message kept.");
|
||||
assertEquals(2, workChunkEntity.getErrorCount(), "error combined with earlier error");
|
||||
}
|
||||
|
||||
@Test
|
||||
default void errorRetry_maxErrors_movesToFailed() {
|
||||
// we start with 1 error already
|
||||
String jobId = getTestManager().createAndStoreJobInstance(null);
|
||||
String myChunkId = getTestManager().createAndDequeueWorkChunk(jobId);
|
||||
getTestManager().getSvc().onWorkChunkError(new WorkChunkErrorEvent(myChunkId, FIRST_ERROR_MESSAGE));
|
||||
|
||||
// 2nd try
|
||||
getTestManager().getSvc().onWorkChunkDequeue(myChunkId);
|
||||
getTestManager().getSvc().onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_B));
|
||||
var chunk = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, chunk.getStatus());
|
||||
assertEquals(2, chunk.getErrorCount());
|
||||
|
||||
// 3rd try
|
||||
getTestManager().getSvc().onWorkChunkDequeue(myChunkId);
|
||||
getTestManager().getSvc().onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_B));
|
||||
chunk = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.ERRORED, chunk.getStatus());
|
||||
assertEquals(3, chunk.getErrorCount());
|
||||
|
||||
// 4th try
|
||||
getTestManager().getSvc().onWorkChunkDequeue(myChunkId);
|
||||
getTestManager().getSvc().onWorkChunkError(new WorkChunkErrorEvent(myChunkId, ERROR_MESSAGE_C));
|
||||
chunk = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.FAILED, chunk.getStatus());
|
||||
assertEquals(4, chunk.getErrorCount());
|
||||
assertThat("Error message contains last error", chunk.getErrorMessage(), containsString(ERROR_MESSAGE_C));
|
||||
assertThat("Error message contains error count and complaint", chunk.getErrorMessage(), containsString("many errors: 4"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package ca.uhn.hapi.fhir.batch2.test;
|
||||
|
||||
import ca.uhn.fhir.batch2.model.WorkChunk;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum;
|
||||
import ca.uhn.test.concurrency.PointcutLatch;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public interface IWorkChunkStateTransitions extends IWorkChunkCommon, WorkChunkTestConstants {
|
||||
|
||||
Logger ourLog = LoggerFactory.getLogger(IWorkChunkStateTransitions.class);
|
||||
|
||||
@Test
|
||||
default void chunkReceived_queuedToInProgress() throws InterruptedException {
|
||||
String jobInstanceId = getTestManager().createAndStoreJobInstance(null);
|
||||
String myChunkId = getTestManager().createChunk(jobInstanceId);
|
||||
|
||||
getTestManager().runMaintenancePass();
|
||||
// the worker has received the chunk, and marks it started.
|
||||
WorkChunk chunk = getTestManager().getSvc().onWorkChunkDequeue(myChunkId).orElseThrow(IllegalArgumentException::new);
|
||||
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus());
|
||||
assertEquals(CHUNK_DATA, chunk.getData());
|
||||
|
||||
// verify the db was updated too
|
||||
WorkChunk fetchedWorkChunk = getTestManager().freshFetchWorkChunk(myChunkId);
|
||||
assertEquals(WorkChunkStatusEnum.IN_PROGRESS, fetchedWorkChunk.getStatus());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package ca.uhn.hapi.fhir.batch2.test;
|
||||
|
||||
import ca.uhn.fhir.batch2.model.JobInstance;
|
||||
import ca.uhn.fhir.batch2.model.WorkChunk;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public interface IWorkChunkStorageTests extends IWorkChunkCommon, WorkChunkTestConstants {
|
||||
|
||||
@Test
|
||||
default void testStoreAndFetchWorkChunk_NoData() {
|
||||
JobInstance instance = createInstance();
|
||||
String instanceId = getTestManager().getSvc().storeNewInstance(instance);
|
||||
|
||||
String id = getTestManager().storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 0, null);
|
||||
|
||||
getTestManager().runInTransaction(() -> {
|
||||
WorkChunk chunk = getTestManager().freshFetchWorkChunk(id);
|
||||
assertNull(chunk.getData());
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package ca.uhn.hapi.fhir.batch2.test;
|
||||
|
||||
public interface WorkChunkTestConstants {
|
||||
public static final String JOB_DEFINITION_ID = "definition-id";
|
||||
// we use a separate id for gated jobs because these job definitions might not
|
||||
// be cleaned up after any given test run
|
||||
String GATED_JOB_DEFINITION_ID = "gated_job_def_id";
|
||||
public static final String TARGET_STEP_ID = "step-id";
|
||||
public static final String DEF_CHUNK_ID = "definition-chunkId";
|
||||
public static final int JOB_DEF_VER = 1;
|
||||
public static final int SEQUENCE_NUMBER = 1;
|
||||
public static final String CHUNK_DATA = "{\"key\":\"value\"}";
|
||||
public static final String ERROR_MESSAGE_A = "This is an error message: A";
|
||||
public static final String ERROR_MESSAGE_B = "This is a different error message: B";
|
||||
public static final String ERROR_MESSAGE_C = "This is a different error message: C";
|
||||
|
||||
String FIRST_ERROR_MESSAGE = ERROR_MESSAGE_A;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package ca.uhn.hapi.fhir.batch2.test.configs;
|
||||
|
||||
import ca.uhn.fhir.batch2.channel.BatchJobSender;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
/**
|
||||
* Provides spying overrides of beans we want to spy on.
|
||||
*
|
||||
* We spy the BatchJobSender so we can test state transitions without
|
||||
* actually sending messages onto the queue
|
||||
*/
|
||||
@Configuration
|
||||
public class SpyOverrideConfig {
|
||||
@Autowired
|
||||
BatchJobSender myRealJobSender;
|
||||
|
||||
@Primary
|
||||
@Bean
|
||||
public BatchJobSender batchJobSenderSpy() {
|
||||
return spy(myRealJobSender);
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -36,4 +36,11 @@ public interface IJobMaintenanceService {
|
|||
*/
|
||||
@VisibleForTesting
|
||||
void forceMaintenancePass();
|
||||
|
||||
/**
|
||||
* This is only to be called in a testing environment
|
||||
* to ensure state changes are controlled.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
void enableMaintenancePass(boolean thetoEnable);
|
||||
}
|
||||
|
|
|
@ -97,6 +97,8 @@ public class JobMaintenanceServiceImpl implements IJobMaintenanceService, IHasSc
|
|||
private Runnable myMaintenanceJobFinishedCallback = () -> {};
|
||||
private final IReductionStepExecutorService myReductionStepExecutorService;
|
||||
|
||||
private boolean myEnabledBool = true;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -196,8 +198,17 @@ public class JobMaintenanceServiceImpl implements IJobMaintenanceService, IHasSc
|
|||
doMaintenancePass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableMaintenancePass(boolean theToEnable) {
|
||||
myEnabledBool = theToEnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runMaintenancePass() {
|
||||
if (!myEnabledBool) {
|
||||
ourLog.error("Maintenance job is disabled! This will affect all batch2 jobs!");
|
||||
}
|
||||
|
||||
if (!myRunMaintenanceSemaphore.tryAcquire()) {
|
||||
ourLog.debug("Another maintenance pass is already in progress. Ignoring request.");
|
||||
return;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -9,7 +9,7 @@
|
|||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<name>HAPI-FHIR</name>
|
||||
<description>An open-source implementation of the FHIR specification in Java.</description>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>7.1.7-SNAPSHOT</version>
|
||||
<version>7.1.8-SNAPSHOT</version>
|
||||
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
|
Loading…
Reference in New Issue