From 33c85cf787f0bebc036425c62a3cf4500458f24a Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Fri, 13 Sep 2024 11:15:01 +0200 Subject: [PATCH 01/17] Add directory move Signed-off-by: Seddik Yengui --- .../java/org/gridsuite/directory/server/DirectoryService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 09f2f3c0..909ddc51 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -337,9 +337,6 @@ private void moveElementDirectory(UUID elementUuid, UUID newDirectoryUuid, Strin } private void validateElementForMove(DirectoryElementEntity element, UUID newDirectoryUuid, String userId) { - if (element.getType().equals(DIRECTORY)) { - throw new DirectoryException(IS_DIRECTORY); - } if (!isDirectoryElementUpdatable(toElementAttributes(element), userId) || directoryHasElementOfNameAndType(newDirectoryUuid, element.getName(), element.getType())) { throw new DirectoryException(NOT_ALLOWED); From 079059166c2cecefe3417efd9f935084dbf6b542 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Fri, 13 Sep 2024 16:26:41 +0200 Subject: [PATCH 02/17] fix unit tests Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryException.java | 1 + .../directory/server/DirectoryService.java | 4 ++++ .../RestResponseEntityExceptionHandler.java | 2 ++ .../directory/server/DirectoryTest.java | 22 ++++++++++++++++++- 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryException.java b/src/main/java/org/gridsuite/directory/server/DirectoryException.java index ce7ab87d..c46feb49 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryException.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryException.java @@ -46,5 +46,6 @@ public enum Type { NOT_DIRECTORY, IS_DIRECTORY, UNKNOWN_NOTIFICATION, + IS_ROOT_DIRECTORY, } } diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 909ddc51..9c275f4d 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -337,6 +337,10 @@ private void moveElementDirectory(UUID elementUuid, UUID newDirectoryUuid, Strin } private void validateElementForMove(DirectoryElementEntity element, UUID newDirectoryUuid, String userId) { + if (Objects.equals(element.getType(), DIRECTORY) && element.getParentId() == null) { + throw new DirectoryException(IS_ROOT_DIRECTORY); + } + if (!isDirectoryElementUpdatable(toElementAttributes(element), userId) || directoryHasElementOfNameAndType(newDirectoryUuid, element.getName(), element.getType())) { throw new DirectoryException(NOT_ALLOWED); diff --git a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java index 67f01384..a440b0c1 100644 --- a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java +++ b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java @@ -40,6 +40,8 @@ protected ResponseEntity handleException(RuntimeException exception) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(NOT_FOUND); case UNKNOWN_NOTIFICATION: return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(UNKNOWN_NOTIFICATION); + case IS_ROOT_DIRECTORY: + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(IS_ROOT_DIRECTORY); default: return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index f16ea932..f6b6f811 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -586,9 +586,29 @@ public void testMoveDirectory() throws Exception { .header("userId", "Doe") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(List.of(directory21UUID)))) - .andExpect(status().isForbidden()); + .andExpect(status().isOk()); assertNbElementsInRepositories(3); + + Message message = output.receive(TIMEOUT, directoryUpdateDestination); + assertEquals("", new String(message.getPayload())); + MessageHeaders headers = message.getHeaders(); + assertEquals("Doe", headers.get(HEADER_USER_ID)); + assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(false, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); + assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); + + message = output.receive(TIMEOUT, directoryUpdateDestination); + assertEquals("", new String(message.getPayload())); + headers = message.getHeaders(); + assertEquals("Doe", headers.get(HEADER_USER_ID)); + assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(false, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); + assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); } @Test From 1104740ea36a9e1778780e2dae5e041143e9f12d Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 26 Sep 2024 15:24:53 +0200 Subject: [PATCH 03/17] fix Signed-off-by: Seddik Yengui --- .../java/org/gridsuite/directory/server/DirectoryService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 90be0a49..17863673 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -319,8 +319,8 @@ private void moveElementDirectory(UUID elementUuid, UUID newDirectoryUuid, Strin DirectoryElementEntity oldDirectory = repositoryService.getElementEntity(element.getParentId()).orElseThrow(); updateElementParentDirectory(element, newDirectoryUuid); - notifyDirectoryHasChanged(element.getParentId() == null ? element.getId() : element.getParentId(), userId, element.getName()); notifyDirectoryHasChanged(oldDirectory.getId(), userId, element.getName()); + notifyDirectoryHasChanged(newDirectoryUuid, userId, element.getName()); } From 8bf279ff83b3ddc3653fcd26170ddcf7f01aa50a Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 26 Sep 2024 16:15:45 +0200 Subject: [PATCH 04/17] fix unit tests Signed-off-by: Seddik Yengui --- .../java/org/gridsuite/directory/server/DirectoryService.java | 2 +- .../java/org/gridsuite/directory/server/DirectoryTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 17863673..883c5d20 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -319,8 +319,8 @@ private void moveElementDirectory(UUID elementUuid, UUID newDirectoryUuid, Strin DirectoryElementEntity oldDirectory = repositoryService.getElementEntity(element.getParentId()).orElseThrow(); updateElementParentDirectory(element, newDirectoryUuid); - notifyDirectoryHasChanged(oldDirectory.getId(), userId, element.getName()); notifyDirectoryHasChanged(newDirectoryUuid, userId, element.getName()); + notifyDirectoryHasChanged(oldDirectory.getId(), userId, element.getName()); } diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index 261cb2fe..06876192 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -595,7 +595,7 @@ public void testMoveDirectory() throws Exception { MessageHeaders headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); - assertEquals(false, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); @@ -605,7 +605,7 @@ public void testMoveDirectory() throws Exception { headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); - assertEquals(false, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); From c962fd12bfabe1b2ff8fc1be0cfee38b4a13655e Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Wed, 2 Oct 2024 14:30:50 +0200 Subject: [PATCH 05/17] fix directory move validation & unit tests Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryController.java | 2 +- .../directory/server/DirectoryException.java | 1 + .../directory/server/DirectoryService.java | 64 ++++++++++----- .../directory/server/NotificationService.java | 6 ++ .../RestResponseEntityExceptionHandler.java | 2 + .../DirectoryElementRepository.java | 23 +++--- .../services/DirectoryRepositoryService.java | 3 + .../server/DirectoryServiceTest.java | 2 +- .../directory/server/DirectoryTest.java | 78 +++++++++++++++---- 9 files changed, 135 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryController.java b/src/main/java/org/gridsuite/directory/server/DirectoryController.java index 9cf9a960..471f7729 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryController.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryController.java @@ -211,7 +211,7 @@ public ResponseEntity updateElement(@PathVariable("elementUuid") UUID elem @ApiResponse(responseCode = "403", description = "Not authorized execute this update") }) public ResponseEntity moveElementsDirectory( - @RequestParam UUID targetDirectoryUuid, + @RequestParam(required = false) UUID targetDirectoryUuid, @RequestBody List elementsUuids, @RequestHeader("userId") String userId) { service.moveElementsDirectory(elementsUuids, targetDirectoryUuid, userId); diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryException.java b/src/main/java/org/gridsuite/directory/server/DirectoryException.java index c46feb49..83cb87e7 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryException.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryException.java @@ -47,5 +47,6 @@ public enum Type { IS_DIRECTORY, UNKNOWN_NOTIFICATION, IS_ROOT_DIRECTORY, + IS_DESCENDENT } } diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 883c5d20..912f3aa5 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -306,27 +306,38 @@ public void moveElementsDirectory(List elementsUuids, UUID newDirectoryUui throw new DirectoryException(NOT_ALLOWED); } - validateNewDirectory(newDirectoryUuid); + List elementEntities = elementsUuids.stream().map(this::getDirectoryElementEntity).toList(); - elementsUuids.forEach(elementUuid -> moveElementDirectory(elementUuid, newDirectoryUuid, userId)); - } + // To validate the new directory, we need to know if the types of the elements are directories + boolean isDirectory = elementEntities.stream().allMatch(element -> Objects.equals(element.getType(), DIRECTORY)); + validateNewDirectory(newDirectoryUuid, isDirectory); - private void moveElementDirectory(UUID elementUuid, UUID newDirectoryUuid, String userId) { - DirectoryElementEntity element = repositoryService.getElementEntity(elementUuid) - .orElseThrow(() -> DirectoryException.createElementNotFound(ELEMENT, elementUuid)); + elementEntities.forEach(elementUuid -> moveElementDirectory(elementUuid, newDirectoryUuid, userId, isDirectory)); + } + private void moveElementDirectory(DirectoryElementEntity element, UUID newDirectoryUuid, String userId, boolean isDirectory) { validateElementForMove(element, newDirectoryUuid, userId); - DirectoryElementEntity oldDirectory = repositoryService.getElementEntity(element.getParentId()).orElseThrow(); + DirectoryElementEntity oldDirectory = element.getParentId() == null ? null : repositoryService.getElementEntity(element.getParentId()).orElseThrow(); updateElementParentDirectory(element, newDirectoryUuid); - notifyDirectoryHasChanged(newDirectoryUuid, userId, element.getName()); - notifyDirectoryHasChanged(oldDirectory.getId(), userId, element.getName()); + + // if it has a parent, we notify it. + // otherwise, which means it is a root, we send a notification that a root has been deleted (in this case, it is moved under a new directory) + if (oldDirectory != null) { + notifyDirectoryHasChanged(oldDirectory.getId(), userId, element.getName(), isDirectory); + } else { + notifyRootDirectoryDeleted(element.getId(), userId, element.getName()); + } + notifyDirectoryHasChanged(newDirectoryUuid, userId, element.getName(), isDirectory); } private void validateElementForMove(DirectoryElementEntity element, UUID newDirectoryUuid, String userId) { - if (Objects.equals(element.getType(), DIRECTORY) && element.getParentId() == null) { - throw new DirectoryException(IS_ROOT_DIRECTORY); + if (Objects.equals(element.getType(), DIRECTORY)) { + List descendents = repositoryService.findAllDescendants(element.getId()); + if (descendents.stream().map(DirectoryElementEntity::getId).anyMatch(uuid -> Objects.equals(uuid, newDirectoryUuid))) { + throw new DirectoryException(IS_DESCENDENT); + } } if (!isDirectoryElementUpdatable(toElementAttributes(element), userId) || @@ -340,12 +351,20 @@ private void updateElementParentDirectory(DirectoryElementEntity element, UUID n repositoryService.saveElement(element); } - private void validateNewDirectory(UUID newDirectoryUuid) { - DirectoryElementEntity newDirectory = repositoryService.getElementEntity(newDirectoryUuid) - .orElseThrow(() -> DirectoryException.createElementNotFound(DIRECTORY, newDirectoryUuid)); + private void validateNewDirectory(UUID newDirectoryUuid, boolean isDirectory) { + if (isDirectory) { + if (newDirectoryUuid == null) { + // We can not make directory root for the moment. + // To be removed when it is possible + throw new DirectoryException(IS_ROOT_DIRECTORY); + } + } else { + DirectoryElementEntity newDirectory = repositoryService.getElementEntity(newDirectoryUuid) + .orElseThrow(() -> DirectoryException.createElementNotFound(DIRECTORY, newDirectoryUuid)); - if (!newDirectory.getType().equals(DIRECTORY)) { - throw new DirectoryException(NOT_DIRECTORY); + if (!newDirectory.getType().equals(DIRECTORY)) { + throw new DirectoryException(NOT_DIRECTORY); + } } } @@ -562,15 +581,23 @@ public UUID getDirectoryUuidFromPath(List directoryPath) { // then we send a notification on this directory private void notifyDirectoryHasChanged(UUID directoryUuid, String userId) { Objects.requireNonNull(directoryUuid); - notifyDirectoryHasChanged(directoryUuid, userId, null, null); + notifyDirectoryHasChanged(directoryUuid, userId, null, null, false); } private void notifyDirectoryHasChanged(UUID directoryUuid, String userId, String elementName) { + notifyDirectoryHasChanged(directoryUuid, userId, elementName, false); + } + + private void notifyDirectoryHasChanged(UUID directoryUuid, String userId, String elementName, boolean isDirectoryMoving) { Objects.requireNonNull(directoryUuid); - notifyDirectoryHasChanged(directoryUuid, userId, elementName, null); + notifyDirectoryHasChanged(directoryUuid, userId, elementName, null, isDirectoryMoving); } private void notifyDirectoryHasChanged(UUID directoryUuid, String userId, String elementName, String error) { + notifyDirectoryHasChanged(directoryUuid, userId, elementName, error, false); + } + + private void notifyDirectoryHasChanged(UUID directoryUuid, String userId, String elementName, String error, boolean isDirectoryMoving) { Objects.requireNonNull(directoryUuid); notificationService.emitDirectoryChanged( directoryUuid, @@ -578,6 +605,7 @@ private void notifyDirectoryHasChanged(UUID directoryUuid, String userId, String userId, error, repositoryService.isRootDirectory(directoryUuid), + isDirectoryMoving, NotificationType.UPDATE_DIRECTORY ); } diff --git a/src/main/java/org/gridsuite/directory/server/NotificationService.java b/src/main/java/org/gridsuite/directory/server/NotificationService.java index 5b027273..bf574cc6 100644 --- a/src/main/java/org/gridsuite/directory/server/NotificationService.java +++ b/src/main/java/org/gridsuite/directory/server/NotificationService.java @@ -35,6 +35,7 @@ public class NotificationService { public static final String HEADER_NOTIFICATION_TYPE = "notificationType"; public static final String HEADER_ELEMENT_NAME = "elementName"; public static final String HEADER_ELEMENT_UUID = "elementUuid"; + public static final String HEADER_IS_DIRECTORY_MOVING = "isDirectoryMoving"; public static final String UPDATE_TYPE_ELEMENT_DELETE = "deleteElement"; private static final String CATEGORY_BROKER_OUTPUT = DirectoryService.class.getName() + ".output-broker-messages"; private static final Logger MESSAGE_OUTPUT_LOGGER = LoggerFactory.getLogger(CATEGORY_BROKER_OUTPUT); @@ -48,6 +49,10 @@ private void sendUpdateMessage(Message message) { } public void emitDirectoryChanged(UUID directoryUuid, String elementName, String userId, String error, boolean isRoot, NotificationType notificationType) { + emitDirectoryChanged(directoryUuid, elementName, userId, error, isRoot, false, notificationType); + } + + public void emitDirectoryChanged(UUID directoryUuid, String elementName, String userId, String error, boolean isRoot, boolean isDirectoryMoving, NotificationType notificationType) { MessageBuilder messageBuilder = MessageBuilder.withPayload("") .setHeader(HEADER_USER_ID, userId) .setHeader(HEADER_DIRECTORY_UUID, directoryUuid) @@ -56,6 +61,7 @@ public void emitDirectoryChanged(UUID directoryUuid, String elementName, String .setHeader(HEADER_IS_PUBLIC_DIRECTORY, true) // null may only come from borked REST request .setHeader(HEADER_NOTIFICATION_TYPE, notificationType) .setHeader(HEADER_UPDATE_TYPE, UPDATE_TYPE_DIRECTORIES) + .setHeader(HEADER_IS_DIRECTORY_MOVING, isDirectoryMoving) .setHeader(HEADER_ERROR, error); sendUpdateMessage(messageBuilder.build()); } diff --git a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java index a440b0c1..e3dbf5e7 100644 --- a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java +++ b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java @@ -42,6 +42,8 @@ protected ResponseEntity handleException(RuntimeException exception) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(UNKNOWN_NOTIFICATION); case IS_ROOT_DIRECTORY: return ResponseEntity.status(HttpStatus.FORBIDDEN).body(IS_ROOT_DIRECTORY); + case IS_DESCENDENT: + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(IS_DESCENDENT); default: return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } diff --git a/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java b/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java index 943629d9..8cee4f35 100644 --- a/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java +++ b/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java @@ -88,20 +88,17 @@ interface SubDirectoryCount { List findElementHierarchy(@Param("elementId") UUID elementId); @Query(nativeQuery = true, value = - "WITH RECURSIVE DescendantHierarchy (element_id, parent_element_id) AS (" + - " SELECT" + - " id AS element_id, parent_id AS parent_element_id" + - " FROM element where id = :elementId" + + "WITH RECURSIVE DescendantHierarchy (element_id, parent_element_id, depth) AS (" + + " SELECT id AS element_id, parent_id AS parent_element_id, 0 AS depth" + + " FROM element WHERE id = :elementId" + " UNION ALL" + - " select e.id AS element_id, e.parent_id AS parent_element_id" + + " SELECT e.id AS element_id, e.parent_id AS parent_element_id, dh.depth + 1" + " FROM element e" + - " INNER JOIN" + - " DescendantHierarchy dh" + - " ON dh.element_id = e.parent_id" + - " WHERE e.type = 'DIRECTORY' )" + - "SELECT * FROM element e" + - "JOIN" + - " DescendantHierarchy dh" + - " ON e.id = dh.element_id") + " INNER JOIN DescendantHierarchy dh ON dh.element_id = e.parent_id" + + " WHERE e.type = 'DIRECTORY')" + + "SELECT * FROM element e " + + "WHERE e.id IN (SELECT dh.element_id FROM DescendantHierarchy dh)" + ) List findAllDescendants(@Param("elementId") UUID elementId); + } diff --git a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java index 4e12b5e4..72c8d634 100644 --- a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java +++ b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java @@ -134,4 +134,7 @@ public List findElementHierarchy(UUID elementId) { return elementId == null ? List.of() : directoryElementRepository.findElementHierarchy(elementId); } + public List findAllDescendants(UUID elementId) { + return elementId == null ? List.of() : directoryElementRepository.findAllDescendants(elementId); + } } diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java index 9731baa9..2cbb98e1 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java @@ -86,7 +86,7 @@ void testDeleteMultipleElementsFromOneDirectory() { verify(notificationService, times(1)).emitDeletedElement(element2.getId(), "user1"); verify(notificationService, times(1)).emitDeletedElement(element0.getId(), "user1"); // notification for updated directory - verify(notificationService, times(1)).emitDirectoryChanged(parentDirectoryUuid, null, "user1", null, true, NotificationType.UPDATE_DIRECTORY); + verify(notificationService, times(1)).emitDirectoryChanged(parentDirectoryUuid, null, "user1", null, true, false, NotificationType.UPDATE_DIRECTORY); verifyNoMoreInteractions(notificationService); } diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index 06876192..0f14cb5a 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -381,8 +381,8 @@ public void testMoveElement() throws Exception { assertEquals("", new String(message.getPayload())); MessageHeaders headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); - assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(directory21UUID, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(false, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); @@ -392,8 +392,8 @@ public void testMoveElement() throws Exception { assertEquals("", new String(message.getPayload())); headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(directory21UUID, headers.get(HEADER_DIRECTORY_UUID)); - assertEquals(false, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); @@ -443,8 +443,8 @@ public void testMoveElementFromDifferentAccessRightsFolder() throws Exception { assertEquals("", new String(message.getPayload())); MessageHeaders headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); - assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(directory21PrivateUUID, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(false, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); @@ -453,8 +453,8 @@ public void testMoveElementFromDifferentAccessRightsFolder() throws Exception { assertEquals("", new String(message.getPayload())); headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(directory21PrivateUUID, headers.get(HEADER_DIRECTORY_UUID)); - assertEquals(false, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); @@ -594,7 +594,7 @@ public void testMoveDirectory() throws Exception { assertEquals("", new String(message.getPayload())); MessageHeaders headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); @@ -604,7 +604,7 @@ public void testMoveDirectory() throws Exception { assertEquals("", new String(message.getPayload())); headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); @@ -637,7 +637,7 @@ public void testElementMove() throws Exception { assertEquals("", new String(message.getPayload())); MessageHeaders headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); @@ -647,13 +647,45 @@ public void testElementMove() throws Exception { assertEquals("", new String(message.getPayload())); headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); } + @Test + public void testDirectoryMoveError() throws Exception { + UUID rootDir1Uuid = insertAndCheckRootDirectory("rootDir1", USER_ID); + + UUID rootDir2Uuid = insertAndCheckRootDirectory("rootDir2", USER_ID); + + UUID elementUuid1 = UUID.randomUUID(); + ElementAttributes elementAttributes1 = toElementAttributes(elementUuid1, "dir1", DIRECTORY, USER_ID); + insertAndCheckSubElementInRootDir(rootDir1Uuid, elementAttributes1); + + UUID elementUuid2 = UUID.randomUUID(); + ElementAttributes elementAttributes2 = toElementAttributes(elementUuid2, "dir2", DIRECTORY, USER_ID); + insertAndCheckSubElement(elementUuid1, elementAttributes2); + + // test move element to be root directory + mockMvc.perform(put("/v1/elements?targetDirectoryUuid=null") + .header("userId", USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(List.of(elementUuid1))) + ) + .andExpect(status().isBadRequest()); + + // test move element to one of its descendents + mockMvc.perform(put("/v1/elements?targetDirectoryUuid=" + elementUuid2) + .header("userId", USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(List.of(elementUuid1))) + ) + .andExpect(status().isForbidden()); + assertNbElementsInRepositories(4); + } + @Test public void testMoveRootDirectory() throws Exception { UUID rootDir10Uuid = insertAndCheckRootDirectory("rootDir10", "Doe"); @@ -670,7 +702,27 @@ public void testMoveRootDirectory() throws Exception { .header("userId", "Doe") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(List.of(rootDir10Uuid)))) - .andExpect(status().isForbidden()); + .andExpect(status().isOk()); + + Message message = output.receive(TIMEOUT, directoryUpdateDestination); + assertEquals("", new String(message.getPayload())); + MessageHeaders headers = message.getHeaders(); + assertEquals("Doe", headers.get(HEADER_USER_ID)); + assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); + assertEquals(NotificationType.DELETE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); + + message = output.receive(TIMEOUT, directoryUpdateDestination); + assertEquals("", new String(message.getPayload())); + headers = message.getHeaders(); + assertEquals("Doe", headers.get(HEADER_USER_ID)); + assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); + assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); assertNbElementsInRepositories(3); } From 9756edb178f5a5f31ee0c6c42559d8f65b64b54d Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 3 Oct 2024 01:25:14 +0200 Subject: [PATCH 06/17] fix Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryService.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 912f3aa5..49c38737 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -326,7 +326,7 @@ private void moveElementDirectory(DirectoryElementEntity element, UUID newDirect if (oldDirectory != null) { notifyDirectoryHasChanged(oldDirectory.getId(), userId, element.getName(), isDirectory); } else { - notifyRootDirectoryDeleted(element.getId(), userId, element.getName()); + notifyRootDirectoryDeleted(element.getId(), userId, element.getName(), isDirectory); } notifyDirectoryHasChanged(newDirectoryUuid, userId, element.getName(), isDirectory); @@ -355,7 +355,7 @@ private void validateNewDirectory(UUID newDirectoryUuid, boolean isDirectory) { if (isDirectory) { if (newDirectoryUuid == null) { // We can not make directory root for the moment. - // To be removed when it is possible + // To be removed when it becomes possible throw new DirectoryException(IS_ROOT_DIRECTORY); } } else { @@ -613,10 +613,15 @@ private void notifyDirectoryHasChanged(UUID directoryUuid, String userId, String // Root directories don't have parent directories. Then if on is deleted, we must send a specific notification private void notifyRootDirectoryDeleted(UUID rootDirectoryUuid, String userId, String elementName) { Objects.requireNonNull(rootDirectoryUuid); - notifyRootDirectoryDeleted(rootDirectoryUuid, userId, elementName, null); + notifyRootDirectoryDeleted(rootDirectoryUuid, userId, elementName, false); } - private void notifyRootDirectoryDeleted(UUID rootDirectoryUuid, String userId, String elementName, String error) { + private void notifyRootDirectoryDeleted(UUID rootDirectoryUuid, String userId, String elementName, boolean isDirectoryMoving) { + Objects.requireNonNull(rootDirectoryUuid); + notifyRootDirectoryDeleted(rootDirectoryUuid, userId, elementName, null, isDirectoryMoving); + } + + private void notifyRootDirectoryDeleted(UUID rootDirectoryUuid, String userId, String elementName, String error, boolean isDirectoryMoving) { Objects.requireNonNull(rootDirectoryUuid); notificationService.emitDirectoryChanged( rootDirectoryUuid, @@ -624,6 +629,7 @@ private void notifyRootDirectoryDeleted(UUID rootDirectoryUuid, String userId, S userId, error, true, + isDirectoryMoving, NotificationType.DELETE_DIRECTORY ); } From 59e661be4229c9392dce1671f513db6e70dfcda7 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Tue, 8 Oct 2024 12:40:03 +0200 Subject: [PATCH 07/17] fixes Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryService.java | 77 +++++++++++++------ .../server/dto/elasticsearch/Path.java | 30 ++++++++ .../DirectoryElementRepository.java | 19 ++++- .../services/DirectoryRepositoryService.java | 16 ++++ 4 files changed, 115 insertions(+), 27 deletions(-) create mode 100644 src/main/java/org/gridsuite/directory/server/dto/elasticsearch/Path.java diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index c358c7d4..0f35fd8d 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -10,6 +10,7 @@ import org.gridsuite.directory.server.dto.ElementAttributes; import org.gridsuite.directory.server.dto.RootDirectoryAttributes; import org.gridsuite.directory.server.dto.elasticsearch.DirectoryElementInfos; +import org.gridsuite.directory.server.dto.elasticsearch.Path; import org.gridsuite.directory.server.repository.DirectoryElementEntity; import org.gridsuite.directory.server.repository.DirectoryElementRepository; import org.gridsuite.directory.server.services.DirectoryElementInfosService; @@ -325,21 +326,27 @@ public void moveElementsDirectory(List elementsUuids, UUID newDirectoryUui throw new DirectoryException(NOT_ALLOWED); } - List elementEntities = elementsUuids.stream().map(this::getDirectoryElementEntity).toList(); + validateNewDirectory(newDirectoryUuid); - // To validate the new directory, we need to know if the types of the elements are directories - boolean isDirectory = elementEntities.stream().allMatch(element -> Objects.equals(element.getType(), DIRECTORY)); - validateNewDirectory(newDirectoryUuid, isDirectory); - - elementEntities.forEach(elementUuid -> moveElementDirectory(elementUuid, newDirectoryUuid, userId, isDirectory)); + elementsUuids.forEach(elementUuid -> moveElementDirectory(elementUuid, newDirectoryUuid, userId)); } - private void moveElementDirectory(DirectoryElementEntity element, UUID newDirectoryUuid, String userId, boolean isDirectory) { - validateElementForMove(element, newDirectoryUuid, userId); + private void moveElementDirectory(UUID elementsUuid, UUID newDirectoryUuid, String userId) { + DirectoryElementEntity element = getDirectoryElementEntity(elementsUuid); + boolean isDirectory = DIRECTORY.equals(element.getType()); + List descendentsUuid = isDirectory ? repositoryService.findAllDescendants(element.getId()).stream().map(DirectoryElementEntity::getId).toList() : List.of(); + validateElementForMove(element, newDirectoryUuid, userId, descendentsUuid); DirectoryElementEntity oldDirectory = element.getParentId() == null ? null : repositoryService.getElementEntity(element.getParentId()).orElseThrow(); + + // we update the parent of the moving element updateElementParentDirectory(element, newDirectoryUuid); + // if the moving element is directory and have descendents, we update the path for the descendents + if (isDirectory && !descendentsUuid.isEmpty()) { + updateElementDescendentsInfos(elementsUuid, descendentsUuid); + } + // if it has a parent, we notify it. // otherwise, which means it is a root, we send a notification that a root has been deleted (in this case, it is moved under a new directory) if (oldDirectory != null) { @@ -351,10 +358,40 @@ private void moveElementDirectory(DirectoryElementEntity element, UUID newDirect } - private void validateElementForMove(DirectoryElementEntity element, UUID newDirectoryUuid, String userId) { + private void updateElementDescendentsInfos(UUID elementsUuid, List descendentsUuids) { + // we store in this map all path of parent elements after the update + Map pathMap = new HashMap<>(); + + // we retrieve the descendents elasticsearch + List directoryElementInfos = repositoryService.getDirectoryElementInfos(descendentsUuids); + List updatedDescendents = new ArrayList<>(); + for (DirectoryElementInfos descendent : directoryElementInfos) { + UUID parentUuid = descendent.getParentId(); + + // we check if the path of the parent already exist, otherwise we retrieve it from database + if (!pathMap.containsKey(parentUuid)) { + pathMap.put(parentUuid, repositoryService.findPath(elementsUuid)); + } + + Path path = pathMap.get(parentUuid); + + // we update the paths + descendent.setPathUuid(path.getPathUuid()); + descendent.setPathName(path.getPathName()); + + // we add the updated descendent to the list + updatedDescendents.add(descendent); + } + + // we update all the descendents + repositoryService.saveElementsInfos(updatedDescendents); + } + + private void validateElementForMove(DirectoryElementEntity element, UUID newDirectoryUuid, String userId, List descendentsUuids) { if (Objects.equals(element.getType(), DIRECTORY)) { - List descendents = repositoryService.findAllDescendants(element.getId()); - if (descendents.stream().map(DirectoryElementEntity::getId).anyMatch(uuid -> Objects.equals(uuid, newDirectoryUuid))) { + + // We check if the new directory is the same or descendent of the moving element + if (newDirectoryUuid == element.getId() || descendentsUuids.stream().anyMatch(uuid -> Objects.equals(uuid, newDirectoryUuid))) { throw new DirectoryException(IS_DESCENDENT); } } @@ -370,20 +407,12 @@ private void updateElementParentDirectory(DirectoryElementEntity element, UUID n repositoryService.saveElement(element); } - private void validateNewDirectory(UUID newDirectoryUuid, boolean isDirectory) { - if (isDirectory) { - if (newDirectoryUuid == null) { - // We can not make directory root for the moment. - // To be removed when it becomes possible - throw new DirectoryException(IS_ROOT_DIRECTORY); - } - } else { - DirectoryElementEntity newDirectory = repositoryService.getElementEntity(newDirectoryUuid) - .orElseThrow(() -> DirectoryException.createElementNotFound(DIRECTORY, newDirectoryUuid)); + private void validateNewDirectory(UUID newDirectoryUuid) { + DirectoryElementEntity newDirectory = repositoryService.getElementEntity(newDirectoryUuid) + .orElseThrow(() -> DirectoryException.createElementNotFound(DIRECTORY, newDirectoryUuid)); - if (!newDirectory.getType().equals(DIRECTORY)) { - throw new DirectoryException(NOT_DIRECTORY); - } + if (!newDirectory.getType().equals(DIRECTORY)) { + throw new DirectoryException(NOT_DIRECTORY); } } diff --git a/src/main/java/org/gridsuite/directory/server/dto/elasticsearch/Path.java b/src/main/java/org/gridsuite/directory/server/dto/elasticsearch/Path.java new file mode 100644 index 00000000..e98eaabf --- /dev/null +++ b/src/main/java/org/gridsuite/directory/server/dto/elasticsearch/Path.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2024, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package org.gridsuite.directory.server.dto.elasticsearch; + +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.util.List; +import java.util.UUID; + +/** + * @author Seddik Yengui + */ + +@SuperBuilder +@NoArgsConstructor +@Setter +@Getter +@ToString +@EqualsAndHashCode +public class Path { + private List pathName; + + private List pathUuid; +} diff --git a/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java b/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java index 8cee4f35..e8827897 100644 --- a/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java +++ b/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java @@ -94,11 +94,24 @@ interface SubDirectoryCount { " UNION ALL" + " SELECT e.id AS element_id, e.parent_id AS parent_element_id, dh.depth + 1" + " FROM element e" + - " INNER JOIN DescendantHierarchy dh ON dh.element_id = e.parent_id" + - " WHERE e.type = 'DIRECTORY')" + + " INNER JOIN DescendantHierarchy dh ON dh.element_id = e.parent_id)" + "SELECT * FROM element e " + - "WHERE e.id IN (SELECT dh.element_id FROM DescendantHierarchy dh)" + "WHERE e.id IN (SELECT dh.element_id FROM DescendantHierarchy dh) AND e.id != :elementId" ) List findAllDescendants(@Param("elementId") UUID elementId); + @Query(nativeQuery = true, value = + "WITH RECURSIVE ElementHierarchy (element_id, parent_element_id, depth) AS ( " + + " SELECT id AS element_id, parent_id AS parent_element_id, 0 AS depth" + + " FROM element " + + " WHERE id = :elementId " + + " UNION ALL " + + " SELECT e.id AS element_id, e.parent_id AS parent_element_id, eh.depth + 1" + + " FROM element e " + + " INNER JOIN ElementHierarchy eh ON eh.parent_element_id = e.id " + + ") " + + "SELECT e.id, e.name FROM element e " + + "WHERE e.id in (SELECT eh.element_id from ElementHierarchy eh) " + + "ORDER BY (SELECT depth FROM ElementHierarchy WHERE element_id = e.id) DESC") + List findPath(@Param("elementId") UUID elementId); } diff --git a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java index 72c8d634..5fee23bf 100644 --- a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java +++ b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java @@ -9,6 +9,7 @@ import com.google.common.collect.Lists; import lombok.NonNull; import org.gridsuite.directory.server.dto.elasticsearch.DirectoryElementInfos; +import org.gridsuite.directory.server.dto.elasticsearch.Path; import org.gridsuite.directory.server.elasticsearch.DirectoryElementInfosRepository; import org.gridsuite.directory.server.repository.DirectoryElementEntity; import org.gridsuite.directory.server.repository.DirectoryElementRepository; @@ -18,6 +19,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.stream.StreamSupport; import static org.gridsuite.directory.server.DirectoryService.DIRECTORY; @@ -59,6 +61,10 @@ public boolean isElementExists(UUID parentDirectoryUuid, String elementName, Str return !directoryElementRepository.findByNameAndParentIdAndType(elementName, parentDirectoryUuid, type).isEmpty(); } + public List getDirectoryElementInfos(List elementUuids) { + return StreamSupport.stream(directoryElementInfosRepository.findAllById(elementUuids).spliterator(), false).toList(); + } + public void saveElementsInfos(@NonNull List directoryElementInfos) { Lists.partition(directoryElementInfos, partitionSize) .parallelStream() @@ -137,4 +143,14 @@ public List findElementHierarchy(UUID elementId) { public List findAllDescendants(UUID elementId) { return elementId == null ? List.of() : directoryElementRepository.findAllDescendants(elementId); } + + public Path findPath(UUID elementId) { + List pathObj = directoryElementRepository.findPath(elementId); + + // the first index in Object array is the id, the second is the name + return Path.builder() + .pathUuid(pathObj.stream().map(obj -> (UUID) obj[0]).toList()) + .pathName(pathObj.stream().map(obj -> (String) obj[1]).toList()) + .build(); + } } From ee47e5d717fcc3be53180878543c06e9620fd587 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Wed, 9 Oct 2024 04:20:14 +0200 Subject: [PATCH 08/17] add unit tests Signed-off-by: Seddik Yengui --- .../server/DirectoryServiceTest.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java index 7f9fabc8..d13d3a77 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java @@ -6,8 +6,10 @@ */ package org.gridsuite.directory.server; +import com.google.common.collect.ImmutableList; import org.gridsuite.directory.server.dto.ElementAttributes; import org.gridsuite.directory.server.dto.RootDirectoryAttributes; +import org.gridsuite.directory.server.dto.elasticsearch.DirectoryElementInfos; import org.gridsuite.directory.server.elasticsearch.DirectoryElementInfosRepository; import org.gridsuite.directory.server.repository.DirectoryElementEntity; import org.gridsuite.directory.server.repository.DirectoryElementRepository; @@ -20,6 +22,7 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -155,4 +158,86 @@ void testDirectoryElementUniqueness() { assertEquals(DirectoryException.createElementNameAlreadyExists(elementAttributes.getElementName()).getMessage(), directoryException.getMessage()); inOrder.verify(directoryService, calls(MAX_RETRY)).getDuplicateNameCandidate(root2Uuid, elementAttributes.getElementName(), elementAttributes.getType(), "User1"); } + + @Test + public void testMoveElement() { + // Create root + ElementAttributes rootAttributes = directoryService.createRootDirectory(new RootDirectoryAttributes("root", "user1", null, null, null, null), "user1"); + UUID rootUuid = rootAttributes.getElementUuid(); + + ElementAttributes root2Attributes = directoryService.createRootDirectory(new RootDirectoryAttributes("root2", "user1", null, null, null, null), "user1"); + UUID root2Uuid = root2Attributes.getElementUuid(); + + // Insert elements + ElementAttributes directoryElementAttributes = toElementAttributes(null, "dir", DIRECTORY, "user1"); + UUID dirUuid = directoryService.createElement(directoryElementAttributes, rootUuid, "user1", false).getElementUuid(); + verify(directoryElementRepository, times(2)).findById(rootUuid); + + ElementAttributes subDirectoryElementAttributes = toElementAttributes(null, "subDir", DIRECTORY, "user1"); + UUID subDirUuid = directoryService.createElement(subDirectoryElementAttributes, dirUuid, "user1", false).getElementUuid(); + verify(directoryElementRepository, times(2)).findById(dirUuid); + + ElementAttributes elementAttributes1 = toElementAttributes(null, "element1", "TYPE1", "user1"); + UUID elementUuid1 = directoryService.createElement(elementAttributes1, subDirUuid, "user1", false).getElementUuid(); + + ElementAttributes elementAttributes2 = toElementAttributes(null, "element2", "TYPE2", "user1"); + UUID elementUuid2 = directoryService.createElement(elementAttributes2, subDirUuid, "user1", false).getElementUuid(); + + ElementAttributes elementAttributes3 = toElementAttributes(null, "element3", "TYPE3", "user1"); + UUID elementUuid3 = directoryService.createElement(elementAttributes3, subDirUuid, "user1", false).getElementUuid(); + + // findById is called 2 times for each element created in subDirUuid + verify(directoryElementRepository, times(6)).findById(subDirUuid); + + verify(notificationService, times(1)).emitDirectoryChanged(subDirUuid, "element1", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); + verify(notificationService, times(1)).emitDirectoryChanged(subDirUuid, "element2", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); + + // we move element1 and element2 from subDir to dir + directoryService.moveElementsDirectory(List.of(elementUuid1, elementUuid2), dirUuid, "user1"); + // findById is called 3 more times. one time when validating the target directory. and two times when sending a notification for each element + verify(directoryElementRepository, times(5)).findById(dirUuid); + + verify(notificationService, times(2)).emitDirectoryChanged(subDirUuid, "element1", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); + verify(notificationService, times(1)).emitDirectoryChanged(dirUuid, "element1", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); + verify(notificationService, times(2)).emitDirectoryChanged(subDirUuid, "element2", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); + verify(notificationService, times(1)).emitDirectoryChanged(dirUuid, "element2", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); + + Optional elementEntity1 = directoryElementRepository.findById(elementUuid1); + Optional elementEntity2 = directoryElementRepository.findById(elementUuid2); + Optional elementEntity3 = directoryElementRepository.findById(elementUuid3); + assertTrue(elementEntity1.isPresent()); + assertTrue(elementEntity2.isPresent()); + assertTrue(elementEntity3.isPresent()); + assertEquals(dirUuid, elementEntity1.get().getParentId()); + assertEquals(dirUuid, elementEntity2.get().getParentId()); + assertEquals(subDirUuid, elementEntity3.get().getParentId()); + + // we move dir to root2 + directoryService.moveElementsDirectory(List.of(dirUuid), root2Uuid, "user1"); + verify(notificationService, times(1)).emitDirectoryChanged(rootUuid, "dir", "user1", null, true, true, NotificationType.UPDATE_DIRECTORY); + verify(notificationService, times(1)).emitDirectoryChanged(root2Uuid, "dir", "user1", null, true, true, NotificationType.UPDATE_DIRECTORY); + Optional dirEntity = directoryElementRepository.findById(dirUuid); + assertTrue(dirEntity.isPresent()); + assertEquals(root2Uuid, dirEntity.get().getParentId()); + + // we check that descendants' path have been updated + List descendants = directoryElementRepository.findAllDescendants(dirUuid); + Iterable infos = directoryElementInfosRepository.findAllById(descendants.stream().map(DirectoryElementEntity::getId).toList()); + assertTrue(ImmutableList.copyOf(infos).stream().allMatch(i -> Objects.equals(root2Uuid, i.getPathUuid().get(0)))); + + // Cases when moving element is rejected + // move directory to it's descendent + DirectoryException exception1 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(dirUuid), subDirUuid, "user1")); + assertEquals(DirectoryException.Type.IS_DESCENDENT.name(), exception1.getMessage()); + + // move element to another element with different type than directory + DirectoryException exception2 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(elementUuid1), elementUuid2, "user1")); + assertEquals(DirectoryException.Type.NOT_DIRECTORY.name(), exception2.getMessage()); + + // move element to not existent element + UUID randomUuid = UUID.randomUUID(); + DirectoryException exception3 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(elementUuid1), randomUuid, "user1")); + String expectedErrorMsg = DIRECTORY + " '" + randomUuid + "' not found !"; + assertEquals(expectedErrorMsg, exception3.getMessage()); + } } From f165e13b5d837fc710e9c671b05d7bea28972bdc Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Wed, 9 Oct 2024 04:36:56 +0200 Subject: [PATCH 09/17] add unit tests Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryServiceTest.java | 5 ----- .../org/gridsuite/directory/server/DirectoryTest.java | 11 +++++++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java index d13d3a77..48270801 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java @@ -220,11 +220,6 @@ public void testMoveElement() { assertTrue(dirEntity.isPresent()); assertEquals(root2Uuid, dirEntity.get().getParentId()); - // we check that descendants' path have been updated - List descendants = directoryElementRepository.findAllDescendants(dirUuid); - Iterable infos = directoryElementInfosRepository.findAllById(descendants.stream().map(DirectoryElementEntity::getId).toList()); - assertTrue(ImmutableList.copyOf(infos).stream().allMatch(i -> Objects.equals(root2Uuid, i.getPathUuid().get(0)))); - // Cases when moving element is rejected // move directory to it's descendent DirectoryException exception1 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(dirUuid), subDirUuid, "user1")); diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index c996ed03..1888863e 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -582,6 +582,11 @@ public void testMoveDirectory() throws Exception { UUID directory21UUID = UUID.randomUUID(); ElementAttributes directory20Attributes = toElementAttributes(directory21UUID, "directory20", DIRECTORY, "Doe"); insertAndCheckSubElementInRootDir(rootDir20Uuid, directory20Attributes); + ElementAttributes elementAttributes1 = toElementAttributes(UUID.randomUUID(), "element1", TYPE_01, "Doe"); + ElementAttributes elementAttributes2 = toElementAttributes(UUID.randomUUID(), "element2", TYPE_02, "Doe"); + insertAndCheckSubElement(directory21UUID, elementAttributes1); + insertAndCheckSubElement(directory21UUID, elementAttributes2); + mockMvc.perform(put("/v1/elements?targetDirectoryUuid=" + rootDir10Uuid) .header("userId", "Doe") @@ -659,8 +664,6 @@ public void testElementMove() throws Exception { public void testDirectoryMoveError() throws Exception { UUID rootDir1Uuid = insertAndCheckRootDirectory("rootDir1", USER_ID); - UUID rootDir2Uuid = insertAndCheckRootDirectory("rootDir2", USER_ID); - UUID elementUuid1 = UUID.randomUUID(); ElementAttributes elementAttributes1 = toElementAttributes(elementUuid1, "dir1", DIRECTORY, USER_ID); insertAndCheckSubElementInRootDir(rootDir1Uuid, elementAttributes1); @@ -669,8 +672,8 @@ public void testDirectoryMoveError() throws Exception { ElementAttributes elementAttributes2 = toElementAttributes(elementUuid2, "dir2", DIRECTORY, USER_ID); insertAndCheckSubElement(elementUuid1, elementAttributes2); - // test move element to be root directory - mockMvc.perform(put("/v1/elements?targetDirectoryUuid=null") + // test move element to be root directory targetDirectoryUuid = null + mockMvc.perform(put("/v1/elements") .header("userId", USER_ID) .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(List.of(elementUuid1))) From 61059c127245ab327f9682e108bdc6977d7f01f9 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Wed, 9 Oct 2024 04:54:48 +0200 Subject: [PATCH 10/17] fix Signed-off-by: Seddik Yengui --- .../org/gridsuite/directory/server/DirectoryServiceTest.java | 3 --- .../java/org/gridsuite/directory/server/DirectoryTest.java | 1 - 2 files changed, 4 deletions(-) diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java index 48270801..d5fe72b1 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java @@ -6,10 +6,8 @@ */ package org.gridsuite.directory.server; -import com.google.common.collect.ImmutableList; import org.gridsuite.directory.server.dto.ElementAttributes; import org.gridsuite.directory.server.dto.RootDirectoryAttributes; -import org.gridsuite.directory.server.dto.elasticsearch.DirectoryElementInfos; import org.gridsuite.directory.server.elasticsearch.DirectoryElementInfosRepository; import org.gridsuite.directory.server.repository.DirectoryElementEntity; import org.gridsuite.directory.server.repository.DirectoryElementRepository; @@ -22,7 +20,6 @@ import org.springframework.boot.test.mock.mockito.SpyBean; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.UUID; diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index 1888863e..7de95b0d 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -587,7 +587,6 @@ public void testMoveDirectory() throws Exception { insertAndCheckSubElement(directory21UUID, elementAttributes1); insertAndCheckSubElement(directory21UUID, elementAttributes2); - mockMvc.perform(put("/v1/elements?targetDirectoryUuid=" + rootDir10Uuid) .header("userId", "Doe") .contentType(MediaType.APPLICATION_JSON) From c9dcaf54ddfba1cdf9a89aa378efb5eb3d384f94 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Wed, 9 Oct 2024 11:14:27 +0200 Subject: [PATCH 11/17] fix Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryService.java | 2 +- .../repository/DirectoryElementRepository.java | 15 --------------- .../services/DirectoryRepositoryService.java | 7 +++---- .../gridsuite/directory/server/DirectoryTest.java | 4 ++-- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 0f35fd8d..70c73217 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -370,7 +370,7 @@ private void updateElementDescendentsInfos(UUID elementsUuid, List descend // we check if the path of the parent already exist, otherwise we retrieve it from database if (!pathMap.containsKey(parentUuid)) { - pathMap.put(parentUuid, repositoryService.findPath(elementsUuid)); + pathMap.put(parentUuid, repositoryService.findPath(parentUuid)); } Path path = pathMap.get(parentUuid); diff --git a/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java b/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java index e8827897..3b0e1c69 100644 --- a/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java +++ b/src/main/java/org/gridsuite/directory/server/repository/DirectoryElementRepository.java @@ -99,19 +99,4 @@ interface SubDirectoryCount { "WHERE e.id IN (SELECT dh.element_id FROM DescendantHierarchy dh) AND e.id != :elementId" ) List findAllDescendants(@Param("elementId") UUID elementId); - - @Query(nativeQuery = true, value = - "WITH RECURSIVE ElementHierarchy (element_id, parent_element_id, depth) AS ( " + - " SELECT id AS element_id, parent_id AS parent_element_id, 0 AS depth" + - " FROM element " + - " WHERE id = :elementId " + - " UNION ALL " + - " SELECT e.id AS element_id, e.parent_id AS parent_element_id, eh.depth + 1" + - " FROM element e " + - " INNER JOIN ElementHierarchy eh ON eh.parent_element_id = e.id " + - ") " + - "SELECT e.id, e.name FROM element e " + - "WHERE e.id in (SELECT eh.element_id from ElementHierarchy eh) " + - "ORDER BY (SELECT depth FROM ElementHierarchy WHERE element_id = e.id) DESC") - List findPath(@Param("elementId") UUID elementId); } diff --git a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java index 5fee23bf..fef038ad 100644 --- a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java +++ b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java @@ -145,12 +145,11 @@ public List findAllDescendants(UUID elementId) { } public Path findPath(UUID elementId) { - List pathObj = directoryElementRepository.findPath(elementId); + List path = findElementHierarchy(elementId); - // the first index in Object array is the id, the second is the name return Path.builder() - .pathUuid(pathObj.stream().map(obj -> (UUID) obj[0]).toList()) - .pathName(pathObj.stream().map(obj -> (String) obj[1]).toList()) + .pathUuid(path.stream().map(DirectoryElementEntity::getId).toList()) + .pathName(path.stream().map(DirectoryElementEntity::getName).toList()) .build(); } } diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index 7de95b0d..8d17f052 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -593,7 +593,7 @@ public void testMoveDirectory() throws Exception { .content(objectMapper.writeValueAsString(List.of(directory21UUID)))) .andExpect(status().isOk()); - assertNbElementsInRepositories(3); + assertNbElementsInRepositories(5); Message message = output.receive(TIMEOUT, directoryUpdateDestination); assertEquals("", new String(message.getPayload())); @@ -686,7 +686,7 @@ public void testDirectoryMoveError() throws Exception { .content(objectMapper.writeValueAsString(List.of(elementUuid1))) ) .andExpect(status().isForbidden()); - assertNbElementsInRepositories(4); + assertNbElementsInRepositories(3); } @Test From b7f7746a913ca4c700bfb2fe7a4509aa248af03c Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Wed, 9 Oct 2024 11:18:14 +0200 Subject: [PATCH 12/17] remove usless changes Signed-off-by: Seddik Yengui --- .../org/gridsuite/directory/server/DirectoryController.java | 2 +- .../java/org/gridsuite/directory/server/DirectoryException.java | 1 - .../directory/server/RestResponseEntityExceptionHandler.java | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryController.java b/src/main/java/org/gridsuite/directory/server/DirectoryController.java index 5e0d2bd3..467f068f 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryController.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryController.java @@ -211,7 +211,7 @@ public ResponseEntity updateElement(@PathVariable("elementUuid") UUID elem @ApiResponse(responseCode = "403", description = "Not authorized execute this update") }) public ResponseEntity moveElementsDirectory( - @RequestParam(required = false) UUID targetDirectoryUuid, + @RequestParam UUID targetDirectoryUuid, @RequestBody List elementsUuids, @RequestHeader("userId") String userId) { service.moveElementsDirectory(elementsUuids, targetDirectoryUuid, userId); diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryException.java b/src/main/java/org/gridsuite/directory/server/DirectoryException.java index 659421e8..b487ec21 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryException.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryException.java @@ -51,7 +51,6 @@ public enum Type { IS_DIRECTORY, UNKNOWN_NOTIFICATION, NAME_ALREADY_EXISTS, - IS_ROOT_DIRECTORY, IS_DESCENDENT } } diff --git a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java index 79a5705f..d21667b8 100644 --- a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java +++ b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java @@ -42,8 +42,6 @@ protected ResponseEntity handleException(RuntimeException exception) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(UNKNOWN_NOTIFICATION); case NAME_ALREADY_EXISTS: return ResponseEntity.status(HttpStatus.CONFLICT).body(directoryException.getMessage()); - case IS_ROOT_DIRECTORY: - return ResponseEntity.status(HttpStatus.FORBIDDEN).body(IS_ROOT_DIRECTORY); case IS_DESCENDENT: return ResponseEntity.status(HttpStatus.FORBIDDEN).body(IS_DESCENDENT); default: From 8dbd28f78d77cd5a2b2efbe4cb7f64b0ba018c98 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Wed, 9 Oct 2024 14:42:17 +0200 Subject: [PATCH 13/17] fix sonar error Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryService.java | 14 +++---- .../server/DirectoryServiceTest.java | 37 ++++++++++++------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 70c73217..41b85263 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -344,7 +344,7 @@ private void moveElementDirectory(UUID elementsUuid, UUID newDirectoryUuid, Stri // if the moving element is directory and have descendents, we update the path for the descendents if (isDirectory && !descendentsUuid.isEmpty()) { - updateElementDescendentsInfos(elementsUuid, descendentsUuid); + updateElementDescendentsInfos(descendentsUuid); } // if it has a parent, we notify it. @@ -358,7 +358,7 @@ private void moveElementDirectory(UUID elementsUuid, UUID newDirectoryUuid, Stri } - private void updateElementDescendentsInfos(UUID elementsUuid, List descendentsUuids) { + private void updateElementDescendentsInfos(List descendentsUuids) { // we store in this map all path of parent elements after the update Map pathMap = new HashMap<>(); @@ -388,12 +388,10 @@ private void updateElementDescendentsInfos(UUID elementsUuid, List descend } private void validateElementForMove(DirectoryElementEntity element, UUID newDirectoryUuid, String userId, List descendentsUuids) { - if (Objects.equals(element.getType(), DIRECTORY)) { - - // We check if the new directory is the same or descendent of the moving element - if (newDirectoryUuid == element.getId() || descendentsUuids.stream().anyMatch(uuid -> Objects.equals(uuid, newDirectoryUuid))) { - throw new DirectoryException(IS_DESCENDENT); - } + // We check if the new directory is the same or descendent of the moving element + if (DIRECTORY.equals(element.getType()) && + (newDirectoryUuid == element.getId() || descendentsUuids.stream().anyMatch(uuid -> Objects.equals(uuid, newDirectoryUuid)))) { + throw new DirectoryException(IS_DESCENDENT); } if (!isDirectoryElementUpdatable(toElementAttributes(element), userId) || diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java index d5fe72b1..6809e9db 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java @@ -157,7 +157,7 @@ void testDirectoryElementUniqueness() { } @Test - public void testMoveElement() { + void testMoveElement() { // Create root ElementAttributes rootAttributes = directoryService.createRootDirectory(new RootDirectoryAttributes("root", "user1", null, null, null, null), "user1"); UUID rootUuid = rootAttributes.getElementUuid(); @@ -168,11 +168,9 @@ public void testMoveElement() { // Insert elements ElementAttributes directoryElementAttributes = toElementAttributes(null, "dir", DIRECTORY, "user1"); UUID dirUuid = directoryService.createElement(directoryElementAttributes, rootUuid, "user1", false).getElementUuid(); - verify(directoryElementRepository, times(2)).findById(rootUuid); ElementAttributes subDirectoryElementAttributes = toElementAttributes(null, "subDir", DIRECTORY, "user1"); UUID subDirUuid = directoryService.createElement(subDirectoryElementAttributes, dirUuid, "user1", false).getElementUuid(); - verify(directoryElementRepository, times(2)).findById(dirUuid); ElementAttributes elementAttributes1 = toElementAttributes(null, "element1", "TYPE1", "user1"); UUID elementUuid1 = directoryService.createElement(elementAttributes1, subDirUuid, "user1", false).getElementUuid(); @@ -183,16 +181,11 @@ public void testMoveElement() { ElementAttributes elementAttributes3 = toElementAttributes(null, "element3", "TYPE3", "user1"); UUID elementUuid3 = directoryService.createElement(elementAttributes3, subDirUuid, "user1", false).getElementUuid(); - // findById is called 2 times for each element created in subDirUuid - verify(directoryElementRepository, times(6)).findById(subDirUuid); - verify(notificationService, times(1)).emitDirectoryChanged(subDirUuid, "element1", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); verify(notificationService, times(1)).emitDirectoryChanged(subDirUuid, "element2", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); // we move element1 and element2 from subDir to dir directoryService.moveElementsDirectory(List.of(elementUuid1, elementUuid2), dirUuid, "user1"); - // findById is called 3 more times. one time when validating the target directory. and two times when sending a notification for each element - verify(directoryElementRepository, times(5)).findById(dirUuid); verify(notificationService, times(2)).emitDirectoryChanged(subDirUuid, "element1", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); verify(notificationService, times(1)).emitDirectoryChanged(dirUuid, "element1", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); @@ -217,19 +210,35 @@ public void testMoveElement() { assertTrue(dirEntity.isPresent()); assertEquals(root2Uuid, dirEntity.get().getParentId()); - // Cases when moving element is rejected // move directory to it's descendent DirectoryException exception1 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(dirUuid), subDirUuid, "user1")); assertEquals(DirectoryException.Type.IS_DESCENDENT.name(), exception1.getMessage()); + } - // move element to another element with different type than directory - DirectoryException exception2 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(elementUuid1), elementUuid2, "user1")); - assertEquals(DirectoryException.Type.NOT_DIRECTORY.name(), exception2.getMessage()); + @Test + void testMoveElementNotExistentDirectory() { + ElementAttributes rootAttributes = directoryService.createRootDirectory(new RootDirectoryAttributes("root", "user1", null, null, null, null), "user1"); + UUID rootUuid = rootAttributes.getElementUuid(); + ElementAttributes elementAttributes = toElementAttributes(null, "element1", "TYPE1", "user1"); + UUID elementUuid = directoryService.createElement(elementAttributes, rootUuid, "user1", false).getElementUuid(); - // move element to not existent element UUID randomUuid = UUID.randomUUID(); - DirectoryException exception3 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(elementUuid1), randomUuid, "user1")); + DirectoryException exception3 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(elementUuid), randomUuid, "user1")); String expectedErrorMsg = DIRECTORY + " '" + randomUuid + "' not found !"; assertEquals(expectedErrorMsg, exception3.getMessage()); } + + @Test + void testMoveElementNotDirectoryElement() { + ElementAttributes rootAttributes = directoryService.createRootDirectory(new RootDirectoryAttributes("root", "user1", null, null, null, null), "user1"); + UUID rootUuid = rootAttributes.getElementUuid(); + + ElementAttributes elementAttributes1 = toElementAttributes(null, "element1", "TYPE1", "user1"); + UUID elementUuid1 = directoryService.createElement(elementAttributes1, rootUuid, "user1", false).getElementUuid(); + ElementAttributes elementAttributes2 = toElementAttributes(null, "element2", "TYPE2", "user1"); + UUID elementUuid2 = directoryService.createElement(elementAttributes2, rootUuid, "user1", false).getElementUuid(); + + DirectoryException exception2 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(elementUuid1), elementUuid2, "user1")); + assertEquals(DirectoryException.Type.NOT_DIRECTORY.name(), exception2.getMessage()); + } } From c6c069dda3817055a15485759f678603601d93b9 Mon Sep 17 00:00:00 2001 From: Slimane AMAR Date: Tue, 15 Oct 2024 13:39:36 +0200 Subject: [PATCH 14/17] Generalize optimization of element reindexing --- .../directory/server/DirectoryController.java | 2 +- .../directory/server/DirectoryException.java | 2 +- .../directory/server/DirectoryService.java | 63 +++++-------------- .../RestResponseEntityExceptionHandler.java | 4 +- .../server/dto/elasticsearch/Path.java | 30 --------- .../services/DirectoryRepositoryService.java | 49 +++++++-------- .../DirectoryElementInfosServiceTest.java | 21 +++---- .../server/DirectoryServiceTest.java | 24 ++++--- .../directory/server/SupervisionTest.java | 2 +- 9 files changed, 67 insertions(+), 130 deletions(-) delete mode 100644 src/main/java/org/gridsuite/directory/server/dto/elasticsearch/Path.java diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryController.java b/src/main/java/org/gridsuite/directory/server/DirectoryController.java index 467f068f..c1194f63 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryController.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryController.java @@ -206,7 +206,7 @@ public ResponseEntity updateElement(@PathVariable("elementUuid") UUID elem @PutMapping(value = "/elements", params = "targetDirectoryUuid") @Operation(summary = "Move elements within directory tree") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Elements was successfully updated"), + @ApiResponse(responseCode = "200", description = "Elements was successfully moved"), @ApiResponse(responseCode = "404", description = "The elements or the targeted directory was not found"), @ApiResponse(responseCode = "403", description = "Not authorized execute this update") }) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryException.java b/src/main/java/org/gridsuite/directory/server/DirectoryException.java index b487ec21..e98ef53d 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryException.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryException.java @@ -51,6 +51,6 @@ public enum Type { IS_DIRECTORY, UNKNOWN_NOTIFICATION, NAME_ALREADY_EXISTS, - IS_DESCENDENT + MOVE_IN_DESCENDANT_NOT_ALLOWED, } } diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 41b85263..7163008f 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -10,7 +10,6 @@ import org.gridsuite.directory.server.dto.ElementAttributes; import org.gridsuite.directory.server.dto.RootDirectoryAttributes; import org.gridsuite.directory.server.dto.elasticsearch.DirectoryElementInfos; -import org.gridsuite.directory.server.dto.elasticsearch.Path; import org.gridsuite.directory.server.repository.DirectoryElementEntity; import org.gridsuite.directory.server.repository.DirectoryElementRepository; import org.gridsuite.directory.server.services.DirectoryElementInfosService; @@ -31,6 +30,7 @@ import java.time.temporal.ChronoUnit; import java.util.*; import java.util.function.Consumer; +import java.util.stream.Collectors; import java.util.stream.Stream; import static org.gridsuite.directory.server.DirectoryException.Type.*; @@ -328,24 +328,26 @@ public void moveElementsDirectory(List elementsUuids, UUID newDirectoryUui validateNewDirectory(newDirectoryUuid); - elementsUuids.forEach(elementUuid -> moveElementDirectory(elementUuid, newDirectoryUuid, userId)); + elementsUuids.forEach(elementUuid -> moveElementDirectory(getDirectoryElementEntity(elementUuid), newDirectoryUuid, userId)); } - private void moveElementDirectory(UUID elementsUuid, UUID newDirectoryUuid, String userId) { - DirectoryElementEntity element = getDirectoryElementEntity(elementsUuid); - boolean isDirectory = DIRECTORY.equals(element.getType()); - List descendentsUuid = isDirectory ? repositoryService.findAllDescendants(element.getId()).stream().map(DirectoryElementEntity::getId).toList() : List.of(); - validateElementForMove(element, newDirectoryUuid, userId, descendentsUuid); + private void moveElementDirectory(DirectoryElementEntity element, UUID newDirectoryUuid, String userId) { + if (element.getParentId() == newDirectoryUuid) { // Same directory ? + return; + } DirectoryElementEntity oldDirectory = element.getParentId() == null ? null : repositoryService.getElementEntity(element.getParentId()).orElseThrow(); + boolean isDirectory = DIRECTORY.equals(element.getType()); + List descendents = isDirectory ? repositoryService.findAllDescendants(element.getId()).stream().toList() : List.of(); + + // validate move elements + validateElementForMove(element, newDirectoryUuid, userId, descendents.stream().map(DirectoryElementEntity::getId).collect(Collectors.toSet())); // we update the parent of the moving element updateElementParentDirectory(element, newDirectoryUuid); - // if the moving element is directory and have descendents, we update the path for the descendents - if (isDirectory && !descendentsUuid.isEmpty()) { - updateElementDescendentsInfos(descendentsUuid); - } + // reindex descendents + repositoryService.reindexElements(descendents); // if it has a parent, we notify it. // otherwise, which means it is a root, we send a notification that a root has been deleted (in this case, it is moved under a new directory) @@ -358,40 +360,9 @@ private void moveElementDirectory(UUID elementsUuid, UUID newDirectoryUuid, Stri } - private void updateElementDescendentsInfos(List descendentsUuids) { - // we store in this map all path of parent elements after the update - Map pathMap = new HashMap<>(); - - // we retrieve the descendents elasticsearch - List directoryElementInfos = repositoryService.getDirectoryElementInfos(descendentsUuids); - List updatedDescendents = new ArrayList<>(); - for (DirectoryElementInfos descendent : directoryElementInfos) { - UUID parentUuid = descendent.getParentId(); - - // we check if the path of the parent already exist, otherwise we retrieve it from database - if (!pathMap.containsKey(parentUuid)) { - pathMap.put(parentUuid, repositoryService.findPath(parentUuid)); - } - - Path path = pathMap.get(parentUuid); - - // we update the paths - descendent.setPathUuid(path.getPathUuid()); - descendent.setPathName(path.getPathName()); - - // we add the updated descendent to the list - updatedDescendents.add(descendent); - } - - // we update all the descendents - repositoryService.saveElementsInfos(updatedDescendents); - } - - private void validateElementForMove(DirectoryElementEntity element, UUID newDirectoryUuid, String userId, List descendentsUuids) { - // We check if the new directory is the same or descendent of the moving element - if (DIRECTORY.equals(element.getType()) && - (newDirectoryUuid == element.getId() || descendentsUuids.stream().anyMatch(uuid -> Objects.equals(uuid, newDirectoryUuid)))) { - throw new DirectoryException(IS_DESCENDENT); + private void validateElementForMove(DirectoryElementEntity element, UUID newDirectoryUuid, String userId, Set descendentsUuids) { + if (newDirectoryUuid == element.getId() || descendentsUuids.contains(newDirectoryUuid)) { + throw new DirectoryException(MOVE_IN_DESCENDANT_NOT_ALLOWED); } if (!isDirectoryElementUpdatable(toElementAttributes(element), userId) || @@ -502,7 +473,7 @@ public void deleteElements(List elementsUuids, UUID parentDirectoryUuid, S * @return ElementAttributes of element and all it's parents up to root directory */ public List getPath(UUID elementUuid) { - List path = repositoryService.findElementHierarchy(elementUuid).stream().map(ElementAttributes::toElementAttributes).toList(); + List path = repositoryService.getPath(elementUuid).stream().map(ElementAttributes::toElementAttributes).toList(); if (path.isEmpty()) { throw DirectoryException.createElementNotFound(ELEMENT, elementUuid); } diff --git a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java index d21667b8..f10d7329 100644 --- a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java +++ b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java @@ -42,8 +42,8 @@ protected ResponseEntity handleException(RuntimeException exception) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(UNKNOWN_NOTIFICATION); case NAME_ALREADY_EXISTS: return ResponseEntity.status(HttpStatus.CONFLICT).body(directoryException.getMessage()); - case IS_DESCENDENT: - return ResponseEntity.status(HttpStatus.FORBIDDEN).body(IS_DESCENDENT); + case MOVE_IN_DESCENDANT_NOT_ALLOWED: + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(MOVE_IN_DESCENDANT_NOT_ALLOWED); default: return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } diff --git a/src/main/java/org/gridsuite/directory/server/dto/elasticsearch/Path.java b/src/main/java/org/gridsuite/directory/server/dto/elasticsearch/Path.java deleted file mode 100644 index e98eaabf..00000000 --- a/src/main/java/org/gridsuite/directory/server/dto/elasticsearch/Path.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2024, RTE (http://www.rte-france.com) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -package org.gridsuite.directory.server.dto.elasticsearch; - -import lombok.*; -import lombok.experimental.SuperBuilder; - -import java.util.List; -import java.util.UUID; - -/** - * @author Seddik Yengui - */ - -@SuperBuilder -@NoArgsConstructor -@Setter -@Getter -@ToString -@EqualsAndHashCode -public class Path { - private List pathName; - - private List pathUuid; -} diff --git a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java index fef038ad..cbfb71dc 100644 --- a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java +++ b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java @@ -9,17 +9,13 @@ import com.google.common.collect.Lists; import lombok.NonNull; import org.gridsuite.directory.server.dto.elasticsearch.DirectoryElementInfos; -import org.gridsuite.directory.server.dto.elasticsearch.Path; import org.gridsuite.directory.server.elasticsearch.DirectoryElementInfosRepository; import org.gridsuite.directory.server.repository.DirectoryElementEntity; import org.gridsuite.directory.server.repository.DirectoryElementRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.StreamSupport; +import java.util.*; import static org.gridsuite.directory.server.DirectoryService.DIRECTORY; @@ -61,23 +57,23 @@ public boolean isElementExists(UUID parentDirectoryUuid, String elementName, Str return !directoryElementRepository.findByNameAndParentIdAndType(elementName, parentDirectoryUuid, type).isEmpty(); } - public List getDirectoryElementInfos(List elementUuids) { - return StreamSupport.stream(directoryElementInfosRepository.findAllById(elementUuids).spliterator(), false).toList(); - } - - public void saveElementsInfos(@NonNull List directoryElementInfos) { + private void saveElementsInfos(List directoryElements) { + Map> pathsCache = new HashMap<>(); + List directoryElementInfos = directoryElements.stream() + .map(directoryElementEntity -> directoryElementEntity.toDirectoryElementInfos(getPath(directoryElementEntity.getParentId(), pathsCache))) + .toList(); Lists.partition(directoryElementInfos, partitionSize) .parallelStream() .forEach(directoryElementInfosRepository::saveAll); } - private DirectoryElementEntity saveElementsInfo(DirectoryElementEntity elementEntity) { - directoryElementInfosRepository.save(elementEntity.toDirectoryElementInfos(findElementHierarchy(elementEntity.getParentId()))); + private DirectoryElementEntity saveElementInfos(DirectoryElementEntity elementEntity) { + directoryElementInfosRepository.save(elementEntity.toDirectoryElementInfos(getPath(elementEntity.getParentId()))); return elementEntity; } public DirectoryElementEntity saveElement(DirectoryElementEntity elementEntity) { - return saveElementsInfo(directoryElementRepository.save(elementEntity)); + return saveElementInfos(directoryElementRepository.save(elementEntity)); } public void deleteElement(UUID elementUuid) { @@ -95,9 +91,11 @@ public boolean canRead(UUID id, String userId) { } public void reindexElements() { - saveElementsInfos(directoryElementRepository.findAll().stream() - .map(directoryElementEntity -> directoryElementEntity.toDirectoryElementInfos(findElementHierarchy(directoryElementEntity.getParentId()))) - .toList()); + reindexElements(directoryElementRepository.findAll()); + } + + public void reindexElements(@NonNull List elementEntities) { + saveElementsInfos(elementEntities); } public UUID getParentUuid(UUID elementUuid) { @@ -135,21 +133,16 @@ public List getNameByTypeAndParentIdAndNameStartWith(String type, UUID p return directoryElementRepository.getNameByTypeAndParentIdAndNameStartWith(type, parentId, name); } - public List findElementHierarchy(UUID elementId) { - // Test null for root directories - return elementId == null ? List.of() : directoryElementRepository.findElementHierarchy(elementId); + public List getPath(UUID elementId) { + return getPath(elementId, new HashMap<>()); } - public List findAllDescendants(UUID elementId) { - return elementId == null ? List.of() : directoryElementRepository.findAllDescendants(elementId); + public List getPath(UUID elementId, Map> pathsCache) { + // Test null for root directories + return elementId == null ? List.of() : pathsCache.computeIfAbsent(elementId, directoryElementRepository::findElementHierarchy); } - public Path findPath(UUID elementId) { - List path = findElementHierarchy(elementId); - - return Path.builder() - .pathUuid(path.stream().map(DirectoryElementEntity::getId).toList()) - .pathName(path.stream().map(DirectoryElementEntity::getName).toList()) - .build(); + public List findAllDescendants(@NonNull UUID elementId) { + return directoryElementRepository.findAllDescendants(elementId); } } diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryElementInfosServiceTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryElementInfosServiceTest.java index 79ed1eb9..6d653f44 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryElementInfosServiceTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryElementInfosServiceTest.java @@ -11,7 +11,6 @@ import org.gridsuite.directory.server.dto.elasticsearch.DirectoryElementInfos; import org.gridsuite.directory.server.elasticsearch.DirectoryElementInfosRepository; import org.gridsuite.directory.server.services.DirectoryElementInfosService; -import org.gridsuite.directory.server.services.DirectoryRepositoryService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -39,8 +38,6 @@ class DirectoryElementInfosServiceTest { public static final String TYPE_03 = "TYPE_03"; public static final String TYPE_04 = "TYPE_04"; public static final String DIRECTORY = "DIRECTORY"; - @Autowired - DirectoryRepositoryService repositoryService; @Autowired DirectoryElementInfosRepository directoryElementInfosRepository; @@ -66,7 +63,7 @@ void testAddDeleteElementInfos() { // Add List infos = List.of(element1Infos, element2Infos, directoryInfos, element3Infos); - repositoryService.saveElementsInfos(infos); + directoryElementInfosRepository.saveAll(infos); List infosDB = IterableUtils.toList(directoryElementInfosRepository.findAll()); assertEquals(4, infosDB.size()); assertEquals(infos, infosDB); @@ -90,7 +87,7 @@ void searchElementInfos() { var element3Infos = DirectoryElementInfos.builder().id(UUID.randomUUID()).name("elementName3").type(TYPE_03).owner("admin").parentId(UUID.randomUUID()).subdirectoriesCount(0L).lastModificationDate(Instant.now().truncatedTo(ChronoUnit.SECONDS)).build(); List infos = List.of(directoryInfos, element2Infos, element1Infos, element4Infos, element3Infos); - repositoryService.saveElementsInfos(infos); + directoryElementInfosRepository.saveAll(infos); Set hits = new HashSet<>(directoryElementInfosService.searchElements("a", "", PageRequest.of(0, 10)).stream().toList()); assertEquals(4, hits.size()); @@ -115,7 +112,7 @@ void searchPagedElementInfos() { for (int i = 0; i < 20; i++) { elements.add(createElements("filter" + i)); } - repositoryService.saveElementsInfos(elements); + directoryElementInfosRepository.saveAll(elements); Page pagedHits = directoryElementInfosService.searchElements("filter", "", PageRequest.of(0, 10)); assertEquals(20, pagedHits.getTotalElements()); assertEquals(10, pagedHits.getContent().size()); @@ -126,7 +123,7 @@ void searchSpecialChars() { var studyInfos = DirectoryElementInfos.builder().id(UUID.randomUUID()).name("s+Ss+ss'sp&pn(n n)ne{e e}ette|eh-ht.th/hl\\lk[k k]k") .type(TYPE_01).owner("admin1").parentId(UUID.randomUUID()) .subdirectoriesCount(0L).lastModificationDate(Instant.now().truncatedTo(ChronoUnit.SECONDS)).build(); - repositoryService.saveElementsInfos(List.of(studyInfos)); + directoryElementInfosRepository.saveAll(List.of(studyInfos)); testNameFullAscii("s+S"); testNameFullAscii("s+s"); @@ -209,12 +206,12 @@ HashMap createFilesElements() { var commonFile5 = makeElementFile("common_file", allDirs.get("sub_sub_directory3_1").getId()); var commonFile6 = makeElementFile("common_file", allDirs.get("sub_sub_directory3_2").getId()); - repositoryService.saveElementsInfos(allDirs.values().stream().toList()); + directoryElementInfosRepository.saveAll(allDirs.values().stream().toList()); List infos = List.of( file1, file2, file3, commonFile1, commonFile2, commonFile3, commonFile4, commonFile5, commonFile6); - repositoryService.saveElementsInfos(infos); + directoryElementInfosRepository.saveAll(infos); return allDirs; } @@ -267,7 +264,7 @@ void testExactMatchingParentDirectory() { // when a file is in a sub directory o var newFile1 = makeElementFile("new-file", allDirs.get("sub_directory2").getId()); var newFile2 = makeElementFile("new-file", allDirs.get("sub_sub_directory2_2").getId()); var newFile3 = makeElementFile("new-file", allDirs.get("sub_sub_directory3_1").getId()); - repositoryService.saveElementsInfos(List.of(newFile1, newFile2, newFile3)); + directoryElementInfosRepository.saveAll(List.of(newFile1, newFile2, newFile3)); //we want to have the files in the current directory if any // then the files in the path of the current directory (sub directories and parent directories) @@ -298,7 +295,7 @@ void testExactMatchInCurrentDir() { var newFile = makeElementFile(fileName, allDirs.get("sub_sub_directory1_2").getId()); var newFile1 = makeElementFile(fileName + "1", allDirs.get("sub_sub_directory1_2").getId()); var newFile2 = makeElementFile("1" + fileName + "2", allDirs.get("sub_sub_directory1_2").getId()); - repositoryService.saveElementsInfos(List.of(newFile, newFile2, newFile1)); + directoryElementInfosRepository.saveAll(List.of(newFile, newFile2, newFile1)); List hitsFile = directoryElementInfosService.searchElements(fileName, currentDirUuid.toString(), PageRequest.of(0, 10)).stream().toList(); assertEquals(3, hitsFile.size()); assertEquals(fileName, hitsFile.get(0).getName()); @@ -325,7 +322,7 @@ void testTermStartByUserInput() { // when a file start with search term var newFile2 = makeElementFile("new-file-Ok", allDirs.get("sub_directory2").getId()); var bNewFile = makeElementFile("bnew-filebbbb", allDirs.get("sub_directory2").getId()); var testNewFile = makeElementFile("test-new-file", allDirs.get("sub_directory2").getId()); - repositoryService.saveElementsInfos(List.of(bNewFile, newFile2, anewFile1, testNewFile)); + directoryElementInfosRepository.saveAll(List.of(bNewFile, newFile2, anewFile1, testNewFile)); //we want to have the files in the current directory if any // then the files in the path of the current directory (sub directories and parent directories) diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java index 6809e9db..8bcc7c63 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java @@ -185,7 +185,9 @@ void testMoveElement() { verify(notificationService, times(1)).emitDirectoryChanged(subDirUuid, "element2", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); // we move element1 and element2 from subDir to dir + reset(directoryElementRepository); directoryService.moveElementsDirectory(List.of(elementUuid1, elementUuid2), dirUuid, "user1"); + verify(directoryElementRepository, times(2)).findElementHierarchy(any(UUID.class)); verify(notificationService, times(2)).emitDirectoryChanged(subDirUuid, "element1", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); verify(notificationService, times(1)).emitDirectoryChanged(dirUuid, "element1", "user1", null, false, false, NotificationType.UPDATE_DIRECTORY); @@ -203,7 +205,9 @@ void testMoveElement() { assertEquals(subDirUuid, elementEntity3.get().getParentId()); // we move dir to root2 + reset(directoryElementRepository); directoryService.moveElementsDirectory(List.of(dirUuid), root2Uuid, "user1"); + verify(directoryElementRepository, times(3)).findElementHierarchy(any(UUID.class)); verify(notificationService, times(1)).emitDirectoryChanged(rootUuid, "dir", "user1", null, true, true, NotificationType.UPDATE_DIRECTORY); verify(notificationService, times(1)).emitDirectoryChanged(root2Uuid, "dir", "user1", null, true, true, NotificationType.UPDATE_DIRECTORY); Optional dirEntity = directoryElementRepository.findById(dirUuid); @@ -211,25 +215,26 @@ void testMoveElement() { assertEquals(root2Uuid, dirEntity.get().getParentId()); // move directory to it's descendent - DirectoryException exception1 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(dirUuid), subDirUuid, "user1")); - assertEquals(DirectoryException.Type.IS_DESCENDENT.name(), exception1.getMessage()); + List list = List.of(dirUuid); // Just for Sonar issue (assertThrows) + DirectoryException exception1 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(list, subDirUuid, "user1")); + assertEquals(DirectoryException.Type.MOVE_IN_DESCENDANT_NOT_ALLOWED, exception1.getType()); } @Test - void testMoveElementNotExistentDirectory() { + void testMoveInNotExistingDirectory() { ElementAttributes rootAttributes = directoryService.createRootDirectory(new RootDirectoryAttributes("root", "user1", null, null, null, null), "user1"); UUID rootUuid = rootAttributes.getElementUuid(); ElementAttributes elementAttributes = toElementAttributes(null, "element1", "TYPE1", "user1"); UUID elementUuid = directoryService.createElement(elementAttributes, rootUuid, "user1", false).getElementUuid(); UUID randomUuid = UUID.randomUUID(); - DirectoryException exception3 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(elementUuid), randomUuid, "user1")); - String expectedErrorMsg = DIRECTORY + " '" + randomUuid + "' not found !"; - assertEquals(expectedErrorMsg, exception3.getMessage()); + List list = List.of(elementUuid); // Just for Sonar issue (assertThrows) + DirectoryException exception3 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(list, randomUuid, "user1")); + assertEquals(DirectoryException.createElementNotFound(DIRECTORY, randomUuid).getMessage(), exception3.getMessage()); } @Test - void testMoveElementNotDirectoryElement() { + void testMoveInNotDirectory() { ElementAttributes rootAttributes = directoryService.createRootDirectory(new RootDirectoryAttributes("root", "user1", null, null, null, null), "user1"); UUID rootUuid = rootAttributes.getElementUuid(); @@ -238,7 +243,8 @@ void testMoveElementNotDirectoryElement() { ElementAttributes elementAttributes2 = toElementAttributes(null, "element2", "TYPE2", "user1"); UUID elementUuid2 = directoryService.createElement(elementAttributes2, rootUuid, "user1", false).getElementUuid(); - DirectoryException exception2 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(List.of(elementUuid1), elementUuid2, "user1")); - assertEquals(DirectoryException.Type.NOT_DIRECTORY.name(), exception2.getMessage()); + List list = List.of(elementUuid1); // Just for Sonar issue (assertThrows) + DirectoryException exception2 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(list, elementUuid2, "user1")); + assertEquals(DirectoryException.Type.NOT_DIRECTORY, exception2.getType()); } } diff --git a/src/test/java/org/gridsuite/directory/server/SupervisionTest.java b/src/test/java/org/gridsuite/directory/server/SupervisionTest.java index cadc1d03..9c3fa37e 100644 --- a/src/test/java/org/gridsuite/directory/server/SupervisionTest.java +++ b/src/test/java/org/gridsuite/directory/server/SupervisionTest.java @@ -78,7 +78,7 @@ void testReindexElements() { List elementPath = List.of(); // No need path for tests verify(directoryElementRepository, times(1)).findAll(); verify(directoryElementInfosRepository, times(1)).saveAll(allElements.stream().map(e -> e.toDirectoryElementInfos(elementPath)).toList()); - verify(directoryElementRepository, times(3)).findElementHierarchy(any(UUID.class)); + verify(directoryElementRepository, times(2)).findElementHierarchy(any(UUID.class)); } @AfterEach From 6c863e7e7da16275c5b121d10c1557e6884e87a7 Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Tue, 15 Oct 2024 14:50:23 +0200 Subject: [PATCH 15/17] add unit test Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryService.java | 2 +- .../directory/server/DirectoryTest.java | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 7163008f..21a44bda 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -350,7 +350,7 @@ private void moveElementDirectory(DirectoryElementEntity element, UUID newDirect repositoryService.reindexElements(descendents); // if it has a parent, we notify it. - // otherwise, which means it is a root, we send a notification that a root has been deleted (in this case, it is moved under a new directory) + // otherwise, which means it is a root, we send a notification that a root has been deleted (in this case, it moved under a new directory) if (oldDirectory != null) { notifyDirectoryHasChanged(oldDirectory.getId(), userId, element.getName(), isDirectory); } else { diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index 8d17f052..d02dbc5f 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -602,6 +602,7 @@ public void testMoveDirectory() throws Exception { assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_DIRECTORY_MOVING)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); @@ -612,8 +613,40 @@ public void testMoveDirectory() throws Exception { assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_DIRECTORY_MOVING)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); + + // test move root directory + mockMvc.perform(put("/v1/elements?targetDirectoryUuid=" + rootDir10Uuid) + .header("userId", "Doe") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(List.of(rootDir20Uuid)))) + .andExpect(status().isOk()); + + message = output.receive(TIMEOUT, directoryUpdateDestination); + assertEquals("", new String(message.getPayload())); + headers = message.getHeaders(); + assertEquals("Doe", headers.get(HEADER_USER_ID)); + assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_DIRECTORY_MOVING)); + assertEquals(NotificationType.DELETE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); + assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); + + message = output.receive(TIMEOUT, directoryUpdateDestination); + assertEquals("", new String(message.getPayload())); + headers = message.getHeaders(); + assertEquals("Doe", headers.get(HEADER_USER_ID)); + assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(true, headers.get(HEADER_IS_DIRECTORY_MOVING)); + assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); + assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); + + assertNbElementsInRepositories(5); } @Test @@ -645,6 +678,7 @@ public void testElementMove() throws Exception { assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(false, headers.get(HEADER_IS_DIRECTORY_MOVING)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); @@ -655,6 +689,7 @@ public void testElementMove() throws Exception { assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); + assertEquals(false, headers.get(HEADER_IS_DIRECTORY_MOVING)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); } From 22a52fe5a270fdd41a7356632c63e21be6ec08ae Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Tue, 15 Oct 2024 19:35:23 +0200 Subject: [PATCH 16/17] fix sonar issues Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryTest.java | 54 ++++++------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index d02dbc5f..c03f6dcf 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -587,66 +587,46 @@ public void testMoveDirectory() throws Exception { insertAndCheckSubElement(directory21UUID, elementAttributes1); insertAndCheckSubElement(directory21UUID, elementAttributes2); - mockMvc.perform(put("/v1/elements?targetDirectoryUuid=" + rootDir10Uuid) - .header("userId", "Doe") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(List.of(directory21UUID)))) - .andExpect(status().isOk()); - - assertNbElementsInRepositories(5); + // test move directory + moveDirectoryAndCheck(directory21UUID, rootDir20Uuid, rootDir10Uuid, false); - Message message = output.receive(TIMEOUT, directoryUpdateDestination); - assertEquals("", new String(message.getPayload())); - MessageHeaders headers = message.getHeaders(); - assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); - assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); - assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); - assertEquals(true, headers.get(HEADER_IS_DIRECTORY_MOVING)); - assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); - assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); + // test move root directory + moveDirectoryAndCheck(rootDir20Uuid, null, rootDir10Uuid, true); - message = output.receive(TIMEOUT, directoryUpdateDestination); - assertEquals("", new String(message.getPayload())); - headers = message.getHeaders(); - assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); - assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); - assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); - assertEquals(true, headers.get(HEADER_IS_DIRECTORY_MOVING)); - assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); - assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); + assertNbElementsInRepositories(5); + } - // test move root directory - mockMvc.perform(put("/v1/elements?targetDirectoryUuid=" + rootDir10Uuid) + private void moveDirectoryAndCheck(UUID directoryUuid, + UUID parentDirectoryUuid, + UUID targetDirectoryUuid, + boolean isMovingDirectoryRoot) throws Exception { + mockMvc.perform(put("/v1/elements?targetDirectoryUuid=" + targetDirectoryUuid) .header("userId", "Doe") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(List.of(rootDir20Uuid)))) + .content(objectMapper.writeValueAsString(List.of(directoryUuid)))) .andExpect(status().isOk()); - message = output.receive(TIMEOUT, directoryUpdateDestination); + Message message = output.receive(TIMEOUT, directoryUpdateDestination); assertEquals("", new String(message.getPayload())); - headers = message.getHeaders(); + MessageHeaders headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir20Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(isMovingDirectoryRoot ? directoryUuid : parentDirectoryUuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_DIRECTORY_MOVING)); - assertEquals(NotificationType.DELETE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); + assertEquals(isMovingDirectoryRoot ? NotificationType.DELETE_DIRECTORY : NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); message = output.receive(TIMEOUT, directoryUpdateDestination); assertEquals("", new String(message.getPayload())); headers = message.getHeaders(); assertEquals("Doe", headers.get(HEADER_USER_ID)); - assertEquals(rootDir10Uuid, headers.get(HEADER_DIRECTORY_UUID)); + assertEquals(targetDirectoryUuid, headers.get(HEADER_DIRECTORY_UUID)); assertEquals(true, headers.get(HEADER_IS_ROOT_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_PUBLIC_DIRECTORY)); assertEquals(true, headers.get(HEADER_IS_DIRECTORY_MOVING)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); - - assertNbElementsInRepositories(5); } @Test From 6966421192d707539ec6326888c3df6bf4b0a49f Mon Sep 17 00:00:00 2001 From: Seddik Yengui Date: Thu, 17 Oct 2024 14:39:36 +0200 Subject: [PATCH 17/17] fix & add unit tests Signed-off-by: Seddik Yengui --- .../directory/server/DirectoryService.java | 2 +- .../directory/server/DirectoryTest.java | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index 21a44bda..95a2ac6e 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -332,7 +332,7 @@ public void moveElementsDirectory(List elementsUuids, UUID newDirectoryUui } private void moveElementDirectory(DirectoryElementEntity element, UUID newDirectoryUuid, String userId) { - if (element.getParentId() == newDirectoryUuid) { // Same directory ? + if (Objects.equals(element.getParentId(), newDirectoryUuid)) { // Same directory ? return; } diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index c03f6dcf..24385b43 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -672,6 +672,14 @@ public void testElementMove() throws Exception { assertEquals(false, headers.get(HEADER_IS_DIRECTORY_MOVING)); assertEquals(NotificationType.UPDATE_DIRECTORY, headers.get(HEADER_NOTIFICATION_TYPE)); assertEquals(UPDATE_TYPE_DIRECTORIES, headers.get(HEADER_UPDATE_TYPE)); + + // Test move element to its parent => keep the same parent + mockMvc.perform(put("/v1/elements?targetDirectoryUuid=" + rootDir10Uuid) + .header("userId", "Doe") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(List.of(elementUUID))) + ) + .andExpect(status().isOk()); // Response status is 200 but nothing changed and no notification should be sent } @Test @@ -686,7 +694,7 @@ public void testDirectoryMoveError() throws Exception { ElementAttributes elementAttributes2 = toElementAttributes(elementUuid2, "dir2", DIRECTORY, USER_ID); insertAndCheckSubElement(elementUuid1, elementAttributes2); - // test move element to be root directory targetDirectoryUuid = null + // test move element to be root directory: targetDirectoryUuid = null mockMvc.perform(put("/v1/elements") .header("userId", USER_ID) .contentType(MediaType.APPLICATION_JSON) @@ -701,6 +709,15 @@ public void testDirectoryMoveError() throws Exception { .content(objectMapper.writeValueAsString(List.of(elementUuid1))) ) .andExpect(status().isForbidden()); + + // test move element to itself + mockMvc.perform(put("/v1/elements?targetDirectoryUuid=" + elementUuid1) + .header("userId", USER_ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(List.of(elementUuid1))) + ) + .andExpect(status().isForbidden()); + assertNbElementsInRepositories(3); }