Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1636,6 +1636,7 @@ public ResponseEntity<Void> buildNode(@Parameter(description = "Study uuid") @Pa
@Parameter(description = "nodeUuid") @PathVariable("nodeUuid") UUID nodeUuid,
@RequestHeader(HEADER_USER_ID) String userId) {
studyService.assertNoBlockedNodeInTree(nodeUuid, rootNetworkUuid);
studyService.assertCanBuildNode(rootNetworkUuid, nodeUuid);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreeing together.
Do not protect every usage of studyService.buildNode.
This fix the main user means of creation the related issue

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

studyService.buildNode(studyUuid, nodeUuid, rootNetworkUuid, userId);
return ResponseEntity.ok().build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,21 @@ public interface NodeRepository extends JpaRepository<NodeEntity, UUID> {
"WHERE n.id_node IN (SELECT nh.id_node FROM NodeHierarchy nh) AND n.id_node != :nodeUuid")
List<NodeEntity> findAllChildren(UUID nodeUuid);

@NativeQuery("WITH RECURSIVE NodeHierarchy (id_node, parent_node) AS ( " +
" SELECT n0.id_node, n0.parent_node" +
" FROM NODE n0 " +
" WHERE n0.id_node = :nodeUuid " +

" UNION ALL " +

" SELECT n.id_node, n.parent_node " +
" FROM NODE n " +
" INNER JOIN NodeHierarchy nh ON n.id_node = nh.parent_node AND n.type != 'ROOT'" +
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does type is indexed ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's unnecessary because there's no join

") " +
"SELECT cast(nh.id_node AS VARCHAR) " +
"FROM NodeHierarchy nh where nh.id_node != :nodeUuid ")
List<UUID> findAllAncestorsUuids(UUID nodeUuid);

@NativeQuery("WITH RECURSIVE ancestors (id_node, parent_node) AS ( " +
" SELECT n.id_node, n.parent_node " +
" FROM NODE n " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,12 @@ public List<UUID> getNodeTreeUuids(UUID parentUuid) {
return nodesUuids;
}

public List<UUID> getNodeBranchUuids(UUID nodeUuid) {
List<UUID> nodesUuids = nodesRepository.findAllAncestorsUuids(nodeUuid);
nodesUuids.addAll(getNodeTreeUuids(nodeUuid));
return nodesUuids;
}

public List<UUID> getAllChildrenUuids(UUID parentUuid) {
return nodesRepository.findAllChildrenUuids(parentUuid);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,12 @@ public void assertCanUpdateNodeInStudy(UUID studyUuid, UUID nodeUuid) {
);
}

@Transactional(readOnly = true)
public void assertCanBuildNode(UUID rootNetworkUuid, UUID nodeUuid) {
List<UUID> nodesUuids = networkModificationTreeService.getNodeBranchUuids(nodeUuid);
rootNetworkNodeInfoService.assertNoBuildingNode(rootNetworkUuid, nodesUuids);
}

private void assertNoBuildNoComputationInTree(UUID rootNetworkUuid, List<UUID> nodesUuids) {
// TODO modify computations endpoints to test multiple uuids
nodesUuids.forEach(uuid -> rootNetworkNodeInfoService.assertComputationNotRunning(uuid, rootNetworkUuid));
Expand Down Expand Up @@ -1809,7 +1815,7 @@ private void buildNode(@NonNull UUID studyUuid, @NonNull UUID nodeUuid, @NonNull
if (networkModificationTreeService.getNodeBuildStatus(nodeUuid, rootNetworkUuid).isBuilt()) {
return;
}
assertCanBuildNode(studyUuid, rootNetworkUuid, userId);
assertNoMaxBuilds(studyUuid, rootNetworkUuid, userId);
BuildInfos buildInfos = networkModificationTreeService.getBuildInfos(nodeUuid, rootNetworkUuid);

// Store all reports (inherited + new) for this node
Expand Down Expand Up @@ -1859,7 +1865,7 @@ private long getAllowedBuildNodesUpToQuota(@NonNull UUID studyUuid, @NonNull UUI
}).orElse(Long.MAX_VALUE);
}

public void assertCanBuildNode(@NonNull UUID studyUuid, @NonNull UUID rootNetworkUuid, @NonNull String userId) {
public void assertNoMaxBuilds(@NonNull UUID studyUuid, @NonNull UUID rootNetworkUuid, @NonNull String userId) {
// check restrictions on node builds number
userAdminService.getUserMaxAllowedBuilds(userId).ifPresent(maxBuilds -> {
long nbBuiltNodes = networkModificationTreeService.countBuiltNodes(studyUuid, rootNetworkUuid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,100 @@ void testLocalBuildValue() throws Exception {
assertEquals(BuildStatus.BUILT_WITH_ERROR, networkModificationTreeService.getNodeBuildStatus(modificationNode2Uuid, rootNetworkUuid).getGlobalBuildStatus());
}

@Test
void testBuildAsserts() throws Exception {
String userId = USER_ID;
StudyEntity studyEntity = insertDummyStudy(UUID.fromString(NETWORK_UUID_STRING), CASE_UUID, "UCTE");
UUID rootNetworkUuid = studyEntity.getFirstRootNetwork().getId();
UUID studyNameUserIdUuid = studyEntity.getId();
UUID rootNodeUuid = getRootNode(studyNameUserIdUuid).getId();

// Branch 1
NetworkModificationNode modificationNode1 = createNetworkModificationNode(studyNameUserIdUuid,
rootNodeUuid, UUID.randomUUID(), "variant_1", "node 1", userId);
NetworkModificationNode modificationNode2 = createNetworkModificationNode(studyNameUserIdUuid,
modificationNode1.getId(), UUID.randomUUID(), "variant_2", "node 2", userId);

// Branch 2
NetworkModificationNode modificationNode3 = createNetworkModificationNode(studyNameUserIdUuid,
rootNodeUuid, UUID.randomUUID(), "variant_3", "node 3", userId);
NetworkModificationNode modificationNode4 = createNetworkModificationNode(studyNameUserIdUuid,
modificationNode3.getId(), UUID.randomUUID(), "variant_4", "node 4", userId);
NetworkModificationNode modificationNode5 = createNetworkModificationNode(studyNameUserIdUuid,
modificationNode4.getId(), UUID.randomUUID(), "variant_5", "node 5", userId);

/*
root
| \
modificationNode1 modificationNode3
| \
modificationNode2 modificationNode4
\
modificationNode5
*/

// just test asserts
doNothing().when(studyService).buildNode(any(), any(), any(), any());

// Build all nodes is ok
testBuildAsserts(studyNameUserIdUuid, rootNetworkUuid,
Set.of(modificationNode1.getId(), modificationNode2.getId(), modificationNode3.getId(), modificationNode4.getId(), modificationNode5.getId()),
Set.of());

// Mark the node 1 status as building
RootNetworkNodeInfoEntity rootNetworkNodeInfo1Entity = rootNetworkNodeInfoRepository.findByNodeInfoIdAndRootNetworkId(modificationNode1.getId(), studyTestUtils.getOneRootNetworkUuid(studyNameUserIdUuid)).orElseThrow(() -> new StudyException(NOT_FOUND, "Root network not found"));
rootNetworkNodeInfo1Entity.setNodeBuildStatus(NodeBuildStatusEmbeddable.from(BuildStatus.BUILDING));
rootNetworkNodeInfoRepository.save(rootNetworkNodeInfo1Entity);

// Build all nodes branch1 is not ok
// Build all nodes branch2 is ok
testBuildAsserts(studyNameUserIdUuid, rootNetworkUuid,
Set.of(modificationNode3.getId(), modificationNode4.getId(), modificationNode5.getId()),
Set.of(modificationNode1.getId(), modificationNode2.getId())
);

// Mark the node 2 status as building
RootNetworkNodeInfoEntity rootNetworkNodeInfo2Entity = rootNetworkNodeInfoRepository.findByNodeInfoIdAndRootNetworkId(modificationNode2.getId(), studyTestUtils.getOneRootNetworkUuid(studyNameUserIdUuid)).orElseThrow(() -> new StudyException(NOT_FOUND, "Root network not found"));
rootNetworkNodeInfo1Entity.setNodeBuildStatus(NodeBuildStatusEmbeddable.from(BuildStatus.NOT_BUILT));
rootNetworkNodeInfo2Entity.setNodeBuildStatus(NodeBuildStatusEmbeddable.from(BuildStatus.BUILDING));
rootNetworkNodeInfoRepository.saveAll(List.of(rootNetworkNodeInfo1Entity, rootNetworkNodeInfo2Entity));

// Build all nodes branch1 is not ok
// Build all nodes branch2 is ok
testBuildAsserts(studyNameUserIdUuid, rootNetworkUuid,
Set.of(modificationNode3.getId(), modificationNode4.getId(), modificationNode5.getId()),
Set.of(modificationNode1.getId(), modificationNode2.getId())
);

// Mark the node 4 status as building
RootNetworkNodeInfoEntity rootNetworkNodeInfo4Entity = rootNetworkNodeInfoRepository.findByNodeInfoIdAndRootNetworkId(modificationNode4.getId(), studyTestUtils.getOneRootNetworkUuid(studyNameUserIdUuid)).orElseThrow(() -> new StudyException(NOT_FOUND, "Root network not found"));
rootNetworkNodeInfo2Entity.setNodeBuildStatus(NodeBuildStatusEmbeddable.from(BuildStatus.NOT_BUILT));
rootNetworkNodeInfo4Entity.setNodeBuildStatus(NodeBuildStatusEmbeddable.from(BuildStatus.BUILDING));
rootNetworkNodeInfoRepository.saveAll(List.of(rootNetworkNodeInfo2Entity, rootNetworkNodeInfo4Entity));

// Build all nodes branch1 is ok
// Build all nodes branch2 is not ok
testBuildAsserts(studyNameUserIdUuid, rootNetworkUuid,
Set.of(modificationNode1.getId(), modificationNode2.getId()),
Set.of(modificationNode3.getId(), modificationNode4.getId(), modificationNode5.getId())
);

verify(rootNetworkNodeInfoService, times(20)).assertNoBuildingNode(any(), any());
}

private void testBuildAsserts(UUID studyUuid, UUID rootNetworkUuid, Set<UUID> nodesUuidsOk, Set<UUID> nodesUuidsNotOk) throws Exception {
for (UUID nodeUuid : nodesUuidsOk) {
mockMvc.perform(post("/v1/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/build", studyUuid, rootNetworkUuid, nodeUuid)
.header(USER_ID_HEADER, USER_ID))
.andExpect(status().isOk());
}
for (UUID nodeUuid : nodesUuidsNotOk) {
mockMvc.perform(post("/v1/studies/{studyUuid}/root-networks/{rootNetworkUuid}/nodes/{nodeUuid}/build", studyUuid, rootNetworkUuid, nodeUuid)
.header(USER_ID_HEADER, USER_ID))
.andExpect(status().isForbidden());
}
}

@Test
void testNetworkModificationSwitch() throws Exception {
reportServerStubs.stubDeleteReport();
Expand Down
Loading