diff --git a/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M014_AddItemNameBescheidToPatchAttachedItemCommand.java b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M014_AddItemNameBescheidToPatchAttachedItemCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..5fd8d5eddebd45a673c2aae68e5be0cda44d0863 --- /dev/null +++ b/vorgang-manager-server/src/main/java/de/ozgcloud/vorgang/common/migration/M014_AddItemNameBescheidToPatchAttachedItemCommand.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2025 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.common.migration; + +import java.util.List; +import java.util.stream.Stream; + +import org.bson.Document; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; + +import io.mongock.api.annotations.ChangeUnit; +import io.mongock.api.annotations.Execution; +import io.mongock.api.annotations.RollbackExecution; + +@ChangeUnit(id = "2025-01-17 16:00:00 OZG-7515", order = "M014", author = "freichenbach", runAlways = true) +public class M014_AddItemNameBescheidToPatchAttachedItemCommand { // NOSONAR + + private static final String ID_FIELD = "_id"; + private static final String COMMAND_COLLECTION_NAME = "command"; + private static final String ORDER_FIELD = "order"; + private static final String SEND_BESCHEID_ORDER = "SEND_BESCHEID"; + private static final String PARENT_ID_FIELD = "bodyObject.parentId"; + private static final String PATCH_ATTACHED_ITEM_ORDER = "PATCH_ATTACHED_ITEM"; + private static final String ITEM_NAME_FILED = "bodyObject.itemName"; + private static final String BESCHEID_ITEM_NAME = "Bescheid"; + + @Execution + public void doMigration(MongoOperations mongoOperations) { + var parentIds = getSendBescheidCommandIds(mongoOperations); + updateDocuments(mongoOperations, parentIds); + } + + List<String> getSendBescheidCommandIds(MongoOperations mongoOperations) { + return getSendBescheidCommands(mongoOperations).map(command -> command.getString(ID_FIELD)).toList(); + } + + private Stream<Document> getSendBescheidCommands(MongoOperations mongoOperations) { + return mongoOperations.stream(Query.query(Criteria.where(ORDER_FIELD).is(SEND_BESCHEID_ORDER)), Document.class, + COMMAND_COLLECTION_NAME); + } + + void updateDocuments(MongoOperations mongoOperations, List<String> parentIds) { + mongoOperations.updateMulti(createQuery(parentIds), createAddBescheidItemNameUpdate(), COMMAND_COLLECTION_NAME); + } + + Query createQuery(List<String> parentIds) { + return new Query().addCriteria(new Criteria().andOperator( + Criteria.where(PARENT_ID_FIELD).in(parentIds), + Criteria.where(ORDER_FIELD).is(PATCH_ATTACHED_ITEM_ORDER), + Criteria.where(ITEM_NAME_FILED).exists(false))); + } + + private Update createAddBescheidItemNameUpdate() { + return new Update().set(ITEM_NAME_FILED, BESCHEID_ITEM_NAME); + } + + @RollbackExecution + public void rollback() { + // kein rollback implementiert + } +} \ No newline at end of file diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M014_AddItemNameBescheidToPatchAttachedItemCommandITCase.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M014_AddItemNameBescheidToPatchAttachedItemCommandITCase.java new file mode 100644 index 0000000000000000000000000000000000000000..63f31347438b235956dabae2ed67cbefd3cbeb01 --- /dev/null +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/M014_AddItemNameBescheidToPatchAttachedItemCommandITCase.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2025 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.common.migration; + +import static org.assertj.core.api.Assertions.*; + +import java.time.ZonedDateTime; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.bson.Document; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoOperations; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.common.test.DataITCase; + +@DataITCase +class M014_AddItemNameBescheidToPatchAttachedItemCommandITCase { + + private static final String BESCHEID_ITEM_NAME = "Bescheid"; + private static final String ITEM_NAME_FIELD = "itemName"; + private static final String PATCH_ATTACHED_ITEM_ORDER = "PATCH_ATTACHED_ITEM"; + private static final String PARENT_ID_FIELD = "parentId"; + private static final String SEND_BESCHEID_ORDER = "SEND_BESCHEID"; + + @InjectMocks + private M014_AddItemNameBescheidToPatchAttachedItemCommand migration; + @Autowired + private MigrationDbTestUtils migrationDbTestUtils; + @Autowired + private MongoOperations mongoOperations; + + private Document sendBescheidCommand; + private Document patchAttachedItemCommand; + private Document subCommandWithUnkownOrder; + private Document patchAttachedItemCommandWithoutParent; + private Document patchAttachedItemCommandWithDifferentParent; + + @BeforeEach + void setUp() { + migrationDbTestUtils.dropCommandCollection(); + sendBescheidCommand = saveSendBescheidCommand(); + patchAttachedItemCommand = savePatchAttachedItemSubCommand(sendBescheidCommand.getString(CommandDocumentTestFactory.ID_FIELD)); + subCommandWithUnkownOrder = saveSubCommandWithUnkownOrder(sendBescheidCommand.getString(CommandDocumentTestFactory.ID_FIELD)); + patchAttachedItemCommandWithoutParent = savePatchAttachedItemCommandWithoutParent(); + patchAttachedItemCommandWithDifferentParent = savePatchAttachedItemCommandWithDifferentParent(); + } + + private Document saveSendBescheidCommand() { + var command = CommandDocumentTestFactory.createWithOrder(SEND_BESCHEID_ORDER); + return migrationDbTestUtils.saveCommand(command); + } + + private Document savePatchAttachedItemSubCommand(String id) { + var itemBody = Map.<String, Object>of(PARENT_ID_FIELD, id); + var command = CommandDocumentTestFactory.createWithOrderAndBody(PATCH_ATTACHED_ITEM_ORDER, itemBody); + return migrationDbTestUtils.saveCommand(command); + } + + private Document saveSubCommandWithUnkownOrder(String id) { + var itemBody = Map.<String, Object>of(PARENT_ID_FIELD, id); + var command = CommandDocumentTestFactory.createWithBody(itemBody); + return migrationDbTestUtils.saveCommand(command); + } + + private Document savePatchAttachedItemCommandWithoutParent() { + var command = CommandDocumentTestFactory.createWithOrder(PATCH_ATTACHED_ITEM_ORDER); + return migrationDbTestUtils.saveCommand(command); + } + + private Document savePatchAttachedItemCommandWithDifferentParent() { + var itemBody = Map.<String, Object>of(PARENT_ID_FIELD, UUID.randomUUID().toString()); + var command = CommandDocumentTestFactory.createWithOrderAndBody(PATCH_ATTACHED_ITEM_ORDER, itemBody); + return migrationDbTestUtils.saveCommand(command); + } + + @Nested + class TestGetSendBescheidCommandIds { + + @Test + void shouldReturnSendBescheidCommandId() { + var ids = migration.getSendBescheidCommandIds(mongoOperations); + + assertThat(ids).containsExactly(sendBescheidCommand.getString(CommandDocumentTestFactory.ID_FIELD)); + } + } + + @Nested + class TestBuildQuery { + @Test + void shouldQueryPatchAttachedItemCommandsWithParentId() { + var query = migration.createQuery(List.of(sendBescheidCommand.getString(CommandDocumentTestFactory.ID_FIELD))); + + var commands = mongoOperations.find(query, Document.class, MigrationDbTestUtils.COMMAND_COLLECTION); + assertThat(commands).usingRecursiveFieldByFieldElementComparator().containsExactly(patchAttachedItemCommand); + } + } + + @Nested + class TestUpdateDocuments { + @Test + void shouldModifyPatchAttachedBescheidItem() { + migration.updateDocuments(mongoOperations, List.of(sendBescheidCommand.getString(CommandDocumentTestFactory.ID_FIELD))); + + var command = migrationDbTestUtils.getCommand(patchAttachedItemCommand.getString(CommandDocumentTestFactory.ID_FIELD)); + assertThat(command).usingRecursiveComparison().isEqualTo(addItemNameToPatchAttachedItemCommand(patchAttachedItemCommand)); + } + + } + + @Nested + class TestFullMigration { + + @Test + void shouldNotAddOrRemoveCommands() { + migration.doMigration(mongoOperations); + + var commands = mongoOperations.findAll(Document.class, MigrationDbTestUtils.COMMAND_COLLECTION); + assertThat(commands).hasSize(5); + } + + @Nested + class TestPatchAttachedBescheidItem { + + @Test + void shouldAddItemNameToCommandBody() { + migration.doMigration(mongoOperations); + + var command = migrationDbTestUtils.getCommand(patchAttachedItemCommand.getString(CommandDocumentTestFactory.ID_FIELD)); + assertThat(command).usingRecursiveComparison().isEqualTo(addItemNameToPatchAttachedItemCommand(patchAttachedItemCommand)); + } + + } + + @Nested + class TestCommandsToNotModify { + @Test + void shouldKeepSendBescheidCommand() { + migration.doMigration(mongoOperations); + + var command = migrationDbTestUtils.getCommand(sendBescheidCommand.getString(CommandDocumentTestFactory.ID_FIELD)); + assertThat(command).usingRecursiveComparison().isEqualTo(sendBescheidCommand); + } + + @Nested + class TestSubCommandsOfSendBescheidItem { + + @Test + void shouldKeepIfOrderIsNotPatchAttachedItem() { + migration.doMigration(mongoOperations); + + var command = migrationDbTestUtils.getCommand(subCommandWithUnkownOrder.getString(CommandDocumentTestFactory.ID_FIELD)); + assertThat(command).usingRecursiveComparison().isEqualTo(subCommandWithUnkownOrder); + + } + } + + @Nested + class TestPatchAttachedItem { + + @Test + void shouldNotModifyOnMissingParentId() { + migration.doMigration(mongoOperations); + + var command = migrationDbTestUtils + .getCommand(patchAttachedItemCommandWithoutParent.getString(CommandDocumentTestFactory.ID_FIELD)); + assertThat(command).usingRecursiveComparison().isEqualTo(patchAttachedItemCommandWithoutParent); + } + + @Test + void shouldNotModifyOnDifferentParentId() { + migration.doMigration(mongoOperations); + + var command = migrationDbTestUtils + .getCommand(patchAttachedItemCommandWithDifferentParent.getString(CommandDocumentTestFactory.ID_FIELD)); + assertThat(command).usingRecursiveComparison().isEqualTo(patchAttachedItemCommandWithDifferentParent); + } + + } + + } + } + + @SuppressWarnings("unchecked") + private Document addItemNameToPatchAttachedItemCommand(Document patchAttachedItemCommand) { + var body = new HashMap<>((Map<String, Object>) patchAttachedItemCommand.get(CommandDocumentTestFactory.BODY_OBJECT_FIELD)); + body.put(ITEM_NAME_FIELD, BESCHEID_ITEM_NAME); + patchAttachedItemCommand.put(CommandDocumentTestFactory.BODY_OBJECT_FIELD, body); + return patchAttachedItemCommand; + } + + private class CommandDocumentTestFactory { + + private static final String ID_FIELD = "_id"; + public static final String ORDER_FIELD = "order"; + public static final String BODY_OBJECT_FIELD = "bodyObject"; + + public static final String VORGANG_ID = UUID.randomUUID().toString(); + public static final String CREATED_AT_STR = "2021-01-10T10:30:00Z"; + public static final Date CREATED_AT = Date.from(ZonedDateTime.parse(CREATED_AT_STR).toInstant()); + public static final String CREATED_BY = UUID.randomUUID().toString(); + public static final String CREATED_BY_NAME = LoremIpsum.getInstance().getName(); + public static final String CREATED_BY_CLIENT = LoremIpsum.getInstance().getWords(1); + public static final String STATUS = "PENDING"; + + public static final String RELATION_ID = UUID.randomUUID().toString(); + public static final Long RELATION_VERSION = 1L; + + public static final String ORDER = LoremIpsum.getInstance().getWords(1); + public static final Map<String, Object> PREVIOUS_STATE = Map.of("test", "value"); + public static final Map<String, Object> BODY = Map.of("key", "value"); + public static final String CREATED_RESOURCE = "createdResource"; + + public static Document create() { + var command = new Document(); + command.put(ID_FIELD, UUID.randomUUID().toString()); + command.put("vorgangId", VORGANG_ID); + command.put("createdAt", CREATED_AT); + command.put("createdBy", CREATED_BY); + command.put("createdByName", CREATED_BY_NAME); + command.put("createdByClientName", CREATED_BY_CLIENT); + command.put("status", STATUS); + command.put("relationId", RELATION_ID); + command.put("relationVersion", RELATION_VERSION); + command.put("previousState", PREVIOUS_STATE); + command.put(ORDER_FIELD, ORDER); + command.put(BODY_OBJECT_FIELD, BODY); + command.put("createdResource", CREATED_RESOURCE); + return command; + } + + public static Document createWithOrder(String order) { + var command = create(); + command.put(ORDER_FIELD, order); + return command; + } + + public static Document createWithBody(Map<String, Object> body) { + var command = create(); + command.put(BODY_OBJECT_FIELD, body); + return command; + } + + public static Document createWithOrderAndBody(String order, Map<String, Object> body) { + var command = createWithOrder(order); + command.put(BODY_OBJECT_FIELD, body); + return command; + } + } +} diff --git a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/MigrationDbTestUtils.java b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/MigrationDbTestUtils.java index beed899b7db19434be08fcd9e294dd134eca3e19..e2a0f66a4081be6329d0c1c027b544ea11cf9cbf 100644 --- a/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/MigrationDbTestUtils.java +++ b/vorgang-manager-server/src/test/java/de/ozgcloud/vorgang/common/migration/MigrationDbTestUtils.java @@ -53,7 +53,7 @@ class MigrationDbTestUtils { return template.save(doc, COMMAND_COLLECTION); } - public Document getCommand(ObjectId id) { + public Document getCommand(String id) { return template.findById(id, Document.class, COMMAND_COLLECTION); }