diff --git a/src/main/java/org/gridsuite/study/server/controller/StudyController.java b/src/main/java/org/gridsuite/study/server/controller/StudyController.java index ddc68e4053..5a33508038 100644 --- a/src/main/java/org/gridsuite/study/server/controller/StudyController.java +++ b/src/main/java/org/gridsuite/study/server/controller/StudyController.java @@ -315,7 +315,18 @@ public ResponseEntity unshareModificationReference( studyService.assertIsStudyAndNodeExist(studyUuid, nodeUuid); studyService.assertIsNodeNotReadOnly(nodeUuid); networkModificationActivityRunnerService.runWith(studyUuid, nodeUuid, userId, - () -> networkModificationService.unshareModificationReference(studyUuid, nodeUuid, modificationUuid, userId)); + () -> networkModificationService.unshareModificationReferences(studyUuid, Map.of(nodeUuid, List.of(modificationUuid)), userId)); + return ResponseEntity.ok().build(); + } + + @PutMapping(value = "/studies/{studyUuid}/unshare") + @Operation(summary = "Unshare all the reference modifications and copy the referenced composites in their place") + @ApiResponse(responseCode = "200", description = "All the reference modifications from the study have been replaced by copies of their referenced composites") + public ResponseEntity unshareAllModificationReferences( + @PathVariable("studyUuid") UUID studyUuid, + @RequestHeader(HEADER_USER_ID) String userId) { + studyService.assertIsStudyExist(studyUuid); + networkModificationService.unshareAllReferencesInStudy(studyUuid, userId); return ResponseEntity.ok().build(); } diff --git a/src/main/java/org/gridsuite/study/server/error/StudyBusinessErrorCode.java b/src/main/java/org/gridsuite/study/server/error/StudyBusinessErrorCode.java index 27b61a4ce7..11510cbc07 100644 --- a/src/main/java/org/gridsuite/study/server/error/StudyBusinessErrorCode.java +++ b/src/main/java/org/gridsuite/study/server/error/StudyBusinessErrorCode.java @@ -13,6 +13,7 @@ */ public enum StudyBusinessErrorCode implements BusinessErrorCode { NOT_FOUND("study.notFound"), + NODE_NOT_FOUND("study.nodeNotFound"), COMPUTATION_RUNNING("study.computationRunning"), LOADFLOW_ERROR("study.loadflowError"), NOT_ALLOWED("study.notAllowed"), diff --git a/src/main/java/org/gridsuite/study/server/error/StudyExceptionHandler.java b/src/main/java/org/gridsuite/study/server/error/StudyExceptionHandler.java index 9f636478a5..a729bb8e5b 100644 --- a/src/main/java/org/gridsuite/study/server/error/StudyExceptionHandler.java +++ b/src/main/java/org/gridsuite/study/server/error/StudyExceptionHandler.java @@ -33,6 +33,7 @@ protected StudyExceptionHandler(ServerNameProvider serverNameProvider) { protected HttpStatus mapStatus(StudyBusinessErrorCode studyBusinessErrorCode) { return switch (studyBusinessErrorCode) { case NOT_FOUND, + NODE_NOT_FOUND, NO_VOLTAGE_INIT_RESULTS_FOR_NODE -> HttpStatus.NOT_FOUND; case COMPUTATION_RUNNING, diff --git a/src/main/java/org/gridsuite/study/server/nodeactivity/NodeActivityType.java b/src/main/java/org/gridsuite/study/server/nodeactivity/NodeActivityType.java index 9b71186861..870e821bc2 100644 --- a/src/main/java/org/gridsuite/study/server/nodeactivity/NodeActivityType.java +++ b/src/main/java/org/gridsuite/study/server/nodeactivity/NodeActivityType.java @@ -28,6 +28,7 @@ public enum NodeActivityType { REIMPORT_CASE(UPDATING, true, false, false), EDIT_TREE(UPDATING, true, true, true), EDIT_MODIFICATIONS(UPDATING, true, true, true), + UNSHARE_MODIFICATIONS(UPDATING, false, true, true), DELETE_NODES(DELETING, true, true, true), EDIT_EVENTS(UPDATING, false, true, true); diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java index 54a8beac4e..1e4c8c3ac7 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java @@ -711,7 +711,7 @@ public RootNodeInfoEntity getRootNodeInfoEntity(UUID nodeId) { } public NetworkModificationNodeInfoEntity getNetworkModificationNodeInfoEntity(UUID nodeId) { - return networkModificationNodeInfoRepository.findById(nodeId).orElseThrow(() -> new StudyException(NOT_FOUND, "Node not found")); + return networkModificationNodeInfoRepository.findById(nodeId).orElseThrow(() -> new StudyException(NODE_NOT_FOUND, "Node not found")); } private AbstractNodeInfoEntity getNodeInfoEntity(UUID nodeUuid) { @@ -1008,6 +1008,10 @@ public List getAllNodes(UUID studyUuid) { return nodesRepository.findAllByStudyId(studyUuid); } + public List getAllNotStashedNetworkModificationNodes(UUID studyUuid) { + return nodesRepository.findAllByStudyIdAndTypeAndStashed(studyUuid, NodeType.NETWORK_MODIFICATION, false); + } + /** * Gets or generates a modification report UUID for a node. *

diff --git a/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java b/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java index 2842a77050..5824a1f349 100644 --- a/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java +++ b/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationRestService.java @@ -153,12 +153,9 @@ public void updateNetworkModification(UUID networkModificationUuid, String modif restTemplate.exchange(getNetworkModificationServerURI(false) + path, HttpMethod.PUT, new HttpEntity<>(modificationInfos, headers), Void.class); } - public void unshareModificationReference(UUID modificationReferenceUuid, String userId) { - String path = UriComponentsBuilder.fromPath(NETWORK_MODIFICATIONS_PATH + "/{uuid}/unshare").buildAndExpand(modificationReferenceUuid).toUriString(); - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - headers.set(HEADER_USER_ID, userId); - restTemplate.exchange(getNetworkModificationServerURI(false) + path, HttpMethod.PUT, new HttpEntity<>(headers), Void.class); + public void unshareModificationReferences(List modificationReferenceUuids, String userId) { + String path = UriComponentsBuilder.fromPath(NETWORK_MODIFICATIONS_PATH + "/unshare").build().toUriString(); + restTemplate.exchange(getNetworkModificationServerURI(false) + path, HttpMethod.PUT, userIdEntity(userId, modificationReferenceUuids), Void.class); } public void updateNetworkModificationsMetadata(List networkModificationUuids, String metadata, String userId) { diff --git a/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationService.java b/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationService.java index 45cd8faf25..234c9d1167 100644 --- a/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationService.java @@ -14,6 +14,8 @@ import org.gridsuite.study.server.dto.networkexport.PermissionType; import org.gridsuite.study.server.error.StudyException; import org.gridsuite.study.server.networkmodificationtree.dto.NodeBuildStatus; +import org.gridsuite.study.server.networkmodificationtree.entities.NodeEntity; +import org.gridsuite.study.server.nodeactivity.NodeActivityRunnerService; import org.gridsuite.study.server.notification.NotificationService; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity; import org.gridsuite.study.server.service.DirectoryService; @@ -30,6 +32,7 @@ import static org.gridsuite.study.server.error.StudyBusinessErrorCode.NOT_ALLOWED; import static org.gridsuite.study.server.error.StudyBusinessErrorCode.NOT_FOUND; +import static org.gridsuite.study.server.nodeactivity.NodeActivityType.UNSHARE_MODIFICATIONS; /** * @author Slimane amar @@ -42,19 +45,22 @@ public class NetworkModificationService { private final NetworkModificationRestService networkModificationRestService; private final NotificationService notificationService; private final DirectoryService directoryService; + private final NodeActivityRunnerService nodeActivityRunnerService; public NetworkModificationService(NetworkModificationTreeService networkModificationTreeService, RootNetworkService rootNetworkService, RootNetworkNodeInfoService rootNetworkNodeInfoService, NetworkModificationRestService networkModificationRestService, NotificationService notificationService, - DirectoryService directoryService) { + DirectoryService directoryService, + NodeActivityRunnerService nodeActivityRunnerService) { this.networkModificationTreeService = networkModificationTreeService; this.rootNetworkService = rootNetworkService; this.rootNetworkNodeInfoService = rootNetworkNodeInfoService; this.networkModificationRestService = networkModificationRestService; this.notificationService = notificationService; this.directoryService = directoryService; + this.nodeActivityRunnerService = nodeActivityRunnerService; } public void updateNetworkModificationNameAndDescription(UUID studyUuid, UUID nodeUuid, UUID networkModificationUuid, String metadata, String userId) { @@ -342,13 +348,35 @@ public NodeBuildStatus getNodeBuildStatus(UUID nodeUuid, UUID rootNetworkUuid) { return networkModificationTreeService.getNodeBuildStatus(nodeUuid, rootNetworkUuid); } - public void unshareModificationReference( - @NonNull final UUID studyUuid, - @NonNull final UUID nodeUuid, - @NonNull final UUID modificationUuid, - String userId) { - networkModificationRestService.unshareModificationReference(modificationUuid, userId); - notificationService.emitModificationsUpdated(studyUuid, nodeUuid, Optional.empty(), List.of(modificationUuid)); + public void unshareAllReferencesInStudy( + @NonNull final UUID studyUuid, + String userId) { + // get the modification references of the whole study grouped by their node + Map> referencesAffectedByNode = new HashMap<>(); + networkModificationTreeService.getAllNotStashedNetworkModificationNodes(studyUuid).stream() + .map(NodeEntity::getIdNode) + .forEach(nodeUuid -> { + UUID groupUuid = networkModificationTreeService.getModificationGroupUuid(nodeUuid); + List modificationReferences = networkModificationRestService.getModificationReferences(groupUuid) + .stream().map(ModificationReference::modificationUuid).toList(); + if (!modificationReferences.isEmpty()) { + referencesAffectedByNode.put(nodeUuid, modificationReferences); + } + }); + if (referencesAffectedByNode.isEmpty()) { + return; + } + + nodeActivityRunnerService.runWith(UNSHARE_MODIFICATIONS, studyUuid, new ArrayList<>(referencesAffectedByNode.keySet()), + () -> unshareModificationReferences(studyUuid, referencesAffectedByNode, userId)); + } + + public void unshareModificationReferences(@NonNull UUID studyUuid, Map> referencesAffectedByNode, String userId) { + // a single remote call for all the references, then every affected node is notified + List allModificationReferenceUuids = referencesAffectedByNode.values().stream().flatMap(List::stream).toList(); + networkModificationRestService.unshareModificationReferences(allModificationReferenceUuids, userId); + referencesAffectedByNode.forEach((nodeUuid, modificationReferenceUuids) -> + notificationService.emitModificationsUpdated(studyUuid, nodeUuid, modificationReferenceUuids)); } @Transactional(readOnly = true) diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java index 9a9e38aef3..fc8bf49833 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTreeTest.java @@ -90,6 +90,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.gridsuite.study.server.StudyConstants.HEADER_USER_ID; +import static org.gridsuite.study.server.error.StudyBusinessErrorCode.NODE_NOT_FOUND; import static org.gridsuite.study.server.error.StudyBusinessErrorCode.NOT_FOUND; import static org.gridsuite.study.server.notification.NotificationService.*; import static org.gridsuite.study.server.service.NetworkModificationTreeService.ROOT_NODE_NAME; @@ -816,7 +817,7 @@ void testNodeModificationInfos() throws Exception { RootNode root = getRootNode(rootStudyId, firstRootNetworkUuid); UUID rootId = root.getId(); - RootNodeInfoEntity rootInfos = rootNodeInfoRepository.findById(rootId).orElseThrow(() -> new StudyException(NOT_FOUND, "Node not found")); + RootNodeInfoEntity rootInfos = rootNodeInfoRepository.findById(rootId).orElseThrow(() -> new StudyException(NODE_NOT_FOUND, "Node not found")); assertEquals(rootId, rootInfos.getId()); List children = root.getChildren(); diff --git a/src/test/java/org/gridsuite/study/server/StudyServiceTest.java b/src/test/java/org/gridsuite/study/server/StudyServiceTest.java index 3b54bc6a48..dfacc74e43 100644 --- a/src/test/java/org/gridsuite/study/server/StudyServiceTest.java +++ b/src/test/java/org/gridsuite/study/server/StudyServiceTest.java @@ -7,6 +7,7 @@ package org.gridsuite.study.server; import org.gridsuite.study.server.dto.ComputationType; +import org.gridsuite.study.server.dto.ModificationReference; import org.gridsuite.study.server.dto.QuotaState; import org.gridsuite.study.server.dto.QuotaType; import org.gridsuite.study.server.error.StudyException; @@ -14,6 +15,7 @@ import org.gridsuite.study.server.networkmodificationtree.dto.NodeBuildStatus; import org.gridsuite.study.server.networkmodificationtree.entities.NodeEntity; import org.gridsuite.study.server.networkmodificationtree.entities.NodeType; +import org.gridsuite.study.server.nodeactivity.NodeActivityRunnerService; import org.gridsuite.study.server.notification.NotificationService; import org.gridsuite.study.server.repository.networkmodificationtree.NodeRepository; import org.gridsuite.study.server.service.NetworkModificationTreeService; @@ -33,10 +35,10 @@ import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.UUID; import static org.gridsuite.study.server.error.StudyBusinessErrorCode.MAX_OPERATION_TYPE_EXCEEDED; +import static org.gridsuite.study.server.nodeactivity.NodeActivityType.UNSHARE_MODIFICATIONS; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.*; @@ -61,6 +63,8 @@ class StudyServiceTest { private NotificationService notificationService; @MockitoBean private RootNetworkService rootNetworkService; + @MockitoBean + private NodeActivityRunnerService nodeActivityRunnerService; @AfterEach void resetOperationQuotasFlag() { @@ -278,11 +282,67 @@ void testUnshareModificationReference() { UUID modificationUuid = UUID.randomUUID(); String userId = "userId"; - networkModificationService.unshareModificationReference(studyUuid, nodeUuid, modificationUuid, userId); + networkModificationService.unshareModificationReferences(studyUuid, Map.of(nodeUuid, List.of(modificationUuid)), userId); // the reference is replaced remotely by a copy of the shared composite, then the front is notified - verify(networkModificationRestService, times(1)).unshareModificationReference(modificationUuid, userId); - verify(notificationService, times(1)).emitModificationsUpdated(studyUuid, nodeUuid, Optional.empty(), List.of(modificationUuid)); + verify(networkModificationRestService, times(1)).unshareModificationReferences(List.of(modificationUuid), userId); + verify(notificationService, times(1)).emitModificationsUpdated(studyUuid, nodeUuid, List.of(modificationUuid)); + } + + @Test + void testUnshareAllReferencesInStudy() { + UUID studyUuid = UUID.randomUUID(); + String userId = "userId"; + + doReturn(List.of()).when(networkModificationTreeService).getAllNotStashedNetworkModificationNodes(studyUuid); + + networkModificationService.unshareAllReferencesInStudy(studyUuid, userId); + + verify(networkModificationTreeService, times(1)).getAllNotStashedNetworkModificationNodes(studyUuid); + verify(nodeActivityRunnerService, never()).runWith(any(), any(), any(), (Runnable) any()); + verify(networkModificationRestService, never()).unshareModificationReferences(any(), any()); + verify(notificationService, never()).emitModificationsUpdated(any(), any(), any()); + } + + @Test + void testUnshareAllReferencesInStudyWithReferences() { + UUID studyUuid = UUID.randomUUID(); + UUID nodeUuid = UUID.randomUUID(); + UUID modificationUuid = UUID.randomUUID(); + String userId = "userId"; + + UUID nodeWithoutReferenceUuid = UUID.randomUUID(); + doReturn(List.of( + new NodeEntity(nodeUuid, null, NodeType.NETWORK_MODIFICATION, null, false, null, List.of()), + new NodeEntity(nodeWithoutReferenceUuid, null, NodeType.NETWORK_MODIFICATION, null, false, null, List.of()) + )).when(networkModificationTreeService).getAllNotStashedNetworkModificationNodes(studyUuid); + + UUID groupUuid = UUID.randomUUID(); + doReturn(groupUuid).when(networkModificationTreeService).getModificationGroupUuid(nodeUuid); + UUID groupWithoutReferenceUuid = UUID.randomUUID(); + doReturn(groupWithoutReferenceUuid).when(networkModificationTreeService).getModificationGroupUuid(nodeWithoutReferenceUuid); + doReturn(List.of()).when(networkModificationRestService).getModificationReferences(groupWithoutReferenceUuid); + + ModificationReference modificationReference = new ModificationReference(modificationUuid, UUID.randomUUID(), null); + doReturn(List.of(modificationReference)).when(networkModificationRestService).getModificationReferences(groupUuid); + + // Mock nodeActivityRunnerService to bypass database checks + doAnswer(invocation -> { + Runnable runnable = invocation.getArgument(3); + runnable.run(); + return null; + }).when(nodeActivityRunnerService).runWith(any(), any(), any(), (Runnable) any()); + + networkModificationService.unshareAllReferencesInStudy(studyUuid, userId); + + verify(networkModificationTreeService, times(1)).getAllNotStashedNetworkModificationNodes(studyUuid); + verify(networkModificationTreeService, times(1)).getModificationGroupUuid(nodeUuid); + verify(networkModificationRestService, times(1)).getModificationReferences(groupUuid); + // only the node having references is held by the activity + verify(nodeActivityRunnerService, times(1)).runWith(eq(UNSHARE_MODIFICATIONS), eq(studyUuid), eq(List.of(nodeUuid)), (Runnable) any()); + verify(networkModificationRestService, times(1)).unshareModificationReferences(List.of(modificationUuid), userId); + verify(notificationService, times(1)).emitModificationsUpdated(studyUuid, nodeUuid, List.of(modificationUuid)); + verify(notificationService, never()).emitModificationsUpdated(eq(studyUuid), eq(nodeWithoutReferenceUuid), any()); } @Test @@ -293,12 +353,11 @@ void testUnshareModificationReferenceDoesNotNotifyWhenRemoteCallFails() { String userId = "userId"; doThrow(new RuntimeException("network modification server error")) - .when(networkModificationRestService).unshareModificationReference(modificationUuid, userId); + .when(networkModificationRestService).unshareModificationReferences(List.of(modificationUuid), userId); assertThrows(RuntimeException.class, - () -> networkModificationService.unshareModificationReference(studyUuid, nodeUuid, modificationUuid, userId)); + () -> networkModificationService.unshareModificationReferences(studyUuid, Map.of(nodeUuid, List.of(modificationUuid)), userId)); - verify(notificationService, never()).emitModificationsUpdated(any(), any(), any(), any()); + verify(notificationService, never()).emitModificationsUpdated(any(), any(), any()); } - } diff --git a/src/test/java/org/gridsuite/study/server/nodeactivity/NodeActivityRulesTest.java b/src/test/java/org/gridsuite/study/server/nodeactivity/NodeActivityRulesTest.java index 835f665c65..211826f05b 100644 --- a/src/test/java/org/gridsuite/study/server/nodeactivity/NodeActivityRulesTest.java +++ b/src/test/java/org/gridsuite/study/server/nodeactivity/NodeActivityRulesTest.java @@ -76,7 +76,7 @@ private static boolean hasConflict(NodeActivityEntity activity, List touchOnlyTheirNode = List.of(BUILD, UNBUILD, COMPUTE, EDIT_EVENTS); + List touchOnlyTheirNode = List.of(BUILD, UNBUILD, COMPUTE, EDIT_EVENTS, UNSHARE_MODIFICATIONS); List invalidateTheirChildren = List.of(UNBUILD_CHILDREN, UNBUILD_ALL, COMPUTE_AND_UNBUILD_CHILDREN, REIMPORT_CASE, EDIT_TREE, EDIT_MODIFICATIONS, DELETE_NODES); @@ -92,7 +92,7 @@ void affectsAllRootNetworksIsClassified() { List oneRootNetwork = List.of(BUILD, UNBUILD, UNBUILD_CHILDREN, COMPUTE, COMPUTE_AND_UNBUILD_CHILDREN, REIMPORT_CASE); List allRootNetworks = List.of(UNBUILD_ALL, EDIT_TREE, EDIT_MODIFICATIONS, - DELETE_NODES, EDIT_EVENTS); + DELETE_NODES, EDIT_EVENTS, UNSHARE_MODIFICATIONS); assertThat(oneRootNetwork).noneMatch(NodeActivityType::affectsAllRootNetworks); assertThat(allRootNetworks).allMatch(NodeActivityType::affectsAllRootNetworks); diff --git a/src/test/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationServiceTest.java b/src/test/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationServiceTest.java index b57c1fff08..74f6cbec75 100644 --- a/src/test/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationServiceTest.java +++ b/src/test/java/org/gridsuite/study/server/service/networkmodification/NetworkModificationServiceTest.java @@ -128,14 +128,14 @@ void testUpdateNetworkModificationsMetadata() { @Test void testUnshareModificationReference() { UUID modificationReferenceUuid = UUID.randomUUID(); - String expectedUrl = NETWORK_MODIFICATION_SERVER_URI + "/v1/network-modifications/" + modificationReferenceUuid + "/unshare"; + String expectedUrl = NETWORK_MODIFICATION_SERVER_URI + "/v1/network-modifications/unshare"; - networkModificationService.unshareModificationReference(modificationReferenceUuid, USER_ID); + networkModificationService.unshareModificationReferences(List.of(modificationReferenceUuid), USER_ID); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set(HEADER_USER_ID, USER_ID); - verify(restTemplate).exchange(expectedUrl, HttpMethod.PUT, new HttpEntity<>(headers), Void.class); + verify(restTemplate).exchange(expectedUrl, HttpMethod.PUT, new HttpEntity<>(List.of(modificationReferenceUuid), headers), Void.class); } @Test diff --git a/src/test/java/org/gridsuite/study/server/studycontroller/StudyControllerRebuildNodeTest.java b/src/test/java/org/gridsuite/study/server/studycontroller/StudyControllerRebuildNodeTest.java index 9183a4a179..7891909c63 100644 --- a/src/test/java/org/gridsuite/study/server/studycontroller/StudyControllerRebuildNodeTest.java +++ b/src/test/java/org/gridsuite/study/server/studycontroller/StudyControllerRebuildNodeTest.java @@ -170,8 +170,17 @@ void testUnshareModificationReference() { ResponseEntity response = studyController.unshareModificationReference(modificationUuid, studyUuid, nodeUuid, userId); Assertions.assertEquals(HttpStatus.OK, response.getStatusCode()); - verify(networkModificationService, times(1)).unshareModificationReference(studyUuid, nodeUuid, modificationUuid, userId); + verify(networkModificationService, times(1)).unshareModificationReferences(studyUuid, Map.of(nodeUuid, List.of(modificationUuid)), userId); verify(studyService, times(1)).assertIsStudyAndNodeExist(studyUuid, nodeUuid); verify(studyService, times(1)).assertIsNodeNotReadOnly(nodeUuid); } + + @Test + void testUnshareAllReferencesInStudy() { + ResponseEntity response = studyController.unshareAllModificationReferences(studyUuid, userId); + + Assertions.assertEquals(HttpStatus.OK, response.getStatusCode()); + verify(studyService, times(1)).assertIsStudyExist(studyUuid); + verify(networkModificationService, times(1)).unshareAllReferencesInStudy(studyUuid, userId); + } }