diff --git a/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java index 61876bd402f13ce74003c41efe440aca9fa4165b..4e0940d8a4cd12dc6acf8970c7cae612e4aac9be 100644 --- a/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java +++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/Command.java @@ -44,6 +44,7 @@ public interface Command { public String getCreatedBy(); public String getCreatedByName(); public CommandStatus getStatus(); + String getCreatedByClientName(); public Map<String, Object> getBodyObject(); public Map<String, String> getBody(); diff --git a/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangLockedEvent.java b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangLockedEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..e7c08bc4538b8cc2bc93d1489a1609ab927dc0b9 --- /dev/null +++ b/vorgang-manager-command/src/main/java/de/ozgcloud/command/VorgangLockedEvent.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.command; + +public class VorgangLockedEvent extends CommandExecutedEvent { + + public VorgangLockedEvent(Command command) { + super(command); + } +} diff --git a/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java b/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java index 3ebddf936e18f8c1576ca81400a5a93cd1f7ec07..98a46f1f9f5423cf0b04d51e208e985dfaa607d7 100644 --- a/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java +++ b/vorgang-manager-command/src/test/java/de/ozgcloud/command/TestCommand.java @@ -21,6 +21,7 @@ public class TestCommand implements Command { private ZonedDateTime finishedAt; private String createdBy; private String createdByName; + private String createdByClientName; private CommandStatus status; diff --git a/vorgang-manager-interface/src/main/protobuf/vorgang.model.proto b/vorgang-manager-interface/src/main/protobuf/vorgang.model.proto index b1c4bad8c989562a34bd0f821ed472b28a0cebcf..5f9efe1e4c9399cf8eecada3d7a23b1e89909f02 100644 --- a/vorgang-manager-interface/src/main/protobuf/vorgang.model.proto +++ b/vorgang-manager-interface/src/main/protobuf/vorgang.model.proto @@ -63,6 +63,13 @@ message GrpcVorgangWithEingang { message GrpcVorgangHead { GrpcServiceKonto serviceKonto = 1; + GrpcLock lock = 2; +} + +message GrpcLock { + string clientName = 1; + string lockedSince = 2; + string reason = 3; } message GrpcEingang { diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java index ff7653e640230c195b26595b3b50c0589f305303..7ff69bdda006fb2d969558ea1f60dc7cc23f99e3 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/CommandService.java @@ -54,6 +54,7 @@ import de.ozgcloud.vorgang.callcontext.CurrentUserService; import de.ozgcloud.vorgang.callcontext.User; import de.ozgcloud.vorgang.common.errorhandling.NotFoundException; import de.ozgcloud.vorgang.common.errorhandling.RevokeFailedException; +import de.ozgcloud.vorgang.vorgang.VorgangService; import lombok.NonNull; @Service @@ -65,15 +66,24 @@ public class CommandService { @Autowired private ApplicationEventPublisher publisher; + @Autowired + private VorgangService vorgangService; @Autowired private CurrentUserService userService; public Command createCommand(CreateCommandRequest request) { + validateVorgang(request.getVorgangId()); var persisted = saveCommand(buildCommand(request)); publisher.publishEvent(new CommandCreatedEvent(persisted)); return persisted; } + void validateVorgang(String vorgangId) { + if (vorgangService.isVorgangLocked(vorgangId)) { + throw new TechnicalException("Cannot create command. Vorgang %s is locked.".formatted(vorgangId)); + } + } + private Command buildCommand(CreateCommandRequest request) { var builder = PersistedCommand.builder() .id(UUID.randomUUID().toString()) @@ -87,6 +97,7 @@ public class CommandService { .body(request.getBody()) .bodyObject(request.getBodyObject()); + userService.findUser().map(CallContextUser::getClientName).ifPresent(builder::createdByClientName); builder = addUserIfExists(builder, Optional.ofNullable(request.getCallContext()).map(CallContext::getUser), userService.findUser()); return builder.build(); } diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java index 7bdcc47b4fc18edd75dc50802ecc6a8c3a7ca980..f51468b4f6c1b2b2021edea87a9e3fb718e764b4 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/Order.java @@ -40,6 +40,7 @@ public enum Order { VORGANG_WIEDEREROEFFNEN, VORGANG_ZUM_LOESCHEN_MARKIEREN, VORGANG_LOESCHEN, + LOCK_VORGANG, ASSIGN_USER, diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java index 71964af4d27968376adf98bb011157c544c41e37..7e045d3e121d5971d33c910c5c717b1a5822d045 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/command/PersistedCommand.java @@ -63,6 +63,7 @@ public class PersistedCommand implements Command { private String createdBy; private String createdByName; + private String createdByClientName; @Setter private CommandStatus status; diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java new file mode 100644 index 0000000000000000000000000000000000000000..a888e0ea88582596dc39af16e2007bc66a507c3e --- /dev/null +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Lock.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.vorgang.vorgang; + +import java.time.ZonedDateTime; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +class Lock { + + static final String FIELD_CLIENT_NAME = "clientName"; + static final String FIELD_LOCKED_SINCE = "lockedSince"; + static final String FIELD_REASON = "reason"; + + private final String clientName; + private final ZonedDateTime lockedSince; + private final String reason; + +} diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java index 88557e44c95e469d95f17dbd1f413c3e941b19fc..979de7347065ba922cf5b41c2eb4151bfc293013 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/Vorgang.java @@ -50,6 +50,7 @@ public class Vorgang { static final String MONGODB_FIELDNAME_CREATED_AT = "createdAt"; public static final String MONGODB_FIELDNAME_ASSIGNED_TO = "assignedTo"; public static final String MONGODB_FIELDNAME_IN_CREATION = "inCreation"; + public static final String MONGODB_FIELDNAME_HEADER = "header"; public static final String FIELD_EINGANGSKENNZ = "eingangs.header.requestId"; public static final String FIELD_AKTENZEICHEN = "aktenzeichen"; diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java index 4433839167a3ecf15dfe1667f920e6d2b2a38757..fe62492f032f6f357a8df8db7fbecee6ce1031c2 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangEventListener.java @@ -35,6 +35,9 @@ import de.ozgcloud.command.Command; import de.ozgcloud.command.CommandCreatedEvent; import de.ozgcloud.command.CommandExecutedEvent; import de.ozgcloud.command.CommandFailedEvent; +import de.ozgcloud.command.CommandRevokeFailedEvent; +import de.ozgcloud.command.CommandRevokedEvent; +import de.ozgcloud.command.RevokeCommandEvent; import de.ozgcloud.vorgang.command.CommandService; import de.ozgcloud.vorgang.command.Order; import de.ozgcloud.vorgang.files.FileService; @@ -54,6 +57,9 @@ public class VorgangEventListener { public static final Predicate<Command> IS_LOESCHEN_COMMAND = command -> Order.VORGANG_LOESCHEN.isMeant(command.getOrder()); public static final Predicate<Command> IS_SET_AKTENZEICHEN_COMMAND = command -> Order.SET_AKTENZEICHEN.isMeant(command.getOrder()); + private static final String IS_LOCK_VORGANG_COMMAND = "{T(de.ozgcloud.vorgang.vorgang.VorgangEventListener).IS_LOCK_VORGANG_ORDER.test(event.getSource())}"; + public static final Predicate<Command> IS_LOCK_VORGANG_ORDER = command -> Order.LOCK_VORGANG.isMeant(command.getOrder()); + @Autowired private StatusService statusService; @Autowired @@ -111,6 +117,29 @@ public class VorgangEventListener { } } + @EventListener(condition = IS_LOCK_VORGANG_COMMAND) + public void onLockVorgang(CommandCreatedEvent event) { + var command = event.getSource(); + try { + vorgangService.lockVorgang(command); + } catch (RuntimeException e) { + LOG.error("Error locking vorgang.", e); + publisher.publishEvent(new CommandFailedEvent(command.getId(), e.getMessage())); + } + } + + @EventListener(condition = IS_LOCK_VORGANG_COMMAND) + public void onRevokeLockVorgang(RevokeCommandEvent event) { + var command = event.getSource(); + try { + vorgangService.unlockVorgang(command); + publisher.publishEvent(new CommandRevokedEvent(command)); + } catch (RuntimeException e) { + LOG.error("Error unlocking vorgang.", e); + publisher.publishEvent(new CommandRevokeFailedEvent(command.getId(), e.getMessage())); + } + } + void publishEvent(CommandExecutedEvent event) { LOG.debug("Command {} executed", event.getSource()); publisher.publishEvent(event); diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java index 13e858035e377296843b70740e23c96ca3c3485e..2f3cb7ddde140b25b2e624da26d1594735bddaf7 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangHead.java @@ -11,9 +11,13 @@ import lombok.Getter; @TypeAlias("VorgangHeader") public class VorgangHead { + public static final String FIELD_LOCK = "lock"; + private ServiceKonto serviceKonto; private String organisationsEinheitId; @Builder.Default private int collaborationLevel = 0; + + private final Lock lock; } diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java index 6c73fec3e55592fdde6648d3c0e449dcd86eb341..26d04339e3b70b7d4223f9767b369769565e4d2b 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangRepository.java @@ -31,31 +31,22 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Stream; -import jakarta.annotation.PostConstruct; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Repository; -import com.mongodb.client.result.UpdateResult; - import de.ozgcloud.vorgang.common.db.CollisionVerifier; import de.ozgcloud.vorgang.common.db.CriteriaUtil; +import lombok.RequiredArgsConstructor; @Repository +@RequiredArgsConstructor class VorgangRepository { - @Autowired - private MongoOperations mongoOperations; + private final MongoOperations mongoOperations; - private CollisionVerifier collisionVerifier; - - @PostConstruct - void init() { - collisionVerifier = new CollisionVerifier(this::exists); - } + private final CollisionVerifier collisionVerifier = new CollisionVerifier(this::exists); public Optional<Vorgang> findById(String vorgangId) { return Optional.ofNullable(findOne(CriteriaUtil.isId(vorgangId))); @@ -85,16 +76,16 @@ class VorgangRepository { var update = new Update().inc(Vorgang.MONGODB_FIELDNAME_VERSION, 1); patch.forEach(update::set); - updateFirst(whereIdAndVersion(vorgangId, version), update); + updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), update); } public void setAktenzeichen(String vorgangId, long version, String akteneinsicht) { - var updateResult = updateFirst(whereIdAndVersion(vorgangId, version), new Update().set(Vorgang.FIELD_AKTENZEICHEN, akteneinsicht)); - collisionVerifier.verify(updateResult, vorgangId); + updateFirst(vorgangId, whereIdAndVersion(vorgangId, version), new Update().set(Vorgang.FIELD_AKTENZEICHEN, akteneinsicht)); } - private UpdateResult updateFirst(Criteria queryObj, Update update) { - return mongoOperations.updateFirst(query(queryObj), update, Vorgang.class); + private void updateFirst(String vorgangId, Criteria queryObj, Update update) { + var updateResult = mongoOperations.updateFirst(query(queryObj), update, Vorgang.class); + collisionVerifier.verify(updateResult, vorgangId); } private Criteria whereIdAndVersion(String vorgangId, long version) { @@ -112,4 +103,13 @@ class VorgangRepository { .andOperator(isNotDeleted()))), Vorgang.class); } + + public boolean isVorgangLocked(String vorgangId) { + return mongoOperations.exists(query(whereIdAndLock(vorgangId)), Vorgang.class); + } + + Criteria whereIdAndLock(String vorgangId) { + return new Criteria().andOperator(CriteriaUtil.isId(vorgangId), CriteriaUtil.isNotDeleted(), + Criteria.where(VorgangService.KEY_HEADER_LOCK).ne(null)); + } } \ No newline at end of file diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java index 67678fb2648931db32733b0f3c113d43e0d87bc5..bb11f2d9dd746310ba8ca7a2aa792347ae74498d 100644 --- a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/vorgang/VorgangService.java @@ -23,10 +23,13 @@ */ package de.ozgcloud.vorgang.vorgang; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Optional; import java.util.stream.Stream; @@ -44,6 +47,8 @@ import org.springframework.validation.annotation.Validated; import de.ozgcloud.command.Command; import de.ozgcloud.command.VorgangAssignedEvent; import de.ozgcloud.command.VorgangCreatedEvent; +import de.ozgcloud.command.VorgangLockedEvent; +import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.vorgang.clientattribute.ClientAttributeMap; import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted; import de.ozgcloud.vorgang.clientattribute.ClientAttributesMap; @@ -57,6 +62,7 @@ public class VorgangService { private static final String BODY_ASSIGNED_TO_FIELD = "assignedTo"; public static final String BODY_OBJECT_AKTENZEICHEN = "aktenzeichen"; + static final String KEY_HEADER_LOCK = "%s.%s".formatted(Vorgang.MONGODB_FIELDNAME_HEADER, VorgangHead.FIELD_LOCK); @Autowired private VorgangAuthorizationService vorgangAuthenticationService; @@ -223,4 +229,40 @@ public class VorgangService { Vorgang loadById(String vorgangId) { return repository.findById(vorgangId).orElseThrow(() -> new NotFoundException(Vorgang.class, vorgangId)); } + + public void lockVorgang(Command command) { + validateLockCommand(command); + repository.patch(command.getVorgangId(), command.getRelationVersion(), buildLockPatch(command)); + publisher.publishEvent(new VorgangLockedEvent(command)); + } + + void validateLockCommand(Command command) { + if (Objects.isNull(command.getCreatedByClientName())) { + throw new TechnicalException("Missing client name in lock command"); + } + if (Objects.isNull(getReason(command.getBodyObject()))) { + throw new TechnicalException("Missing reason in lock command"); + } + } + + Map<String, Object> buildLockPatch(Command command) { + return Map.of(KEY_HEADER_LOCK, Map.of( + Lock.FIELD_CLIENT_NAME, command.getCreatedByClientName(), + Lock.FIELD_LOCKED_SINCE, ZonedDateTime.now(ZoneId.of("UTC")), + Lock.FIELD_REASON, getReason(command.getBodyObject()))); + } + + String getReason(Map<String, Object> commandBody) { + return StringUtils.trimToNull(MapUtils.getString(commandBody, Lock.FIELD_REASON)); + } + + public boolean isVorgangLocked(String vorgangId) { + return repository.isVorgangLocked(vorgangId); + } + + public void unlockVorgang(Command command) { + // TODO wird implementiert in OZG-6992 + // publisher.publishEvent(new CommandRevokedEvent(command)); + throw new UnsupportedOperationException("Not yet implemented"); + } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java index 3f4d68d90efa91280762ec75d49a7692d352a175..a129a4c389de52dbf8d0ef358efdec8ea5e6771c 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandServiceTest.java @@ -35,6 +35,7 @@ import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -59,6 +60,7 @@ import de.ozgcloud.vorgang.callcontext.CurrentUserService; import de.ozgcloud.vorgang.callcontext.UserTestFactory; import de.ozgcloud.vorgang.common.errorhandling.NotFoundException; import de.ozgcloud.vorgang.common.errorhandling.RevokeFailedException; +import de.ozgcloud.vorgang.vorgang.VorgangService; import de.ozgcloud.vorgang.vorgang.VorgangTestFactory; class CommandServiceTest { @@ -73,6 +75,8 @@ class CommandServiceTest { private ApplicationEventPublisher publisher; @Mock private CurrentUserService currentUserService; + @Mock + private VorgangService vorgangService; @Nested class TestCreateCommand { @@ -82,6 +86,13 @@ class CommandServiceTest { @Captor private ArgumentCaptor<Command> commandCaptor; + @Test + void shouldCallValidateVorgang() { + service.createCommand(request); + + verify(service).validateVorgang(VorgangTestFactory.ID); + } + @Test void shouldCallOperationRepository() { service.createCommand(request); @@ -102,6 +113,15 @@ class CommandServiceTest { assertThat(command.getRelationVersion()).isEqualTo(CreateCommandRequestTestFactory.RELATION_VERSION); } + @Test + void shouldSetClientName() { + when(currentUserService.findUser()).thenReturn(Optional.of(CallContextUserTestFactory.create())); + + var command = (PersistedCommand) service.createCommand(request); + + assertThat(command.getCreatedByClientName()).isEqualTo(CallContextTestFactory.CLIENT); + } + @Test void shouldHandleMissingCallContext() { var request = CreateCommandRequestTestFactory.createBuilder().callContext(null).build(); @@ -157,6 +177,25 @@ class CommandServiceTest { } } + @Nested + class TestValidateVorgang { + + @Test + void shouldCallIsVorgangLocked() { + service.validateVorgang(VorgangTestFactory.ID); + + verify(vorgangService).isVorgangLocked(VorgangTestFactory.ID); + } + + @Test + void shouldThrowExceptionIfVorgangLocked() { + when(vorgangService.isVorgangLocked(anyString())).thenReturn(true); + + Assertions.assertThrows(TechnicalException.class, () -> service.validateVorgang(VorgangTestFactory.ID)); + } + + } + @Nested class TestGetVorgangCommand { diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java index ff3e080efe5ba9eaa41c46b74820bcda8427dd5c..c87132fce74264ffcb34a894b036e0f6351fe7e7 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/CommandTestFactory.java @@ -29,6 +29,7 @@ import java.util.UUID; import de.ozgcloud.command.CommandStatus; import de.ozgcloud.vorgang.attached_item.VorgangAttachedItemTestFactory; +import de.ozgcloud.vorgang.callcontext.CallContextTestFactory; import de.ozgcloud.vorgang.callcontext.UserTestFactory; import de.ozgcloud.vorgang.vorgang.VorgangTestFactory; @@ -39,6 +40,7 @@ public class CommandTestFactory { public static final ZonedDateTime CREATED_AT = ZonedDateTime.parse(CREATED_AT_STR); public static final String CREATED_BY = UserTestFactory.ID; public static final String CREATED_BY_NAME = UserTestFactory.NAME; + public static final String CREATED_BY_CLIENT = CallContextTestFactory.CLIENT; public static final CommandStatus STATUS = CommandStatus.PENDING; public static final String RELATION_ID = VorgangAttachedItemTestFactory.ID; @@ -59,6 +61,7 @@ public class CommandTestFactory { .createdAt(CREATED_AT) .createdBy(CREATED_BY) .createdByName(CREATED_BY_NAME) + .createdByClientName(CREATED_BY_CLIENT) .status(STATUS) .relationId(RELATION_ID) .relationVersion(RELATION_VERSION) diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java index e890e4ea2097781bba11e16db414d51370c90562..784f0e26762198dfac1d195b47e7e5ed64512648 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceITCase.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -39,6 +40,7 @@ import de.ozgcloud.vorgang.grpc.command.GrpcCreateCommandRequest; import de.ozgcloud.vorgang.grpc.command.GrpcFindCommandsRequest; import de.ozgcloud.vorgang.grpc.command.GrpcRevokeCommandRequest; import de.ozgcloud.vorgang.vorgang.Vorgang; +import de.ozgcloud.vorgang.vorgang.VorgangHeadTestFactory; import de.ozgcloud.vorgang.vorgang.VorgangTestFactory; import io.grpc.StatusRuntimeException; import lombok.extern.log4j.Log4j2; @@ -110,6 +112,20 @@ class GrpcCommandServiceITCase { assertThat(commands).hasSize(1).first().extracting(Command::getStatus).isEqualTo(CommandStatus.FINISHED); }); } + + @Test + void shouldNotPersistCommand() { + var lockedVorgang = mongoOperations.save(buildLockedVorgang()); + var request = GrpcCreateCommandRequestTestFactory.createBuilder().setVorgangId(lockedVorgang.getId()).build(); + + assertThrows(StatusRuntimeException.class, () -> serviceBlockingStub.createCommand(request)); + + assertThat(mongoOperations.findAll(Command.class)).isEmpty(); + } + + Vorgang buildLockedVorgang() { + return VorgangTestFactory.createBuilder().id(null).version(0).header(VorgangHeadTestFactory.create()).build(); + } } @Nested @@ -215,6 +231,14 @@ class GrpcCommandServiceITCase { }); } + @Test + void shouldFailOnLockedVorgang() { + mongoOperations.save(vorgang.toBuilder().header(VorgangHeadTestFactory.create()).build()); + var request = buildAddSubCommandsRequest(parentCommand.getId(), buildCreateCommand()); + + Assertions.assertThrows(StatusRuntimeException.class, () -> serviceBlockingStub.addSubCommands(request)); + } + private GrpcCommand createParentCommand() { var createParentCommandRequest = GrpcCreateCommandRequestTestFactory.createBuilder() .setVorgangId(vorgang.getId()) diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java index 6807b332b138383be4bff92001a809aba224d3ac..c906cab1c71d690a375b705dac310cd0844ea1bd 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/command/GrpcCommandServiceTest.java @@ -93,7 +93,8 @@ class GrpcCommandServiceTest { private StreamObserver<GrpcCommandResponse> responseObserver; @Captor private ArgumentCaptor<GrpcCommandResponse> responseCaptor; - private final GrpcCreateCommandRequest request = GrpcCreateCommandRequest.newBuilder().build(); + + private final GrpcCreateCommandRequest request = GrpcCreateCommandRequestTestFactory.create(); private final CreateCommandRequest createComandRequest = CreateCommandRequestTestFactory.create(); private final GrpcCommandResponse response = GrpcCommandResponse.newBuilder().build(); private final Command persistedCommand = CommandTestFactory.create(); @@ -107,28 +108,28 @@ class GrpcCommandServiceTest { } @Test - void shouldCallPolicyService() throws Exception { + void shouldCallPolicyService() { callCreateCommand(); - verify(policyService).checkPermission(anyString()); + verify(policyService).checkPermission(VorgangTestFactory.ID); } @Test - void shouldCallCommandRequestMapper() throws Exception { + void shouldCallCommandRequestMapper() { callCreateCommand(); verify(createCommandRequestMapper).fromGrpc(request); } @Test - void shouldCallCommandService() throws Exception { + void shouldCallCommandService() { callCreateCommand(); verify(commandService).createCommand(createComandRequest); } @Test - void shouldReturnValue() throws Exception { + void shouldReturnValue() { callCreateCommand(); var values = responseCaptor.getValue(); @@ -136,7 +137,7 @@ class GrpcCommandServiceTest { assertThat(values).isEqualTo(response); } - private void callCreateCommand() throws Exception { + private void callCreateCommand() { service.createCommand(request, responseObserver); verify(responseObserver).onNext(responseCaptor.capture()); diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcLockTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcLockTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..4d1a76fea6b05042afa532bf250c5beee236666e --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcLockTestFactory.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.vorgang.vorgang; + +public class GrpcLockTestFactory { + + public static GrpcLock create() { + return createBuilder().build(); + } + + public static GrpcLock.Builder createBuilder() { + return GrpcLock.newBuilder() + .setClientName(LockTestFactory.CLIENT_NAME) + .setLockedSince(LockTestFactory.LOCKED_SINCE_STR) + .setReason(LockTestFactory.REASON); + } +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangHeadTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangHeadTestFactory.java index 2dad17c7bcb3ef89ddb5c8a1aea0f39d5af7bd8b..9cf5020e2d1cbbf5f9bd105e3887d4ac45c4ca14 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangHeadTestFactory.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/GrpcVorgangHeadTestFactory.java @@ -4,12 +4,15 @@ import de.ozgcloud.vorgang.servicekonto.GrpcServiceKontoTestFactory; public class GrpcVorgangHeadTestFactory { + public static final GrpcLock LOCK = GrpcLockTestFactory.create(); + public static GrpcVorgangHead create() { return createBuilder().build(); } public static GrpcVorgangHead.Builder createBuilder() { return GrpcVorgangHead.newBuilder() - .setServiceKonto(GrpcServiceKontoTestFactory.create()); + .setServiceKonto(GrpcServiceKontoTestFactory.create()) + .setLock(LOCK); } } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..7b4905e5280cf65dc77a65dae4888feb035e7f01 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/LockTestFactory.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.vorgang.vorgang; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.vorgang.vorgang.Lock.LockBuilder; + +public class LockTestFactory { + + public static final String CLIENT_NAME = LoremIpsum.getInstance().getFirstName() + "-Client"; + public static final String REASON = LoremIpsum.getInstance().getWords(5); + public static final String LOCKED_SINCE_STR = ZonedDateTime.now().withNano(0).format(DateTimeFormatter.ISO_INSTANT); + public static final ZonedDateTime LOCKED_SINCE = ZonedDateTime.parse(LOCKED_SINCE_STR); + + public static Lock create() { + return createBuilder().build(); + } + + public static LockBuilder createBuilder() { + return Lock.builder() + .clientName(CLIENT_NAME) + .lockedSince(LOCKED_SINCE) + .reason(REASON); + } + + public static Map<String, Object> asMap() { + return Map.of( + Lock.FIELD_CLIENT_NAME, CLIENT_NAME, + Lock.FIELD_LOCKED_SINCE, LOCKED_SINCE, + Lock.FIELD_REASON, REASON + ); + } +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java index 8b81f437d748490a869bf45321ea8e73c02856ed..d57886aa60ea449c2003ecdbdf979614a259dc89 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangEventListenerTest.java @@ -46,6 +46,9 @@ import com.thedeanda.lorem.LoremIpsum; import de.ozgcloud.command.Command; import de.ozgcloud.command.CommandExecutedEvent; import de.ozgcloud.command.CommandFailedEvent; +import de.ozgcloud.command.CommandRevokeFailedEvent; +import de.ozgcloud.command.CommandRevokedEvent; +import de.ozgcloud.command.RevokeCommandEvent; import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.vorgang.command.CommandCreatedEventTestFactory; import de.ozgcloud.vorgang.command.CommandService; @@ -231,4 +234,77 @@ class VorgangEventListenerTest { } } + @Nested + class TestOnLockVorgang { + + @Captor + private ArgumentCaptor<CommandFailedEvent> eventCaptor; + + @Test + void shouldCallLockVorgang() { + var command = CommandTestFactory.create(); + + listener.onLockVorgang(CommandCreatedEventTestFactory.create(command)); + + verify(service).lockVorgang(command); + } + + @Test + void shouldPublishCommandFailedEvent() { + var command = CommandTestFactory.create(); + var errorMessage = "error message"; + doThrow(new RuntimeException(errorMessage)).when(service).lockVorgang(command); + + listener.onLockVorgang(CommandCreatedEventTestFactory.create(command)); + + verify(publisher).publishEvent(eventCaptor.capture()); + assertThat(eventCaptor.getValue()).satisfies(event -> { + assertThat(event.getSource()).isEqualTo(CommandTestFactory.ID); + assertThat(event.getErrorMessage()).isEqualTo(errorMessage); + }); + } + } + + @Nested + class TestRevokeLockVorgang { + + @Captor + private ArgumentCaptor<CommandRevokedEvent> commandRevokedEventCaptor; + @Captor + private ArgumentCaptor<CommandRevokeFailedEvent> commandRevokeFailedEventCaptor; + + @Test + void shouldCallUnlockVorgang() { + var command = CommandTestFactory.create(); + + listener.onRevokeLockVorgang(new RevokeCommandEvent(command)); + + verify(service).unlockVorgang(command); + } + + @Test + void shouldPublishCommandRevokedEvent() { + var command = CommandTestFactory.create(); + + listener.onRevokeLockVorgang(new RevokeCommandEvent(command)); + + verify(publisher).publishEvent(commandRevokedEventCaptor.capture()); + assertThat(commandRevokedEventCaptor.getValue().getSource()).isSameAs(command); + } + + @Test + void shouldPublishCommandFailedEvent() { + var command = CommandTestFactory.create(); + var errorMessage = "error message"; + doThrow(new RuntimeException(errorMessage)).when(service).unlockVorgang(command); + + listener.onRevokeLockVorgang(new RevokeCommandEvent(command)); + + verify(publisher).publishEvent(commandRevokeFailedEventCaptor.capture()); + assertThat(commandRevokeFailedEventCaptor.getValue()).satisfies(event -> { + assertThat(event.getSource()).isEqualTo(CommandTestFactory.ID); + assertThat(event.getErrorMessage()).isEqualTo(errorMessage); + }); + } + } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangHeadTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangHeadTestFactory.java index 3df7b94939e7c79fcf36323a02036948d29340d3..fa00c709994f056c37eab9475c82472ff88dee49 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangHeadTestFactory.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangHeadTestFactory.java @@ -1,15 +1,20 @@ package de.ozgcloud.vorgang.vorgang; +import de.ozgcloud.vorgang.servicekonto.ServiceKonto; import de.ozgcloud.vorgang.servicekonto.ServiceKontoTestFactory; public class VorgangHeadTestFactory { + public static final Lock LOCK = LockTestFactory.create(); + public static final ServiceKonto SERVICE_KONTO = ServiceKontoTestFactory.create(); + public static VorgangHead create() { return createBuilder().build(); } public static VorgangHead.VorgangHeadBuilder createBuilder() { return VorgangHead.builder() - .serviceKonto(ServiceKontoTestFactory.create()); + .serviceKonto(SERVICE_KONTO) + .lock(LOCK); } } diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java index f8e53b21c3330f11204100db26086e1d5274c4c7..9d19e8a701453ad636c4458f45d9de1f30b2927b 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangRepositoryITCase.java @@ -340,7 +340,7 @@ class VorgangRepositoryITCase { } @Test - void should() { + void should() { assertThat(mongoOperations.findAll(Vorgang.class)).isEmpty(); repository.setAktenzeichen(VorgangTestFactory.ID, VorgangTestFactory.VERSION, VorgangTestFactory.AKTENZEICHEN); @@ -360,4 +360,27 @@ class VorgangRepositoryITCase { return mongoOperations.findById(VorgangTestFactory.ID, Vorgang.class); } } + + @Nested + class TestIsVorgangLocked { + + @Test + void shouldReturnTrue() { + var vorgang = mongoOperations.save( + VorgangTestFactory.createBuilder().id(null).version(0).header(VorgangHeadTestFactory.create()).build()); + + var isLocked = repository.isVorgangLocked(vorgang.getId()); + + assertThat(isLocked).isTrue(); + } + + @Test + void shouldReturnFalseWhenNoLock() { + var vorgang = mongoOperations.save(VorgangTestFactory.createBuilder().id(null).version(0).build()); + + var isLocked = repository.isVorgangLocked(vorgang.getId()); + + assertThat(isLocked).isFalse(); + } + } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java index c6a8daf26e2d1696cad785c5cb1c66cf1d73f33a..5e4c2e4690780c92555b58237d9662f6dafe91c8 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangServiceTest.java @@ -28,10 +28,13 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; import java.util.Optional; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -49,6 +52,8 @@ import org.springframework.security.access.AccessDeniedException; import de.ozgcloud.command.Command; import de.ozgcloud.command.VorgangAssignedEvent; import de.ozgcloud.command.VorgangCreatedEvent; +import de.ozgcloud.command.VorgangLockedEvent; +import de.ozgcloud.common.errorhandling.TechnicalException; import de.ozgcloud.vorgang.clientattribute.ClientAttributeReadPermitted; import de.ozgcloud.vorgang.command.CommandTestFactory; import de.ozgcloud.vorgang.common.errorhandling.NotFoundException; @@ -507,4 +512,124 @@ class VorgangServiceTest { verify(repository).setAktenzeichen(VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION, null); } } + + @Nested + class TestLockVorgang { + + private static final Command LOCK_COMMAND = CommandTestFactory.create(); + private static final Map<String, Object> LOCK_PATCH = Map.of("key", "value"); + + @Captor + private ArgumentCaptor<VorgangLockedEvent> eventCaptor; + + @BeforeEach + void init() { + doNothing().when(service).validateLockCommand(any()); + doReturn(LOCK_PATCH).when(service).buildLockPatch(any()); + } + + @Test + void shouldCallValidateLockCommand() { + service.lockVorgang(LOCK_COMMAND); + + verify(service).validateLockCommand(LOCK_COMMAND); + } + + @Test + void shouldCallBuildLockPatch() { + service.lockVorgang(LOCK_COMMAND); + + verify(service).buildLockPatch(LOCK_COMMAND); + } + + @Test + void shouldCallRepository() { + service.lockVorgang(LOCK_COMMAND); + + verify(repository).patch(VorgangTestFactory.ID, CommandTestFactory.RELATION_VERSION, LOCK_PATCH); + } + + @Test + void shouldCallPublishEvent() { + service.lockVorgang(LOCK_COMMAND); + + verify(publisher).publishEvent(eventCaptor.capture()); + assertThat(eventCaptor.getValue().getCommand()).isSameAs(LOCK_COMMAND); + } + } + + @Nested + class TestValidateLockCommand { + + @Test + void shouldThrowExceptionOnMissingClient() { + var command = CommandTestFactory.createBuilder().createdByClientName(null).build(); + + assertThrows(TechnicalException.class, () -> service.validateLockCommand(command)); + } + + @Test + void shouldThrowExceptionOnMissingReason() { + var command = CommandTestFactory.createBuilder().bodyObject(Map.of()).build(); + + assertThrows(TechnicalException.class, () -> service.validateLockCommand(command)); + } + + @Test + void shouldAcceptValidCommand() { + var command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build(); + + assertDoesNotThrow(() -> service.validateLockCommand(command)); + } + } + + @Nested + class TestBuildLockPatch { + + private final Command command = CommandTestFactory.createBuilder().bodyObject(Map.of(Lock.FIELD_REASON, LockTestFactory.REASON)).build(); + + @Test + void shouldSetClientName() { + var result = service.buildLockPatch(command); + + assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP) + .containsEntry(Lock.FIELD_CLIENT_NAME, CommandTestFactory.CREATED_BY_CLIENT); + } + + @Test + void shouldSetLockedSince() { + var result = service.buildLockPatch(command); + + assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP) + .extractingByKey(Lock.FIELD_LOCKED_SINCE, InstanceOfAssertFactories.ZONED_DATE_TIME) + .isCloseTo(ZonedDateTime.now(), within(1, ChronoUnit.SECONDS)); + } + + @Test + void shouldSetReason() { + var result = service.buildLockPatch(command); + + assertThat(result).extractingByKey(VorgangService.KEY_HEADER_LOCK, MAP).containsEntry(Lock.FIELD_REASON, LockTestFactory.REASON); + } + } + + @Nested + class TestIsVorgangLocked { + + @Test + void shouldCallRepository() { + service.isVorgangLocked(VorgangTestFactory.ID); + + verify(repository).isVorgangLocked(VorgangTestFactory.ID); + } + + @Test + void shouldReturnResult() { + when(repository.isVorgangLocked(anyString())).thenReturn(true); + + var result = service.isVorgangLocked(VorgangTestFactory.ID); + + assertThat(result).isTrue(); + } + } } \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangTestFactory.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangTestFactory.java index ab5b9993fd21163e0584405f38972ca7b1970675..f3631378b23be339f5be8a007839fb39cf730e76 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangTestFactory.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangTestFactory.java @@ -75,7 +75,7 @@ public class VorgangTestFactory { .nummer(VORGANG_NUMMER) .status(STATUS) .createdAt(CREATED_AT) - .header(VorgangHeadTestFactory.create()) + .header(VorgangHeadTestFactory.createBuilder().lock(null).build()) .eingang(EINGANG) .version(VERSION) .assignedTo(UserTestFactory.ID) diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangWithEingangMapperTest.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangWithEingangMapperTest.java index fb2835b2c69b35167c8a9c5d5a50a8d1a0fa70df..a231605a85030e5bb12a810d00dc9f3fe56c2fb3 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangWithEingangMapperTest.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/vorgang/VorgangWithEingangMapperTest.java @@ -70,7 +70,7 @@ class VorgangWithEingangMapperTest { var vorgangWithEingang = callMapper(); assertThat(vorgangWithEingang).usingRecursiveComparison() - .ignoringFields("eingang_", "clientAttributes_", "memoizedHashCode", "header_") + .ignoringFields("eingang_", "clientAttributes_", "memoizedHashCode") .isEqualTo(GrpcVorgangWithEingangTestFactory.create()); } @@ -81,15 +81,9 @@ class VorgangWithEingangMapperTest { assertThat(eingang).usingRecursiveComparison().isEqualTo(GrpcEingangTestFactory.create()); } - @Test - void shouldMapHeader() { - var header = callMapper().getHeader(); - - assertThat(header).usingRecursiveComparison().isEqualTo(GrpcVorgangHeadTestFactory.create()); - } - private GrpcVorgangWithEingang callMapper() { - return mapper.toVorgangWithEingang(VorgangTestFactory.create()); + var vorgang = VorgangTestFactory.createBuilder().header(VorgangHeadTestFactory.createBuilder().lock(VorgangHeadTestFactory.LOCK).build()); + return mapper.toVorgangWithEingang(vorgang.build()); } } } \ No newline at end of file