diff --git a/enrollment-server-onboarding-common/pom.xml b/enrollment-server-onboarding-common/pom.xml
index 09f6359c5..d6d88b13e 100644
--- a/enrollment-server-onboarding-common/pom.xml
+++ b/enrollment-server-onboarding-common/pom.xml
@@ -61,6 +61,12 @@
spring-boot-starter-test
test
+
+
+ com.h2database
+ h2
+ test
+
diff --git a/enrollment-server-onboarding-common/src/main/java/com/wultra/app/onboardingserver/common/database/DocumentResultRepository.java b/enrollment-server-onboarding-common/src/main/java/com/wultra/app/onboardingserver/common/database/DocumentResultRepository.java
index cb0eab250..fdcc339ba 100644
--- a/enrollment-server-onboarding-common/src/main/java/com/wultra/app/onboardingserver/common/database/DocumentResultRepository.java
+++ b/enrollment-server-onboarding-common/src/main/java/com/wultra/app/onboardingserver/common/database/DocumentResultRepository.java
@@ -40,18 +40,20 @@ public interface DocumentResultRepository extends CrudRepository streamAllInProgressDocumentSubmits();
+ Stream streamAllInProgressDocumentSubmits(String providerName);
/**
* @return All not finished document submit verifications (upload is in progress and verification id exists)
*/
@Query("SELECT doc FROM DocumentResultEntity doc WHERE" +
" doc.documentVerification.status = com.wultra.app.enrollmentserver.model.enumeration.DocumentStatus.UPLOAD_IN_PROGRESS" +
+ " AND doc.documentVerification.providerName = :providerName " +
" AND doc.documentVerification.verificationId IS NOT NULL" +
" ORDER BY doc.timestampCreated ASC")
- Stream streamAllInProgressDocumentSubmitVerifications();
+ Stream streamAllInProgressDocumentSubmitVerifications(String providerName);
/**
* @return All document results for the specified document verification and processing phase
diff --git a/enrollment-server-onboarding-common/src/test/java/com/wultra/app/onboardingserver/common/EnrollmentServerOnboardingCommonTestApplication.java b/enrollment-server-onboarding-common/src/test/java/com/wultra/app/onboardingserver/common/EnrollmentServerOnboardingCommonTestApplication.java
new file mode 100644
index 000000000..437b51434
--- /dev/null
+++ b/enrollment-server-onboarding-common/src/test/java/com/wultra/app/onboardingserver/common/EnrollmentServerOnboardingCommonTestApplication.java
@@ -0,0 +1,24 @@
+/*
+ * PowerAuth Enrollment Server
+ * Copyright (C) 2023 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package com.wultra.app.onboardingserver.common;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class EnrollmentServerOnboardingCommonTestApplication {
+}
diff --git a/enrollment-server-onboarding-common/src/test/java/com/wultra/app/onboardingserver/common/database/DocumentResultRepositoryTest.java b/enrollment-server-onboarding-common/src/test/java/com/wultra/app/onboardingserver/common/database/DocumentResultRepositoryTest.java
new file mode 100644
index 000000000..c95706d24
--- /dev/null
+++ b/enrollment-server-onboarding-common/src/test/java/com/wultra/app/onboardingserver/common/database/DocumentResultRepositoryTest.java
@@ -0,0 +1,65 @@
+/*
+ * PowerAuth Enrollment Server
+ * Copyright (C) 2023 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package com.wultra.app.onboardingserver.common.database;
+
+
+import com.wultra.app.onboardingserver.common.database.entity.DocumentResultEntity;
+import com.wultra.app.onboardingserver.common.database.entity.DocumentVerificationEntity;
+import jakarta.transaction.Transactional;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.jdbc.Sql;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test for {@link DocumentResultRepository}.
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@DataJpaTest
+@ActiveProfiles("test")
+@Transactional
+class DocumentResultRepositoryTest {
+
+ @Autowired
+ private DocumentResultRepository tested;
+
+ @Test
+ @Sql
+ void testStreamAllInProgressDocumentSubmits() {
+ assertThat(tested.streamAllInProgressDocumentSubmits("mock"))
+ .extracting(DocumentResultEntity::getDocumentVerification)
+ .extracting(DocumentVerificationEntity::getProviderName)
+ .containsOnly("mock")
+ .hasSize(1);
+ }
+
+ @Test
+ @Sql
+ void testStreamAllInProgressDocumentSubmitVerifications() {
+ assertThat(tested.streamAllInProgressDocumentSubmitVerifications("mock"))
+ .extracting(DocumentResultEntity::getDocumentVerification)
+ .extracting(DocumentVerificationEntity::getProviderName)
+ .containsOnly("mock")
+ .hasSize(1);
+ }
+
+}
diff --git a/enrollment-server-onboarding-common/src/test/resources/application-test.properties b/enrollment-server-onboarding-common/src/test/resources/application-test.properties
new file mode 100644
index 000000000..308c2b3ac
--- /dev/null
+++ b/enrollment-server-onboarding-common/src/test/resources/application-test.properties
@@ -0,0 +1,5 @@
+spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
+spring.datasource.username=sa
+spring.datasource.password=password
+spring.datasource.driver-class-name=org.h2.Driver
+spring.jpa.hibernate.ddl-auto=create
diff --git a/enrollment-server-onboarding-common/src/test/resources/com/wultra/app/onboardingserver/common/database/DocumentResultRepositoryTest.testStreamAllInProgressDocumentSubmitVerifications.sql b/enrollment-server-onboarding-common/src/test/resources/com/wultra/app/onboardingserver/common/database/DocumentResultRepositoryTest.testStreamAllInProgressDocumentSubmitVerifications.sql
new file mode 100644
index 000000000..a6affd76d
--- /dev/null
+++ b/enrollment-server-onboarding-common/src/test/resources/com/wultra/app/onboardingserver/common/database/DocumentResultRepositoryTest.testStreamAllInProgressDocumentSubmitVerifications.sql
@@ -0,0 +1,12 @@
+-- Documents that have been already submitted and data were extracted (multiple providers).
+INSERT INTO es_identity_verification(id, activation_id, user_id, process_id, status, phase, timestamp_created, timestamp_last_updated) VALUES
+('v3', 'a3', 'u3', 'p3', 'IN_PROGRESS', 'DOCUMENT_UPLOAD', now(), now()),
+('v4', 'a4', 'u4', 'p4', 'IN_PROGRESS', 'DOCUMENT_UPLOAD', now(), now());
+
+INSERT INTO es_document_verification(id, provider_name, activation_id, identity_verification_id, verification_id, type, status, filename, used_for_verification, timestamp_created, timestamp_last_updated) VALUES
+ ('d3', 'foreign', 'a3', 'v3', 'verification1', 'ID_CARD', 'UPLOAD_IN_PROGRESS', 'f3', true, now(), now()),
+ ('d4', 'mock', 'a4', 'v4', 'verification2', 'ID_CARD', 'UPLOAD_IN_PROGRESS', 'f4', true, now(), now());
+
+INSERT INTO es_document_result(id, document_verification_id, phase, extracted_data, timestamp_created) VALUES
+ (3, 'd3', 'UPLOAD', '{extracted_data}', now()),
+ (4, 'd4', 'UPLOAD', '{extracted_data}', now());
diff --git a/enrollment-server-onboarding-common/src/test/resources/com/wultra/app/onboardingserver/common/database/DocumentResultRepositoryTest.testStreamAllInProgressDocumentSubmits.sql b/enrollment-server-onboarding-common/src/test/resources/com/wultra/app/onboardingserver/common/database/DocumentResultRepositoryTest.testStreamAllInProgressDocumentSubmits.sql
new file mode 100644
index 000000000..e32e438eb
--- /dev/null
+++ b/enrollment-server-onboarding-common/src/test/resources/com/wultra/app/onboardingserver/common/database/DocumentResultRepositoryTest.testStreamAllInProgressDocumentSubmits.sql
@@ -0,0 +1,12 @@
+-- Documents that have not been submitted yet (multiple providers).
+INSERT INTO es_identity_verification(id, activation_id, user_id, process_id, status, phase, timestamp_created, timestamp_last_updated) VALUES
+ ('v1', 'a1', 'u1', 'p1', 'IN_PROGRESS', 'DOCUMENT_UPLOAD', now(), now()),
+ ('v2', 'a2', 'u2', 'p2', 'IN_PROGRESS', 'DOCUMENT_UPLOAD', now(), now());
+
+INSERT INTO es_document_verification(id, provider_name, activation_id, identity_verification_id, type, status, filename, used_for_verification, timestamp_created, timestamp_last_updated) VALUES
+ ('d1', 'foreign', 'a1', 'v1', 'ID_CARD', 'UPLOAD_IN_PROGRESS', 'f1', true, now(), now()),
+ ('d2', 'mock', 'a2', 'v2', 'ID_CARD', 'UPLOAD_IN_PROGRESS', 'f2', true, now(), now());
+
+INSERT INTO es_document_result(id, document_verification_id, phase, timestamp_created) VALUES
+ (1, 'd1', 'UPLOAD', now()),
+ (2, 'd2', 'UPLOAD', now());
diff --git a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/document/DocumentProcessingBatchService.java b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/document/DocumentProcessingBatchService.java
index cb3cda261..2ffb2e34a 100644
--- a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/document/DocumentProcessingBatchService.java
+++ b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/document/DocumentProcessingBatchService.java
@@ -22,6 +22,8 @@
import com.wultra.app.onboardingserver.common.database.entity.DocumentVerificationEntity;
import com.wultra.app.enrollmentserver.model.enumeration.DocumentStatus;
import com.wultra.app.enrollmentserver.model.integration.OwnerId;
+import com.wultra.app.onboardingserver.configuration.IdentityVerificationConfig;
+import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,6 +39,7 @@
* @author Lukas Lukovsky, lukas.lukovsky@wultra.com
*/
@Service
+@AllArgsConstructor
public class DocumentProcessingBatchService {
private static final Logger logger = LoggerFactory.getLogger(DocumentProcessingBatchService.class);
@@ -45,18 +48,7 @@ public class DocumentProcessingBatchService {
private final DocumentProcessingService documentProcessingService;
- /**
- * Service constructor.
- * @param documentResultRepository Document verification result repository.
- * @param documentProcessingService Document processing service.
- */
- @Autowired
- public DocumentProcessingBatchService(
- DocumentResultRepository documentResultRepository,
- DocumentProcessingService documentProcessingService) {
- this.documentResultRepository = documentResultRepository;
- this.documentProcessingService = documentProcessingService;
- }
+ private final IdentityVerificationConfig identityVerificationConfig;
/**
* Checks in progress document submits on current provider status and data result
@@ -64,7 +56,7 @@ public DocumentProcessingBatchService(
@Transactional
public void checkInProgressDocumentSubmits() {
AtomicInteger countFinished = new AtomicInteger(0);
- try (Stream stream = documentResultRepository.streamAllInProgressDocumentSubmits()) {
+ try (Stream stream = documentResultRepository.streamAllInProgressDocumentSubmits(identityVerificationConfig.getDocumentVerificationProvider())) {
stream.forEach(docResult -> {
DocumentVerificationEntity docVerification = docResult.getDocumentVerification();
final OwnerId ownerId = new OwnerId();
diff --git a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/verification/VerificationProcessingBatchService.java b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/verification/VerificationProcessingBatchService.java
index fb6282b5f..34672929b 100644
--- a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/verification/VerificationProcessingBatchService.java
+++ b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/verification/VerificationProcessingBatchService.java
@@ -31,8 +31,10 @@
import com.wultra.app.onboardingserver.common.service.AuditService;
import com.wultra.app.onboardingserver.common.service.CommonOnboardingService;
import com.wultra.app.onboardingserver.api.errorhandling.DocumentVerificationException;
+import com.wultra.app.onboardingserver.configuration.IdentityVerificationConfig;
import com.wultra.app.onboardingserver.impl.service.IdentityVerificationService;
import com.wultra.app.onboardingserver.api.provider.DocumentVerificationProvider;
+import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -49,6 +51,7 @@
* @author Lukas Lukovsky, lukas.lukovsky@wultra.com
*/
@Service
+@AllArgsConstructor
public class VerificationProcessingBatchService {
private static final Logger logger = LoggerFactory.getLogger(VerificationProcessingBatchService.class);
@@ -67,34 +70,7 @@ public class VerificationProcessingBatchService {
private final CommonOnboardingService commonOnboardingService;
- /**
- * Service constructor.
- * @param documentResultRepository Document verification result repository.
- * @param documentVerificationProvider Document verification provider.
- * @param identityVerificationRepository Identity verification repository.
- * @param identityVerificationService Identity verification service.
- * @param verificationProcessingService Verification processing service.
- * @param auditService Audit service.
- * @param commonOnboardingService Onboarding process service (common).
- */
- @Autowired
- public VerificationProcessingBatchService(
- final DocumentResultRepository documentResultRepository,
- final DocumentVerificationProvider documentVerificationProvider,
- final IdentityVerificationRepository identityVerificationRepository,
- final IdentityVerificationService identityVerificationService,
- final VerificationProcessingService verificationProcessingService,
- final AuditService auditService,
- final CommonOnboardingService commonOnboardingService) {
-
- this.documentResultRepository = documentResultRepository;
- this.identityVerificationRepository = identityVerificationRepository;
- this.documentVerificationProvider = documentVerificationProvider;
- this.identityVerificationService = identityVerificationService;
- this.verificationProcessingService = verificationProcessingService;
- this.auditService = auditService;
- this.commonOnboardingService = commonOnboardingService;
- }
+ private final IdentityVerificationConfig identityVerificationConfig;
/**
* Checks document submit verifications
@@ -102,7 +78,7 @@ public VerificationProcessingBatchService(
@Transactional
public void checkDocumentSubmitVerifications() {
AtomicInteger countFinished = new AtomicInteger(0);
- try (Stream stream = documentResultRepository.streamAllInProgressDocumentSubmitVerifications()) {
+ try (Stream stream = documentResultRepository.streamAllInProgressDocumentSubmitVerifications(identityVerificationConfig.getDocumentVerificationProvider())) {
stream.forEach(docResult -> {
DocumentVerificationEntity docVerification = docResult.getDocumentVerification();
diff --git a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/statemachine/service/StateMachineService.java b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/statemachine/service/StateMachineService.java
index b871dc4fe..5b1357537 100644
--- a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/statemachine/service/StateMachineService.java
+++ b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/statemachine/service/StateMachineService.java
@@ -19,6 +19,7 @@
import com.wultra.app.enrollmentserver.model.integration.OwnerId;
import com.wultra.app.onboardingserver.common.database.entity.IdentityVerificationEntity;
import com.wultra.app.onboardingserver.common.errorhandling.IdentityVerificationException;
+import com.wultra.app.onboardingserver.configuration.IdentityVerificationConfig;
import com.wultra.app.onboardingserver.impl.service.IdentityVerificationService;
import com.wultra.app.onboardingserver.statemachine.EnrollmentStateProvider;
import com.wultra.app.onboardingserver.statemachine.consts.EventHeaderName;
@@ -27,6 +28,7 @@
import com.wultra.app.onboardingserver.statemachine.enums.OnboardingState;
import com.wultra.app.onboardingserver.statemachine.interceptor.CustomStateMachineInterceptor;
import jakarta.annotation.Nullable;
+import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.messaging.Message;
@@ -53,6 +55,7 @@
*/
@Service
@Slf4j
+@AllArgsConstructor
@ConditionalOnProperty(value = "enrollment-server-onboarding.identity-verification.enabled", havingValue = "true")
public class StateMachineService {
@@ -66,27 +69,7 @@ public class StateMachineService {
private final TransactionTemplate transactionTemplate;
- /**
- * Constructor.
- *
- * @param enrollmentStateProvider Enrollment state provider.
- * @param stateMachineFactory State machine factory.
- * @param stateMachineInterceptor State machine interceptor.
- * @param identityVerificationService Identity verification service.
- */
- public StateMachineService(
- final EnrollmentStateProvider enrollmentStateProvider,
- final StateMachineFactory stateMachineFactory,
- final CustomStateMachineInterceptor stateMachineInterceptor,
- final IdentityVerificationService identityVerificationService,
- final TransactionTemplate transactionTemplate
- ) {
- this.enrollmentStateProvider = enrollmentStateProvider;
- this.stateMachineFactory = stateMachineFactory;
- this.stateMachineInterceptor = stateMachineInterceptor;
- this.identityVerificationService = identityVerificationService;
- this.transactionTemplate = transactionTemplate;
- }
+ private final IdentityVerificationConfig identityVerificationConfig;
@Transactional
public StateMachine processStateMachineEvent(OwnerId ownerId, String processId, OnboardingEvent event)
@@ -144,23 +127,25 @@ public Message createMessage(OwnerId ownerId, String processId,
public void changeMachineStatesInBatch() {
final AtomicInteger countFinished = new AtomicInteger(0);
try (Stream stream = identityVerificationService.streamAllIdentityVerificationsToChangeState().parallel()) {
- stream.forEach(identityVerification -> {
- final String processId = identityVerification.getProcessId();
- final OwnerId ownerId = new OwnerId();
- ownerId.setActivationId(identityVerification.getActivationId());
- ownerId.setUserId(identityVerification.getUserId());
- logger.debug("Changing state of machine for process ID: {}", processId);
-
- transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
- transactionTemplate.executeWithoutResult(status -> {
- try {
- processStateMachineEvent(ownerId, processId, OnboardingEvent.EVENT_NEXT_STATE);
- countFinished.incrementAndGet();
- } catch (IdentityVerificationException e) {
- logger.warn("Unable to change state for process ID: {}", processId, e);
- }
- });
- });
+ stream.filter(identityVerification -> identityVerification.getDocumentVerifications().stream()
+ .anyMatch(doc -> identityVerificationConfig.getDocumentVerificationProvider().equals(doc.getProviderName())))
+ .forEach(identityVerification -> {
+ final String processId = identityVerification.getProcessId();
+ final OwnerId ownerId = new OwnerId();
+ ownerId.setActivationId(identityVerification.getActivationId());
+ ownerId.setUserId(identityVerification.getUserId());
+ logger.debug("Changing state of machine for process ID: {}", processId);
+
+ transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
+ transactionTemplate.executeWithoutResult(status -> {
+ try {
+ processStateMachineEvent(ownerId, processId, OnboardingEvent.EVENT_NEXT_STATE);
+ countFinished.incrementAndGet();
+ } catch (IdentityVerificationException e) {
+ logger.warn("Unable to change state for process ID: {}", processId, e);
+ }
+ });
+ });
}
if (countFinished.get() > 0) {
logger.debug("Changed state of {} identity verifications", countFinished.get());
diff --git a/enrollment-server-onboarding/src/test/java/com/wultra/app/onboardingserver/impl/service/PresenceCheckServiceTest.java b/enrollment-server-onboarding/src/test/java/com/wultra/app/onboardingserver/impl/service/PresenceCheckServiceTest.java
index c256c6d5d..93ea22fbe 100644
--- a/enrollment-server-onboarding/src/test/java/com/wultra/app/onboardingserver/impl/service/PresenceCheckServiceTest.java
+++ b/enrollment-server-onboarding/src/test/java/com/wultra/app/onboardingserver/impl/service/PresenceCheckServiceTest.java
@@ -18,34 +18,23 @@
import com.wultra.app.enrollmentserver.model.enumeration.CardSide;
import com.wultra.app.enrollmentserver.model.enumeration.DocumentType;
-import com.wultra.app.enrollmentserver.model.enumeration.IdentityVerificationPhase;
-import com.wultra.app.enrollmentserver.model.enumeration.IdentityVerificationStatus;
import com.wultra.app.enrollmentserver.model.integration.Image;
import com.wultra.app.enrollmentserver.model.integration.OwnerId;
import com.wultra.app.enrollmentserver.model.integration.SessionInfo;
import com.wultra.app.onboardingserver.EnrollmentServerTestApplication;
import com.wultra.app.onboardingserver.api.provider.PresenceCheckProvider;
import com.wultra.app.onboardingserver.common.database.DocumentVerificationRepository;
-import com.wultra.app.onboardingserver.common.database.IdentityVerificationRepository;
-import com.wultra.app.onboardingserver.common.database.ScaResultRepository;
import com.wultra.app.onboardingserver.common.database.entity.DocumentVerificationEntity;
import com.wultra.app.onboardingserver.common.database.entity.IdentityVerificationEntity;
-import com.wultra.app.onboardingserver.impl.service.internal.JsonSerializationService;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import java.util.List;
import java.util.Optional;
-import static com.wultra.app.enrollmentserver.model.enumeration.IdentityVerificationPhase.DOCUMENT_VERIFICATION_FINAL;
import static com.wultra.app.enrollmentserver.model.enumeration.IdentityVerificationPhase.PRESENCE_CHECK;
import static com.wultra.app.enrollmentserver.model.enumeration.IdentityVerificationStatus.*;
import static org.junit.jupiter.api.Assertions.assertTrue;
diff --git a/enrollment-server-onboarding/src/test/java/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.java b/enrollment-server-onboarding/src/test/java/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.java
new file mode 100644
index 000000000..9972b40bd
--- /dev/null
+++ b/enrollment-server-onboarding/src/test/java/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.java
@@ -0,0 +1,70 @@
+/*
+ * PowerAuth Enrollment Server
+ * Copyright (C) 2023 Wultra s.r.o.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package com.wultra.app.onboardingserver.statemachine.service;
+
+import com.wultra.app.enrollmentserver.model.enumeration.IdentityVerificationStatus;
+import com.wultra.app.onboardingserver.EnrollmentServerTestApplication;
+import com.wultra.app.onboardingserver.common.database.IdentityVerificationRepository;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.jdbc.Sql;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Test for {@link StateMachineService}
+ *
+ * @author Jan Pesek, jan.pesek@wultra.com
+ */
+@SpringBootTest(classes = EnrollmentServerTestApplication.class)
+@ActiveProfiles("test")
+class StateMachineServiceTest {
+
+ @Autowired
+ private StateMachineService tested;
+
+ @Autowired
+ private IdentityVerificationRepository repository;
+
+ @Test
+ @Sql
+ void testChangeMachineStatesInBatch() {
+ tested.changeMachineStatesInBatch();
+
+ assertEquals(IdentityVerificationStatus.VERIFICATION_PENDING, repository.findById("v1").get().getStatus());
+ }
+
+ @Test
+ @Sql
+ void testChangeMachineStatesInBatch_submitting() {
+ tested.changeMachineStatesInBatch();
+
+ assertEquals(IdentityVerificationStatus.IN_PROGRESS, repository.findById("v2").get().getStatus());
+ }
+
+ @Test
+ @Sql
+ void testChangeMachineStatesInBatch_noDocuments() {
+ tested.changeMachineStatesInBatch();
+
+ assertEquals(IdentityVerificationStatus.IN_PROGRESS, repository.findById("v3").get().getStatus());
+ }
+
+}
diff --git a/enrollment-server-onboarding/src/test/resources/application-test.properties b/enrollment-server-onboarding/src/test/resources/application-test.properties
index 50a2b529f..5dff6a04e 100644
--- a/enrollment-server-onboarding/src/test/resources/application-test.properties
+++ b/enrollment-server-onboarding/src/test/resources/application-test.properties
@@ -24,3 +24,5 @@ spring.jpa.hibernate.ddl-auto=create
spring.liquibase.enabled=false
enrollment-server-onboarding.identity-verification.enabled=true
+enrollment-server-onboarding.document-verification.provider=mock
+
diff --git a/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.testChangeMachineStatesInBatch.sql b/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.testChangeMachineStatesInBatch.sql
new file mode 100644
index 000000000..740d005e4
--- /dev/null
+++ b/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.testChangeMachineStatesInBatch.sql
@@ -0,0 +1,6 @@
+INSERT INTO es_identity_verification(id, activation_id, user_id, process_id, status, phase, timestamp_created, timestamp_last_updated) VALUES
+ ('v1', 'a1', 'u1', 'p1', 'IN_PROGRESS', 'DOCUMENT_UPLOAD', now(), now());
+
+-- document already submitted to 'mock' provider
+INSERT INTO es_document_verification(id, activation_id, identity_verification_id, type, provider_name, status, filename, used_for_verification, timestamp_created, timestamp_last_updated) VALUES
+ ('doc1', 'a1', 'v1', 'ID_CARD', 'mock', 'VERIFICATION_PENDING', 'f2', true, now(), now());
diff --git a/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.testChangeMachineStatesInBatch_noDocuments.sql b/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.testChangeMachineStatesInBatch_noDocuments.sql
new file mode 100644
index 000000000..fb63b4bdf
--- /dev/null
+++ b/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.testChangeMachineStatesInBatch_noDocuments.sql
@@ -0,0 +1,4 @@
+INSERT INTO es_identity_verification(id, activation_id, user_id, process_id, status, phase, timestamp_created, timestamp_last_updated) VALUES
+ ('v3', 'a3', 'u3', 'p3', 'IN_PROGRESS', 'DOCUMENT_UPLOAD', now(), now());
+
+-- no documents submitted yet
diff --git a/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.testChangeMachineStatesInBatch_submitting.sql b/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.testChangeMachineStatesInBatch_submitting.sql
new file mode 100644
index 000000000..5cf138318
--- /dev/null
+++ b/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/statemachine/service/StateMachineServiceTest.testChangeMachineStatesInBatch_submitting.sql
@@ -0,0 +1,6 @@
+INSERT INTO es_identity_verification(id, activation_id, user_id, process_id, status, phase, timestamp_created, timestamp_last_updated) VALUES
+ ('v2', 'a2', 'u2', 'p2', 'IN_PROGRESS', 'DOCUMENT_UPLOAD', now(), now());
+
+-- document is being submitted to a provider
+INSERT INTO es_document_verification(id, activation_id, identity_verification_id, type, provider_name, status, filename, used_for_verification, timestamp_created, timestamp_last_updated) VALUES
+ ('doc2', 'a2', 'v2', 'ID_CARD', null, 'UPLOAD_IN_PROGRESS', 'f1', true, now(), now());