diff --git a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/api/ListGroupOnBehalfOfApi.java b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/api/ListGroupOnBehalfOfApi.java index 54dc500f593035f75859650e33acee5480364080..84c4bbd90f3721163efca9d6d501c8a47e9bc612 100644 --- a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/api/ListGroupOnBehalfOfApi.java +++ b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/api/ListGroupOnBehalfOfApi.java @@ -28,7 +28,7 @@ public class ListGroupOnBehalfOfApi { private final PartitionHeaderValidationService partitionHeaderValidationService; @GetMapping("/members/{member_email}/groups") - @PreAuthorize("@authorizationFilter.hasAnyPermission('" + AppProperties.ADMIN + "')") + @PreAuthorize("@authorizationFilter.hasAnyPermission('" + AppProperties.OPS + "', '" + AppProperties.ADMIN + "')") public ResponseEntity listGroupsOnBehalfOf(@PathVariable("member_email") String memberId, @RequestParam(name="type", required = false) String type, @RequestParam(name="appid", required = false) String appId) { diff --git a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/AddMemberService.java b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/AddMemberService.java index 7d8da30f0f3435890ae1c21ca9583bbd6d47d8d0..ff279597413a7cd6fdb1580a24c1f40a3dc3eb3d 100644 --- a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/AddMemberService.java +++ b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/AddMemberService.java @@ -27,6 +27,7 @@ public class AddMemberService { private final AppProperties config; private final JaxRsDpsLog log; private final PermissionService permissionService; + private final GroupCacheService groupCacheService; /** * Add Member only allows to create a member node for a new user (first time add a user to a data partition), but not for a group. @@ -63,7 +64,8 @@ public class AddMemberService { } AddMemberRepoDto addMemberRepoDto = AddMemberRepoDto.builder().memberNode(memberNode).role(addMemberDto.getRole()). partitionId(addMemberServiceDto.getPartitionId()).existingParents(allExistingParents).build(); - addMemberRepo.addMember(existingGroupEntityNode, addMemberRepoDto); + Set impactedUsers = addMemberRepo.addMember(existingGroupEntityNode, addMemberRepoDto); + groupCacheService.refreshListGroupCache(impactedUsers, addMemberServiceDto.getPartitionId()); } private EntityNode createNewMemberNode(String memberPrimaryId, String memberDesId, String partitionId) { diff --git a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/CreateGroupService.java b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/CreateGroupService.java index c40cdccfba209df2bbaafa69957bdd8cc005c0f0..bc956fe59c682a21b3409430fbb4d618ce513c1a 100644 --- a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/CreateGroupService.java +++ b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/CreateGroupService.java @@ -24,13 +24,14 @@ public class CreateGroupService { private final CreateGroupRepo createGroupRepo; private final RetrieveGroupRepo retrieveGroupRepo; + private final GroupCacheService groupCacheService; private final JaxRsDpsLog log; private final DefaultGroupsService defaultGroupsService; public EntityNode run(EntityNode groupNode, CreateGroupServiceDto createGroupServiceDto) { log.info(String.format("requested by %s", createGroupServiceDto.getRequesterId())); EntityNode requesterNode = EntityNode.createMemberNodeForRequester(createGroupServiceDto.getRequesterId(), createGroupServiceDto.getPartitionId()); - Set allExistingParents = retrieveGroupRepo.loadAllParents(requesterNode).getParentReferences(); + Set allExistingParents = groupCacheService.getFromPartitionCache(requesterNode.getNodeId(), createGroupServiceDto.getPartitionId()); if (allExistingParents.size() >= EntityNode.MAX_PARENTS) { log.error(String.format("Identity %s already belong to %d groups", createGroupServiceDto.getRequesterId(), allExistingParents.size())); throw new AppException(HttpStatus.PRECONDITION_FAILED.value(), HttpStatus.PRECONDITION_FAILED.getReasonPhrase(), String.format("%s's group quota hit. Identity can't belong to more than %d groups", createGroupServiceDto.getRequesterId(), EntityNode.MAX_PARENTS)); @@ -63,6 +64,7 @@ public class CreateGroupService { } private void createGroup(EntityNode groupNode, CreateGroupRepoDto createGroupRepoDto) { - createGroupRepo.createGroup(groupNode, createGroupRepoDto); + Set impactedUsers = createGroupRepo.createGroup(groupNode, createGroupRepoDto); + groupCacheService.refreshListGroupCache(impactedUsers, createGroupRepoDto.getPartitionId()); } } diff --git a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/DeleteGroupService.java b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/DeleteGroupService.java index 743f6f871e8dfcf463730482928cb7e317c616b9..4ef17e5b123739d12baff4c5448dd0e220ce9aa6 100644 --- a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/DeleteGroupService.java +++ b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/DeleteGroupService.java @@ -12,6 +12,7 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import java.util.Optional; +import java.util.Set; @Service @RequiredArgsConstructor @@ -19,6 +20,7 @@ public class DeleteGroupService { private final DeleteGroupRepo deleteGroupRepo; private final RetrieveGroupRepo retrieveGroupRepo; + private final GroupCacheService groupCacheService; private final JaxRsDpsLog log; private final DefaultGroupsService defaultGroupsService; private final RequestInfo requestInfo; @@ -39,7 +41,7 @@ public class DeleteGroupService { if (defaultGroupsService.isDefaultGroupName(groupNode.getName())) { throw new AppException(HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.getReasonPhrase(), "Invalid group, bootstrap groups are not allowed to be deleted"); } - deleteGroupRepo.deleteGroup(existingGroupEntityNode.get()); - + Set impactedUsers = deleteGroupRepo.deleteGroup(existingGroupEntityNode.get()); + groupCacheService.refreshListGroupCache(impactedUsers, deleteGroupServiceDto.getPartitionId()); } } diff --git a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/DeleteMemberService.java b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/DeleteMemberService.java index 6e5878ef6a7bc09b8e314263282d4534ce1cdca3..9cba8ca135f17a555ad988a55e4a73a64b69c46c 100644 --- a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/DeleteMemberService.java +++ b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/DeleteMemberService.java @@ -18,12 +18,14 @@ import java.util.stream.Collectors; @RequiredArgsConstructor public class DeleteMemberService { private final JaxRsDpsLog log; - private final RetrieveGroupRepo retrieveGroup; + private final RetrieveGroupRepo retrieveGroupRepo; + private final GroupCacheService groupCacheService; private final RemoveMemberService removeMemberService; public void deleteMember(DeleteMemberDto deleteMemberDto) { log.info(String.format("Remove member %s from all groups", deleteMemberDto.getMemberEmail())); createRemoveMemberServiceDtos(deleteMemberDto).forEach(this::removeMemberFromGroup); + groupCacheService.flushListGroupCacheForUser(deleteMemberDto.getMemberEmail(), deleteMemberDto.getPartitionId()); } private List createRemoveMemberServiceDtos(DeleteMemberDto deleteMemberDto) { @@ -42,7 +44,7 @@ public class DeleteMemberService { } private Set loadDirectParentsEmails(DeleteMemberDto deleteMemberDto) { - List directParents = retrieveGroup.loadDirectParents( + List directParents = retrieveGroupRepo.loadDirectParents( deleteMemberDto.getPartitionId(), deleteMemberDto.getMemberEmail()); return directParents.stream() .map(ParentReference::getId) diff --git a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/GroupCacheService.java b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/GroupCacheService.java index fa3bd0467c67204b185ee883c121a0676067727e..b970750482e0e1ab5f850c09c6952d6e6d9da8a8 100644 --- a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/GroupCacheService.java +++ b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/GroupCacheService.java @@ -7,4 +7,8 @@ import java.util.Set; public interface GroupCacheService { Set getFromPartitionCache(String requesterId, String partitionId); + + void refreshListGroupCache(final Set userIds, String partitionId); + + void flushListGroupCacheForUser(String userId, String partitionId); } diff --git a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/RemoveMemberService.java b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/RemoveMemberService.java index 895841f392d7a53010be219df03cbe2282548040..a09dd6c0301a5d1d6737f118224dc1f9574cc60b 100644 --- a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/RemoveMemberService.java +++ b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/RemoveMemberService.java @@ -20,6 +20,7 @@ import java.util.Set; public class RemoveMemberService { private final RemoveMemberRepo removeMemberRepo; private final RetrieveGroupRepo retrieveGroupRepo; + private final GroupCacheService groupCacheService; private final JaxRsDpsLog log; private final ServiceAccountsConfigurationService serviceAccountsConfigurationService; private final BootstrapGroupsConfigurationService bootstrapGroupsConfigurationService; @@ -62,7 +63,9 @@ public class RemoveMemberService { memberNode.getName(), existingGroupEntityNode.getName())); } - return removeMemberRepo.removeMember(existingGroupEntityNode, memberNode, removeMemberServiceDto); + Set impactedUsers = removeMemberRepo.removeMember(existingGroupEntityNode, memberNode, removeMemberServiceDto); + groupCacheService.refreshListGroupCache(impactedUsers, removeMemberServiceDto.getPartitionId()); + return impactedUsers; } private EntityNode getEntityNode(String id, String partitionId) { diff --git a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/UpdateGroupService.java b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/UpdateGroupService.java index 2aa79352a85fff27d922722b0ceba10a3630ffe5..4365e4e812faa472983cb24405cfcf4f14b41e99 100644 --- a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/UpdateGroupService.java +++ b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/service/UpdateGroupService.java @@ -1,5 +1,6 @@ package org.opengroup.osdu.entitlements.v2.service; +import lombok.RequiredArgsConstructor; import org.opengroup.osdu.core.common.model.http.AppException; import org.opengroup.osdu.entitlements.v2.model.EntityNode; import org.opengroup.osdu.entitlements.v2.model.updategroup.UpdateGroupResponseDto; @@ -8,27 +9,24 @@ import org.opengroup.osdu.entitlements.v2.spi.renamegroup.RenameGroupRepo; import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.opengroup.osdu.entitlements.v2.spi.updateappids.UpdateAppIdsRepo; import org.opengroup.osdu.entitlements.v2.util.GroupCreationUtil; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Set; @Service +@RequiredArgsConstructor public class UpdateGroupService { - @Autowired - private RetrieveGroupRepo retrieveGroupRepo; - @Autowired - private RenameGroupRepo renameGroupRepo; - @Autowired - private UpdateAppIdsRepo updateAppIdsRepo; - @Autowired - private DefaultGroupsService defaultGroupsService; - @Autowired - private PermissionService permissionService; + private final RetrieveGroupRepo retrieveGroupRepo; + private final GroupCacheService groupCacheService; + private final RenameGroupRepo renameGroupRepo; + private final UpdateAppIdsRepo updateAppIdsRepo; + private final DefaultGroupsService defaultGroupsService; + private final PermissionService permissionService; public UpdateGroupResponseDto updateGroup(UpdateGroupServiceDto updateGroupServiceDto) { String existingGroupEmail = updateGroupServiceDto.getExistingGroupEmail(); @@ -44,6 +42,7 @@ public class UpdateGroupService { existingAppIds.addAll(existingGroupEntityNode.getAppIds()); UpdateGroupResponseDto result = new UpdateGroupResponseDto(existingGroupName, existingGroupEmail, existingAppIds); + Set impactedUsers = new HashSet<>(); if (updateGroupServiceDto.getRenameOperation() != null) { validateIfGroupIsNotDataGroup(existingGroupEmail, existingGroupEntityNode); String newGroupName = updateGroupServiceDto.getRenameOperation().getValue().get(0).toLowerCase(); @@ -52,17 +51,17 @@ public class UpdateGroupService { String newGroupEmail = GroupCreationUtil.createGroupEmail(newGroupName, partitionDomain); validateIfNewGroupNameDoesNotExist(newGroupName, partitionId, newGroupEmail); - renameGroupRepo.run(existingGroupEntityNode, newGroupName); + impactedUsers.addAll(renameGroupRepo.run(existingGroupEntityNode, newGroupName)); result.setEmail(newGroupEmail); result.setName(newGroupName); } - if (updateGroupServiceDto.getAppIdsOperation()!= null) { + if (updateGroupServiceDto.getAppIdsOperation() != null) { List allowedAppIdsList = updateGroupServiceDto.getAppIdsOperation().getValue(); - updateAppIdsRepo.updateAppIds(existingGroupEntityNode, new HashSet<>(allowedAppIdsList)); + impactedUsers.addAll(updateAppIdsRepo.updateAppIds(existingGroupEntityNode, new HashSet<>(allowedAppIdsList))); result.setAppIds(allowedAppIdsList); } - + groupCacheService.refreshListGroupCache(new HashSet<>(impactedUsers), updateGroupServiceDto.getPartitionId()); return result; } diff --git a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/spi/updateappids/UpdateAppIdsRepo.java b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/spi/updateappids/UpdateAppIdsRepo.java index 9ffab481a3de48d40279a4523cea23966ab1c0e4..e455c6c5d7350ed875e28ce837251454ce3e9bb9 100644 --- a/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/spi/updateappids/UpdateAppIdsRepo.java +++ b/entitlements-v2-core/src/main/java/org/opengroup/osdu/entitlements/v2/spi/updateappids/UpdateAppIdsRepo.java @@ -5,5 +5,5 @@ import org.opengroup.osdu.entitlements.v2.model.EntityNode; import java.util.Set; public interface UpdateAppIdsRepo { - void updateAppIds(EntityNode groupNode, Set allowedAppIds); + Set updateAppIds(EntityNode groupNode, Set allowedAppIds); } diff --git a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/AddMemberServiceTests.java b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/AddMemberServiceTests.java index c13e80e4d790724d2e6302aeab64679d13ef9159..a9f3f1779fec89b6067b6d45cda9565744beb37b 100644 --- a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/AddMemberServiceTests.java +++ b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/AddMemberServiceTests.java @@ -25,9 +25,11 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Optional; +import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; @@ -47,6 +49,8 @@ public class AddMemberServiceTests { @MockBean private RetrieveGroupRepo retrieveGroupRepo; @MockBean + private GroupCacheService groupCacheService; + @MockBean private AddMemberRepo addMemberRepo; @MockBean private JaxRsDpsLog log; @@ -87,6 +91,8 @@ public class AddMemberServiceTests { .requesterId("requesterid") .partitionId("common") .build(); + Set allImpactUsers = new HashSet<>(Arrays.asList("member@xxx.com")); + when(addMemberRepo.addMember(any(), any())).thenReturn(allImpactUsers); addMemberService.run(addMemberDto, addMemberServiceDto); @@ -94,6 +100,7 @@ public class AddMemberServiceTests { verify(addMemberRepo).addMember(eq(groupNode), captor.capture()); assertThat(captor.getValue().getRole()).isEqualTo(Role.MEMBER); assertThat(captor.getValue().getPartitionId()).isEqualTo("common"); + verify(groupCacheService).refreshListGroupCache(allImpactUsers, "common"); } @Test @@ -118,6 +125,8 @@ public class AddMemberServiceTests { .requesterId("datafier@test.com") .partitionId("common") .build(); + Set allImpactUsers = new HashSet<>(Arrays.asList("member@xxx.com")); + when(addMemberRepo.addMember(any(), any())).thenReturn(allImpactUsers); addMemberService.run(addMemberDto, addMemberServiceDto); @@ -125,6 +134,7 @@ public class AddMemberServiceTests { verify(addMemberRepo).addMember(eq(groupNode), captor.capture()); assertThat(captor.getValue().getRole()).isEqualTo(Role.MEMBER); assertThat(captor.getValue().getPartitionId()).isEqualTo("common"); + verify(groupCacheService).refreshListGroupCache(allImpactUsers, "common"); } @Test @@ -178,6 +188,8 @@ public class AddMemberServiceTests { .requesterId("requesterid") .partitionId("common") .build(); + Set allImpactUsers = new HashSet<>(Arrays.asList("member@xxx.com")); + when(addMemberRepo.addMember(any(), any())).thenReturn(allImpactUsers); addMemberService.run(addMemberDto, addMemberServiceDto); @@ -186,6 +198,7 @@ public class AddMemberServiceTests { assertThat(captor.getValue().getMemberNode()).isEqualTo(memberNode); assertThat(captor.getValue().getRole()).isEqualTo(Role.MEMBER); assertThat(captor.getValue().getPartitionId()).isEqualTo("common"); + verify(groupCacheService).refreshListGroupCache(allImpactUsers, "common"); } @Test diff --git a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/CreateGroupServiceTests.java b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/CreateGroupServiceTests.java index f8d19ed057f0f564613e7e31b26c0de76566a03b..917005181f98433c5069fb135680b971273ce959 100644 --- a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/CreateGroupServiceTests.java +++ b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/CreateGroupServiceTests.java @@ -19,6 +19,7 @@ import org.opengroup.osdu.entitlements.v2.spi.creategroup.CreateGroupRepo; import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.powermock.reflect.Whitebox; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -26,6 +27,7 @@ import java.util.Set; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -40,6 +42,8 @@ public class CreateGroupServiceTests { @Mock private RetrieveGroupRepo retrieveGroupRepo; @Mock + private GroupCacheService groupCacheService; + @Mock private JaxRsDpsLog logger; @Mock private DefaultGroupsService defaultGroupsService; @@ -68,8 +72,7 @@ public class CreateGroupServiceTests { .name("callerdesid") .dataPartitionId("dp") .build(); - ParentTreeDto parentTreeDto = ParentTreeDto.builder().parentReferences(parents).maxDepth(2).build(); - when(retrieveGroupRepo.loadAllParents(requesterNode)).thenReturn(parentTreeDto); + when(groupCacheService.getFromPartitionCache(requesterNode.getNodeId(), "dp")).thenReturn(parents); try { CreateGroupServiceDto createGroupServiceDto = CreateGroupServiceDto.builder() .requesterId("callerdesid") @@ -103,9 +106,6 @@ public class CreateGroupServiceTests { when(retrieveGroupRepo.groupExistenceValidation("users.data.root@dp.domain.com", "dp")).thenReturn(dataRootGroupNode); when(defaultGroupsService.isNotDefaultGroupName("data.x")).thenReturn(true); when(retrieveGroupRepo.loadAllParents(dataRootGroupNode)).thenReturn(ParentTreeDto.builder().parentReferences(parents).maxDepth(2).build()); - EntityNode requesterNode = EntityNode.createMemberNodeForRequester("callerdesid", "dp"); - ParentTreeDto parentTreeDto = ParentTreeDto.builder().parentReferences(Collections.emptySet()).maxDepth(2).build(); - when(retrieveGroupRepo.loadAllParents(requesterNode)).thenReturn(parentTreeDto); try { CreateGroupServiceDto createGroupServiceDto = CreateGroupServiceDto.builder() .requesterId("callerdesid") @@ -143,14 +143,16 @@ public class CreateGroupServiceTests { .partitionDomain("dp.domain.com") .partitionId("dp").build(); EntityNode requesterNode = EntityNode.createMemberNodeForRequester("callerdesid", "dp"); - ParentTreeDto parentTreeDto = ParentTreeDto.builder().parentReferences(Collections.emptySet()).maxDepth(2).build(); - when(retrieveGroupRepo.loadAllParents(requesterNode)).thenReturn(parentTreeDto); + when(groupCacheService.getFromPartitionCache(requesterNode.getNodeId(), "dp")).thenReturn(Collections.emptySet()); ArgumentCaptor captor = ArgumentCaptor.forClass(CreateGroupRepoDto.class); when(defaultGroupsService.isNotDefaultGroupName("data.x")).thenReturn(true); + Set impactedUsers = new HashSet<>(Arrays.asList("callerdesid")); + when(createGroupRepo.createGroup(any(), any())).thenReturn(impactedUsers); createGroupService.run(groupNode, createGroupServiceDto); verify(createGroupRepo, times(1)).createGroup(eq(groupNode), captor.capture()); assertThat(captor.getValue().getDataRootGroupNode()).isNotNull(); assertThat(captor.getValue().isAddDataRootGroup()).isTrue(); + verify(groupCacheService).refreshListGroupCache(impactedUsers, "dp"); } @Test @@ -166,13 +168,15 @@ public class CreateGroupServiceTests { .partitionDomain("dp.domain.com") .partitionId("dp").build(); EntityNode requesterNode = EntityNode.createMemberNodeForRequester("callerdesid", "dp"); - ParentTreeDto parentTreeDto = ParentTreeDto.builder().parentReferences(Collections.emptySet()).maxDepth(2).build(); - when(retrieveGroupRepo.loadAllParents(requesterNode)).thenReturn(parentTreeDto); + when(groupCacheService.getFromPartitionCache(requesterNode.getNodeId(), "dp")).thenReturn(Collections.emptySet()); ArgumentCaptor captor = ArgumentCaptor.forClass(CreateGroupRepoDto.class); + Set impactedUsers = new HashSet<>(Arrays.asList("callerdesid")); + when(createGroupRepo.createGroup(any(), any())).thenReturn(impactedUsers); createGroupService.run(groupNode, createGroupServiceDto); verify(createGroupRepo, times(1)).createGroup(eq(groupNode), captor.capture()); assertThat(captor.getValue().getDataRootGroupNode()).isNull(); assertThat(captor.getValue().isAddDataRootGroup()).isFalse(); + verify(groupCacheService).refreshListGroupCache(impactedUsers, "dp"); } @Test @@ -188,13 +192,15 @@ public class CreateGroupServiceTests { .partitionDomain("dp.domain.com") .partitionId("dp").build(); EntityNode requesterNode = EntityNode.createMemberNodeForRequester("callerdesid", "dp"); - ParentTreeDto parentTreeDto = ParentTreeDto.builder().parentReferences(Collections.emptySet()).maxDepth(2).build(); - when(retrieveGroupRepo.loadAllParents(requesterNode)).thenReturn(parentTreeDto); + when(groupCacheService.getFromPartitionCache(requesterNode.getNodeId(), "dp")).thenReturn(Collections.emptySet()); ArgumentCaptor captor = ArgumentCaptor.forClass(CreateGroupRepoDto.class); when(defaultGroupsService.isNotDefaultGroupName("data.x")).thenReturn(false); + Set impactedUsers = new HashSet<>(Arrays.asList("callerdesid")); + when(createGroupRepo.createGroup(any(), any())).thenReturn(impactedUsers); createGroupService.run(groupNode, createGroupServiceDto); verify(createGroupRepo, times(1)).createGroup(eq(groupNode), captor.capture()); assertThat(captor.getValue().getDataRootGroupNode()).isNull(); assertThat(captor.getValue().isAddDataRootGroup()).isFalse(); + verify(groupCacheService).refreshListGroupCache(impactedUsers, "dp"); } } diff --git a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/DeleteGroupServiceTests.java b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/DeleteGroupServiceTests.java index 3f8d98f01d33a1dd96a99fd7f320c6065024ac84..40ac62ec93f5da76e5efdab1dea46ca51eaa121e 100644 --- a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/DeleteGroupServiceTests.java +++ b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/DeleteGroupServiceTests.java @@ -22,7 +22,9 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; import java.util.Collections; +import java.util.HashSet; import java.util.Optional; +import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -36,10 +38,12 @@ import static org.mockito.Mockito.when; public class DeleteGroupServiceTests { @MockBean - private DeleteGroupRepo deleteGroupRepoRedis; + private DeleteGroupRepo deleteGroupRepo; @MockBean private RetrieveGroupRepo retrieveGroupRepo; @MockBean + private GroupCacheService groupCacheService; + @MockBean private JaxRsDpsLog logger; @MockBean private DefaultGroupsService defaultGroupsService; @@ -68,10 +72,13 @@ public class DeleteGroupServiceTests { .requesterId("callerdesid") .partitionId("common").build(); when(defaultGroupsService.isDefaultGroupName("data.x.viewers")).thenReturn(false); + Set impactedUsers = new HashSet<>(Collections.singletonList("callerdesid")); + when(deleteGroupRepo.deleteGroup(any())).thenReturn(impactedUsers); this.service.run(groupNode, deleteGroupServiceDto); - verify(deleteGroupRepoRedis).deleteGroup(groupNode); + verify(deleteGroupRepo).deleteGroup(groupNode); + verify(groupCacheService).refreshListGroupCache(impactedUsers, "common"); } @Test @@ -85,7 +92,7 @@ public class DeleteGroupServiceTests { this.service.run(groupNode, deleteGroupServiceDto); - verify(deleteGroupRepoRedis, never()).deleteGroup(any(EntityNode.class)); + verify(deleteGroupRepo, never()).deleteGroup(any(EntityNode.class)); } @Test diff --git a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/DeleteMemberServiceTest.java b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/DeleteMemberServiceTest.java index ae8c52ebcf920c36078d5424d87582122182db66..171179ccd86965093dfbed513e32192e469494bd 100644 --- a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/DeleteMemberServiceTest.java +++ b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/DeleteMemberServiceTest.java @@ -29,6 +29,8 @@ public class DeleteMemberServiceTest { private RetrieveGroupRepo retrieveGroupRepo; @Mock private RemoveMemberService removeMemberService; + @Mock + private GroupCacheService groupCacheService; @InjectMocks private DeleteMemberService deleteMemberService; @@ -65,6 +67,7 @@ public class DeleteMemberServiceTest { verify(retrieveGroupRepo, times(1)).loadDirectParents(DATA_PARTITION_ID, MEMBER_EMAIL); verify(removeMemberService, times(1)).removeMember(buildRemoveMemberServiceDto(groupEmail1)); verify(removeMemberService, times(1)).removeMember(buildRemoveMemberServiceDto(groupEmail2)); + verify(groupCacheService).flushListGroupCacheForUser(MEMBER_EMAIL, DATA_PARTITION_ID); } private RemoveMemberServiceDto buildRemoveMemberServiceDto(String groupEmail) { diff --git a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/RemoveMemberServiceTests.java b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/RemoveMemberServiceTests.java index a6f29829827ff54f22f08fd5d2ce2c4683db86ed..61a7553fc89f9f986127c202708cccc8560cf2bd 100644 --- a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/RemoveMemberServiceTests.java +++ b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/RemoveMemberServiceTests.java @@ -25,6 +25,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; import org.springframework.test.context.junit4.SpringRunner; +import java.util.Collections; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; @@ -42,6 +43,8 @@ public class RemoveMemberServiceTests { @MockBean private RetrieveGroupRepo retrieveGroupRepo; @MockBean + private GroupCacheService groupCacheService; + @MockBean private RemoveMemberRepo removeMemberRepo; @MockBean private RequestInfo requestInfo; @@ -109,10 +112,12 @@ public class RemoveMemberServiceTests { .requesterId("requesterid") .partitionId("common") .build(); + when(removeMemberRepo.removeMember(any(), any(), any())).thenReturn(Collections.emptySet()); removeMemberService.removeMember(removeMemberServiceDto); verify(removeMemberRepo).removeMember(groupNode, memberNode, removeMemberServiceDto); + verify(groupCacheService).refreshListGroupCache(Collections.emptySet(), "common"); } @Test @@ -149,9 +154,11 @@ public class RemoveMemberServiceTests { .requesterId("datafier@evd-ddl-us-common.iam.gserviceaccount.com") .partitionId("common") .build(); + when(removeMemberRepo.removeMember(any(), any(), any())).thenReturn(Collections.emptySet()); removeMemberService.removeMember(removeMemberServiceDto); + verify(groupCacheService).refreshListGroupCache(Collections.emptySet(), "common"); verify(removeMemberRepo).removeMember(groupNode, memberNode, removeMemberServiceDto); } diff --git a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/UpdateGroupServiceTests.java b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/UpdateGroupServiceTests.java index c118188bfff7f622e20d6a5ec20a51a8ef98879c..2c4dc722acf199ef8ab627b422a29d87eff2b98a 100644 --- a/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/UpdateGroupServiceTests.java +++ b/entitlements-v2-core/src/test/java/org/opengroup/osdu/entitlements/v2/service/UpdateGroupServiceTests.java @@ -20,9 +20,11 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Optional; +import java.util.Set; @SpringBootTest @RunWith(SpringRunner.class) @@ -42,6 +44,8 @@ public class UpdateGroupServiceTests { @MockBean private RetrieveGroupRepo retrieveGroupRepo; @MockBean + private GroupCacheService groupCacheService; + @MockBean private RenameGroupRepo renameGroupRepo; @MockBean private UpdateAppIdsRepo updateAppIdsRepo; @@ -62,12 +66,14 @@ public class UpdateGroupServiceTests { Mockito.when(retrieveGroupRepo.groupExistenceValidation(TEST_EXISTING_USER_GROUP_EMAIL, TEST_PARTITION)).thenReturn(groupNode); Mockito.when(permissionService.hasOwnerPermissionOf(Mockito.any(), Mockito.any())).thenReturn(true); + Mockito.when(renameGroupRepo.run(groupNode, newGroupName)).thenReturn(Collections.emptySet()); UpdateGroupResponseDto responseDto = updateGroupService.updateGroup(serviceDto); Mockito.verify(renameGroupRepo).run(groupNode, newGroupName); Assert.assertNotNull(responseDto); Assert.assertEquals("users.test.x@dp.domain", responseDto.getEmail()); Assert.assertEquals("users.test.x", responseDto.getName()); + Mockito.verify(groupCacheService).refreshListGroupCache(Collections.emptySet(), "dp"); } @Test @@ -95,7 +101,6 @@ public class UpdateGroupServiceTests { public void shouldThrow400WhenNewGroupNameIsAlreadyExist() { String newGroupName = "users.test.x"; String newGroupEmail = "users.test.x@dp.domain"; - EntityNode existedNewGroupNode = createGroupNode(newGroupName, newGroupEmail); EntityNode groupNode = createGroupNode(TEST_EXISTING_USER_GROUP_NAME, TEST_EXISTING_USER_GROUP_EMAIL); UpdateGroupOperation renameOperation = createUpdateGroupOperation(RENAME_PATH, newGroupName); @@ -169,14 +174,18 @@ public class UpdateGroupServiceTests { Mockito.when(retrieveGroupRepo.groupExistenceValidation(TEST_EXISTING_USER_GROUP_EMAIL, TEST_PARTITION)).thenReturn(groupNode); Mockito.when(permissionService.hasOwnerPermissionOf(Mockito.any(), Mockito.any())).thenReturn(true); - UpdateGroupResponseDto responseDto = updateGroupService.updateGroup(serviceDto); List appIds = new ArrayList<>(); appIds.add("app1"); appIds.add("app2"); + Mockito.when(updateAppIdsRepo.updateAppIds(groupNode, new HashSet<>(appIds))).thenReturn(Collections.emptySet()); + + UpdateGroupResponseDto responseDto = updateGroupService.updateGroup(serviceDto); + Mockito.verify(updateAppIdsRepo).updateAppIds(groupNode, new HashSet<>(appIds)); Assert.assertNotNull(responseDto); Assert.assertEquals(appIds, responseDto.getAppIds()); + Mockito.verify(groupCacheService).refreshListGroupCache(Collections.emptySet(), "dp"); } @Test @@ -201,27 +210,30 @@ public class UpdateGroupServiceTests { } @Test - public void shouldUpdateGroupAppIdsandRenameSuccessfullyWhenUserHasOwnerPermissionOfTheUserGroup() { + public void shouldUpdateGroupAppIdsAndRenameSuccessfullyWhenUserHasOwnerPermissionOfTheUserGroup() { String newGroupName = "users.test.x"; EntityNode groupNode = createGroupNode(TEST_EXISTING_USER_GROUP_NAME, TEST_EXISTING_USER_GROUP_EMAIL); UpdateGroupOperation renameOperation = createUpdateGroupOperation(RENAME_PATH, newGroupName); UpdateGroupOperation appIdsOperation = createUpdateGroupOperation(APP_IDS_PATH, "app1", "app2"); UpdateGroupServiceDto serviceDto = createUpdateGroupServiceDto(TEST_EXISTING_USER_GROUP_EMAIL, renameOperation, appIdsOperation); + Set impactedUsers = new HashSet<>(Collections.singletonList(USER_A)); + List appIds = new ArrayList<>(); + appIds.add("app1"); + appIds.add("app2"); Mockito.when(retrieveGroupRepo.groupExistenceValidation(TEST_EXISTING_USER_GROUP_EMAIL, TEST_PARTITION)).thenReturn(groupNode); Mockito.when(permissionService.hasOwnerPermissionOf(Mockito.any(), Mockito.any())).thenReturn(true); + Mockito.when(renameGroupRepo.run(groupNode, newGroupName)).thenReturn(impactedUsers); + Mockito.when(updateAppIdsRepo.updateAppIds(groupNode, new HashSet<>(appIds))).thenReturn(impactedUsers); UpdateGroupResponseDto responseDto = updateGroupService.updateGroup(serviceDto); - List appIds = new ArrayList<>(); - appIds.add("app1"); - appIds.add("app2"); - Mockito.verify(renameGroupRepo).run(groupNode, newGroupName); Mockito.verify(updateAppIdsRepo).updateAppIds(groupNode, new HashSet<>(appIds)); Assert.assertNotNull(responseDto); Assert.assertEquals(appIds, responseDto.getAppIds()); Assert.assertEquals("users.test.x@dp.domain", responseDto.getEmail()); Assert.assertEquals("users.test.x", responseDto.getName()); + Mockito.verify(groupCacheService).refreshListGroupCache(impactedUsers, "dp"); } private EntityNode createGroupNode(String groupName, String groupEmail) { diff --git a/pom.xml b/pom.xml index e4e558be2b5c367fa3f47b1655e9398647b0d0ac..dea06ea5486da0ca376348509bba7a20b7808eb6 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 - 0.9.0-rc7 + 0.9.0-rc10 1.8 1.8 1.8 diff --git a/provider/entitlements-v2-aws/src/main/java/org/opengroup/osdu/entitlements/v2/aws/service/GroupCacheServiceAws.java b/provider/entitlements-v2-aws/src/main/java/org/opengroup/osdu/entitlements/v2/aws/service/GroupCacheServiceAws.java index 499d59c2196b183ec1c28b18cdb02c9b886c4524..82e5dd9c717f39935dfc4f1e48980eb2fdca98fc 100644 --- a/provider/entitlements-v2-aws/src/main/java/org/opengroup/osdu/entitlements/v2/aws/service/GroupCacheServiceAws.java +++ b/provider/entitlements-v2-aws/src/main/java/org/opengroup/osdu/entitlements/v2/aws/service/GroupCacheServiceAws.java @@ -43,4 +43,14 @@ public class GroupCacheServiceAws implements GroupCacheService { } return result; } + + @Override + public void refreshListGroupCache(Set userIds, String partitionId) { + + } + + @Override + public void flushListGroupCacheForUser(String userId, String partitionId) { + + } } diff --git a/provider/entitlements-v2-aws/src/main/java/org/opengroup/osdu/entitlements/v2/aws/spi/updateappids/AwsUpdateAppIdsRepo.java b/provider/entitlements-v2-aws/src/main/java/org/opengroup/osdu/entitlements/v2/aws/spi/updateappids/AwsUpdateAppIdsRepo.java index c4785b70c3d223c13eb409f16e3377b6baf632d5..bca14a5a282a94a7cf86f39b438ebfdb4599afe4 100644 --- a/provider/entitlements-v2-aws/src/main/java/org/opengroup/osdu/entitlements/v2/aws/spi/updateappids/AwsUpdateAppIdsRepo.java +++ b/provider/entitlements-v2-aws/src/main/java/org/opengroup/osdu/entitlements/v2/aws/spi/updateappids/AwsUpdateAppIdsRepo.java @@ -28,6 +28,7 @@ import org.opengroup.osdu.entitlements.v2.spi.updateappids.UpdateAppIdsRepo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import java.util.HashSet; import java.util.Set; @Repository @@ -49,7 +50,7 @@ public class AwsUpdateAppIdsRepo extends BaseRepo implements UpdateAppIdsRepo { private Retry retry; @Override - public void updateAppIds(EntityNode groupNode, Set allowedAppIds) { + public Set updateAppIds(EntityNode groupNode, Set allowedAppIds) { log.info(String.format("Updating allowed appids for group %s to %s in redis", groupNode, allowedAppIds)); try { executeAppIdUpdate(groupNode, allowedAppIds); @@ -61,6 +62,7 @@ public class AwsUpdateAppIdsRepo extends BaseRepo implements UpdateAppIdsRepo { executedCommands.clear(); } auditLogger.updateAppIds(AuditStatus.SUCCESS, groupNode.getNodeId(), allowedAppIds); + return new HashSet<>(); } private void executeAppIdUpdate(EntityNode groupEntityNode, Set appIds) { diff --git a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/service/GroupCacheServiceAzure.java b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/service/GroupCacheServiceAzure.java index 90182f920aa7f9372cd2e6f75c4cf7786e2f7e1b..a59f3e304126da5c49611a65ec39e42e48d2ca32 100644 --- a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/service/GroupCacheServiceAzure.java +++ b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/service/GroupCacheServiceAzure.java @@ -17,6 +17,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import java.security.SecureRandom; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -30,6 +31,8 @@ public class GroupCacheServiceAzure implements GroupCacheService { private final HitsNMissesMetricService metricService; private final RedissonClient redissonClient; private final Retry retry; + private static final String REDIS_KEY_FORMAT = "%s-%s"; + @Value("${redisson.lock.acquisition.timeout}") private int redissonLockAcquisitionTimeOut; @Value("${redisson.lock.expiration}") @@ -37,7 +40,7 @@ public class GroupCacheServiceAzure implements GroupCacheService { @Override public Set getFromPartitionCache(String requesterId, String partitionId) { - String cacheKey = String.format("%s-%s", requesterId, partitionId); + String cacheKey = String.format(REDIS_KEY_FORMAT, requesterId, partitionId); ParentReferences parentReferences = redisGroupCache.get(cacheKey); if (parentReferences == null) { String lockKey = String.format("lock-%s", cacheKey); @@ -49,6 +52,26 @@ public class GroupCacheServiceAzure implements GroupCacheService { } } + @Override + public void refreshListGroupCache(final Set userIds, String partitionId) { + userIds.forEach(userId -> flushListGroupCacheForUser(userId, partitionId)); + } + + /** + Flush the list group cache for user by setting the ttl for that user's cache entry to a small random value between a lower and upper bound range. + */ + @Override + public void flushListGroupCacheForUser(String userId, String partitionId) { + String key = String.format(REDIS_KEY_FORMAT, userId, partitionId); + long baseTtl = partitionCacheTtlService.getCacheFlushTtlBaseOfPartition(partitionId); + long jitter = partitionCacheTtlService.getCacheFlushTtlJitterOfPartition(partitionId); + if (redisGroupCache.getTtl(key) > baseTtl + jitter) { + SecureRandom random = new SecureRandom(); + long ttlOfKey = baseTtl + (long)(random.nextDouble() * jitter); + redisGroupCache.updateTtl(key, ttlOfKey); + } + } + /** The unblock function may throw exception when cache update takes longer than the lock expiration time, so when the time it tries to unlock the lock has already expired or re-acquired by another thread. In this case, since the lock is already released, we just @@ -99,5 +122,4 @@ public class GroupCacheServiceAzure implements GroupCacheService { parentReferences.setParentReferencesOfUser(allParents); return parentReferences; } - } diff --git a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/service/PartitionCacheTtlService.java b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/service/PartitionCacheTtlService.java index d7cfc6f827f88c54d1eb626275a28f479cf8d15a..c4a7dcd147aa2c50cee477b78813a6dca0845ba4 100644 --- a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/service/PartitionCacheTtlService.java +++ b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/service/PartitionCacheTtlService.java @@ -26,6 +26,10 @@ public class PartitionCacheTtlService { private static final String LOGGER_NAME = "CronJobLogger"; private static final String CACHE_TTL_PROPERTY_NAME = "ent-cache-ttl"; + private static final String CACHE_FLUSH_TTL_BASE = "ent-cache-flush-ttl-base"; + private static final String CACHE_FLUSH_TTL_JITTER = "ent-cache-flush-ttl-jitter"; + private static final long MAX_TTL_BASE = 10000; + private static final long MAX_TTL_JITTER = 50000; /** * Logger is not depending on request data @@ -36,8 +40,14 @@ public class PartitionCacheTtlService { @Value("${app.redis.ttl.seconds}") private int cacheTtl; + @Value("${cache.flush.ttl.base}") + private long cacheFlushTtlBase; + @Value("${cache.flush.ttl.jitter}") + private long cacheFlushTtlJitter; private final ConcurrentMap ttlPerDataPartition = new ConcurrentHashMap<>(); + private final ConcurrentMap baseTtlPerDataPartition = new ConcurrentHashMap<>(); + private final ConcurrentMap jitterTtlPerDataPartition = new ConcurrentHashMap<>(); @PostConstruct private void init() { @@ -55,6 +65,28 @@ public class PartitionCacheTtlService { return ttl; } + /** + * Returns the base ttl for cache flush in milliseconds for a given data partition id. Maximum is 10000ms. + */ + public long getCacheFlushTtlBaseOfPartition(String dataPartitionId) { + Long baseTtl = baseTtlPerDataPartition.get(dataPartitionId); + if (baseTtl == null || baseTtl > MAX_TTL_BASE) { + return cacheFlushTtlBase; + } + return baseTtl; + } + + /** + * Returns the jitter amount for cache flush in milliseconds for a given data partition id. Maximum is 50000ms. + */ + public long getCacheFlushTtlJitterOfPartition(String dataPartitionId) { + Long jitterTtl = jitterTtlPerDataPartition.get(dataPartitionId); + if (jitterTtl == null || jitterTtl > MAX_TTL_JITTER) { + return cacheFlushTtlJitter; + } + return jitterTtl; + } + /** * Refresh the ttl info cache every 5 minutes */ @@ -68,14 +100,20 @@ public class PartitionCacheTtlService { getDataPartitionIds(provider).forEach(dataPartitionId -> getPartitionInfo(provider, dataPartitionId) .ifPresent(partitionInfo -> { long ttl = 1000L * cacheTtl; + long ttlFlushBase = cacheFlushTtlBase; + long ttlFlushJitter = cacheFlushTtlJitter; if (partitionInfo.getProperties().containsKey(CACHE_TTL_PROPERTY_NAME)) { - ttl = new Gson().toJsonTree(partitionInfo.getProperties()) - .getAsJsonObject() - .get(CACHE_TTL_PROPERTY_NAME) - .getAsJsonObject() - .get("value").getAsLong(); + ttl = getValueFromKey(partitionInfo, CACHE_TTL_PROPERTY_NAME); } ttlPerDataPartition.put(dataPartitionId, ttl); + if (partitionInfo.getProperties().containsKey(CACHE_FLUSH_TTL_BASE)) { + ttlFlushBase = getValueFromKey(partitionInfo, CACHE_FLUSH_TTL_BASE); + } + baseTtlPerDataPartition.put(dataPartitionId, ttlFlushBase); + if (partitionInfo.getProperties().containsKey(CACHE_FLUSH_TTL_JITTER)) { + ttlFlushJitter = getValueFromKey(partitionInfo, CACHE_FLUSH_TTL_JITTER); + } + jitterTtlPerDataPartition.put(dataPartitionId, ttlFlushJitter); })); } @@ -96,4 +134,12 @@ public class PartitionCacheTtlService { return Collections.emptyList(); } } + + private Long getValueFromKey(PartitionInfo partitionInfo, String key) { + return new Gson().toJsonTree(partitionInfo.getProperties()) + .getAsJsonObject() + .get(key) + .getAsJsonObject() + .get("value").getAsLong(); + } } diff --git a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/addmember/AddMemberRepoGremlin.java b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/addmember/AddMemberRepoGremlin.java index 527f15d84be05e45e7b89baff326a0f3bea1d07d..cb9d266946262dfe64e4965cad3350204777ba97 100644 --- a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/addmember/AddMemberRepoGremlin.java +++ b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/addmember/AddMemberRepoGremlin.java @@ -6,11 +6,13 @@ import org.opengroup.osdu.entitlements.v2.azure.service.AddEdgeDto; import org.opengroup.osdu.entitlements.v2.azure.service.GraphTraversalSourceUtilService; import org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.constant.EdgePropertyNames; import org.opengroup.osdu.entitlements.v2.logging.AuditLogger; +import org.opengroup.osdu.entitlements.v2.model.ChildrenTreeDto; import org.opengroup.osdu.entitlements.v2.model.EntityNode; import org.opengroup.osdu.entitlements.v2.model.Role; import org.opengroup.osdu.entitlements.v2.model.addmember.AddMemberRepoDto; import org.opengroup.osdu.entitlements.v2.spi.Operation; import org.opengroup.osdu.entitlements.v2.spi.addmember.AddMemberRepo; +import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.springframework.stereotype.Repository; import java.util.Collections; @@ -23,6 +25,7 @@ import java.util.Set; public class AddMemberRepoGremlin implements AddMemberRepo { private final GraphTraversalSourceUtilService graphTraversalSourceUtilService; private final AuditLogger auditlogger; + private final RetrieveGroupRepo retrieveGroupRepo; /** * Adds a member by adding two edges in the database. @@ -30,6 +33,8 @@ public class AddMemberRepoGremlin implements AddMemberRepo { */ @Override public Set addMember(EntityNode groupNode, AddMemberRepoDto addMemberRepoDto) { + ChildrenTreeDto childrenUserDto = retrieveGroupRepo.loadAllChildrenUsers(addMemberRepoDto.getMemberNode()); + Set impactedUsers = new HashSet<>(childrenUserDto.getChildrenUserIds()); graphTraversalSourceUtilService.createVertexFromEntityNodeIdempotent(addMemberRepoDto.getMemberNode()); AddEdgeDto.AddEdgeDtoBuilder addChildEdgeRequestBuilder = AddEdgeDto.builder() .fromNodeId(groupNode.getNodeId()) @@ -62,7 +67,7 @@ public class AddMemberRepoGremlin implements AddMemberRepo { addMemberRepoDto.getRole()); throw e; } - return new HashSet<>(); + return new HashSet<>(impactedUsers); } @Override diff --git a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/creategroup/CreateGroupRepoGremlin.java b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/creategroup/CreateGroupRepoGremlin.java index 8821b0285382b39b57eac7b827d3f09ce51af16d..1d87c02f9bbe32ed3d13bb039b89d2fc58c85f14 100644 --- a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/creategroup/CreateGroupRepoGremlin.java +++ b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/creategroup/CreateGroupRepoGremlin.java @@ -3,18 +3,21 @@ package org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.creategroup; import org.opengroup.osdu.core.common.logging.audit.AuditStatus; import org.opengroup.osdu.entitlements.v2.azure.service.GraphTraversalSourceUtilService; import org.opengroup.osdu.entitlements.v2.logging.AuditLogger; -import org.opengroup.osdu.entitlements.v2.model.addmember.AddMemberRepoDto; -import org.opengroup.osdu.entitlements.v2.model.creategroup.CreateGroupRepoDto; import org.opengroup.osdu.entitlements.v2.model.EntityNode; import org.opengroup.osdu.entitlements.v2.model.Role; +import org.opengroup.osdu.entitlements.v2.model.addmember.AddMemberRepoDto; +import org.opengroup.osdu.entitlements.v2.model.creategroup.CreateGroupRepoDto; import org.opengroup.osdu.entitlements.v2.spi.Operation; import org.opengroup.osdu.entitlements.v2.spi.addmember.AddMemberRepo; import org.opengroup.osdu.entitlements.v2.spi.creategroup.CreateGroupRepo; +import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import java.util.ArrayList; import java.util.Deque; import java.util.HashSet; +import java.util.List; import java.util.Set; @Repository @@ -26,13 +29,16 @@ public class CreateGroupRepoGremlin implements CreateGroupRepo { private AddMemberRepo addMemberRepo; @Autowired private AuditLogger auditLogger; + @Autowired + private RetrieveGroupRepo retrieveGroupRepo; @Override public Set createGroup(EntityNode groupNode, CreateGroupRepoDto createGroupRepoDto) { + Set impactedUsers; try { - executeCreateGroupOperation(groupNode, createGroupRepoDto); + impactedUsers = executeCreateGroupOperation(groupNode, createGroupRepoDto); auditLogger.createGroup(AuditStatus.SUCCESS, groupNode.getNodeId()); - return new HashSet<>(); + return impactedUsers; } catch (Exception e) { auditLogger.createGroup(AuditStatus.FAILURE, groupNode.getNodeId()); throw e; @@ -60,11 +66,15 @@ public class CreateGroupRepoGremlin implements CreateGroupRepo { addMemberRepo.addMember(groupNode, addMemberRepoDto); } - private void executeCreateGroupOperation(EntityNode groupNode, CreateGroupRepoDto createGroupRepoDto) { + private Set executeCreateGroupOperation(EntityNode groupNode, CreateGroupRepoDto createGroupRepoDto) { + List impactedUsers = new ArrayList<>(); + impactedUsers.add(createGroupRepoDto.getRequesterNode().getNodeId()); graphTraversalSourceUtilService.createGroupVertex(groupNode); addRequesterAsOwnerMemberToGroup(groupNode, createGroupRepoDto); if (createGroupRepoDto.isAddDataRootGroup()) { addRootGroupNodeAsMemberOfGroupNewGroup(groupNode, createGroupRepoDto); + impactedUsers.addAll(retrieveGroupRepo.loadAllChildrenUsers(createGroupRepoDto.getDataRootGroupNode()).getChildrenUserIds()); } + return new HashSet<>(impactedUsers); } } diff --git a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/deletegroup/DeleteGroupRepoGremlin.java b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/deletegroup/DeleteGroupRepoGremlin.java index 56c4fc96f945dfb397471e7fc74caf1cc3c610bf..7522a4a6352c2d9481e7e249cedfd8ece8fbaa64 100644 --- a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/deletegroup/DeleteGroupRepoGremlin.java +++ b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/deletegroup/DeleteGroupRepoGremlin.java @@ -9,11 +9,14 @@ import org.opengroup.osdu.entitlements.v2.logging.AuditLogger; import org.opengroup.osdu.entitlements.v2.model.EntityNode; import org.opengroup.osdu.entitlements.v2.spi.Operation; import org.opengroup.osdu.entitlements.v2.spi.deletegroup.DeleteGroupRepo; +import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import java.util.Collections; import java.util.Deque; import java.util.HashSet; +import java.util.List; import java.util.Set; @Repository @@ -22,6 +25,9 @@ public class DeleteGroupRepoGremlin implements DeleteGroupRepo { @Autowired private GremlinConnector gremlinConnector; + @Autowired + private RetrieveGroupRepo retrieveGroupRepo; + @Autowired private AuditLogger auditLogger; @@ -30,10 +36,11 @@ public class DeleteGroupRepoGremlin implements DeleteGroupRepo { */ @Override public Set deleteGroup(final EntityNode groupNode) { + Set impactedUsers; try { - executeDeleteGroupOperation(groupNode); + impactedUsers = executeDeleteGroupOperation(groupNode); auditLogger.deleteGroup(AuditStatus.SUCCESS, groupNode.getNodeId()); - return new HashSet<>(); + return impactedUsers; } catch (Exception e) { auditLogger.deleteGroup(AuditStatus.FAILURE, groupNode.getNodeId()); throw e; @@ -45,11 +52,13 @@ public class DeleteGroupRepoGremlin implements DeleteGroupRepo { return new HashSet<>(); } - private void executeDeleteGroupOperation(final EntityNode groupNode) { + private Set executeDeleteGroupOperation(final EntityNode groupNode) { + List impactedUsers = retrieveGroupRepo.loadAllChildrenUsers(groupNode).getChildrenUserIds(); Traversal traversal = gremlinConnector.getGraphTraversalSource().V() .has(VertexPropertyNames.NODE_ID, groupNode.getNodeId()) .has(VertexPropertyNames.DATA_PARTITION_ID, groupNode.getDataPartitionId()) .drop(); gremlinConnector.removeVertex(traversal); + return (impactedUsers == null) ? Collections.emptySet() : new HashSet<>(impactedUsers); } } diff --git a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/removemember/RemoveMemberRepoGremlin.java b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/removemember/RemoveMemberRepoGremlin.java index 820951864985a538f08a7dbeccf1be9f1fad200a..744a881542ee6c90aae886554b338f918e46c6e4 100644 --- a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/removemember/RemoveMemberRepoGremlin.java +++ b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/removemember/RemoveMemberRepoGremlin.java @@ -8,10 +8,13 @@ import org.opengroup.osdu.entitlements.v2.logging.AuditLogger; import org.opengroup.osdu.entitlements.v2.model.EntityNode; import org.opengroup.osdu.entitlements.v2.model.removemember.RemoveMemberServiceDto; import org.opengroup.osdu.entitlements.v2.spi.removemember.RemoveMemberRepo; +import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; @Repository @@ -20,6 +23,9 @@ public class RemoveMemberRepoGremlin implements RemoveMemberRepo { @Autowired private GraphTraversalSourceUtilService graphTraversalSourceUtilService; + @Autowired + private RetrieveGroupRepo retrieveGroupRepo; + @Autowired private AuditLogger auditLogger; @@ -28,17 +34,19 @@ public class RemoveMemberRepoGremlin implements RemoveMemberRepo { */ @Override public Set removeMember(EntityNode groupNode, EntityNode memberNode, RemoveMemberServiceDto removeMemberServiceDto) { + Set impactedUsers; try { - executeRemoveMemberOperation(groupNode, memberNode); + impactedUsers = executeRemoveMemberOperation(groupNode, memberNode); auditLogger.removeMember(AuditStatus.SUCCESS, groupNode.getNodeId(), memberNode.getNodeId(), removeMemberServiceDto.getRequesterId()); - return new HashSet<>(); + return impactedUsers; } catch (Exception e) { auditLogger.removeMember(AuditStatus.FAILURE, groupNode.getNodeId(), memberNode.getNodeId(), removeMemberServiceDto.getRequesterId()); throw e; } } - private void executeRemoveMemberOperation(EntityNode groupNode, EntityNode memberNode) { + private Set executeRemoveMemberOperation(EntityNode groupNode, EntityNode memberNode) { + List impactedUsers = retrieveGroupRepo.loadAllChildrenUsers(memberNode).getChildrenUserIds(); RemoveEdgeDto removeChildEdgeDto = RemoveEdgeDto.builder() .fromNodeId(groupNode.getNodeId()) .fromDataPartitionId(groupNode.getDataPartitionId()) @@ -55,5 +63,6 @@ public class RemoveMemberRepoGremlin implements RemoveMemberRepo { .build(); graphTraversalSourceUtilService.removeEdge(removeChildEdgeDto); graphTraversalSourceUtilService.removeEdge(removeParentEdgeDto); + return (impactedUsers == null) ? Collections.emptySet() : new HashSet<>(impactedUsers); } } diff --git a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/renamegroup/RenameGroupRepoGremlin.java b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/renamegroup/RenameGroupRepoGremlin.java index 0813d1d72275c8b07a7767c87a09cb003788d578..99ad34b2d8c07c7c132783cc1c288aca61ffce73 100644 --- a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/renamegroup/RenameGroupRepoGremlin.java +++ b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/renamegroup/RenameGroupRepoGremlin.java @@ -10,32 +10,39 @@ import org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.constant.VertexPrope import org.opengroup.osdu.entitlements.v2.logging.AuditLogger; import org.opengroup.osdu.entitlements.v2.model.EntityNode; import org.opengroup.osdu.entitlements.v2.spi.renamegroup.RenameGroupRepo; +import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.opengroup.osdu.entitlements.v2.util.GroupCreationUtil; import org.springframework.stereotype.Repository; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; @Repository @RequiredArgsConstructor public class RenameGroupRepoGremlin implements RenameGroupRepo { + private final RetrieveGroupRepo retrieveGroupRepo; private final GremlinConnector gremlinConnector; private final AuditLogger auditLogger; @Override public Set run(EntityNode groupNode, String newGroupName) { + Set impactedUsers; try { - executeRenameGroupOperation(groupNode, newGroupName); + impactedUsers = executeRenameGroupOperation(groupNode, newGroupName); auditLogger.updateGroup(AuditStatus.SUCCESS, groupNode.getNodeId()); - return new HashSet<>(); + return impactedUsers; } catch (Exception e) { auditLogger.updateGroup(AuditStatus.FAILURE, groupNode.getNodeId()); throw e; } } - private void executeRenameGroupOperation(EntityNode groupNode, String newGroupName) { + private Set executeRenameGroupOperation(EntityNode groupNode, String newGroupName) { + List impactedUsers = new ArrayList<>(); + impactedUsers.addAll(retrieveGroupRepo.loadAllChildrenUsers(groupNode).getChildrenUserIds()); String partitionDomain = groupNode.getNodeId().split("@")[1]; String newNodeId = GroupCreationUtil.createGroupEmail(newGroupName, partitionDomain); Traversal traversal = gremlinConnector.getGraphTraversalSource().V() @@ -44,5 +51,6 @@ public class RenameGroupRepoGremlin implements RenameGroupRepo { .property(VertexProperty.Cardinality.single, VertexPropertyNames.NODE_ID, newNodeId) .property(VertexProperty.Cardinality.single, VertexPropertyNames.NAME, newGroupName); gremlinConnector.updateVertex(traversal); + return new HashSet<>(impactedUsers); } } diff --git a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/retrievegroup/RetrieveGroupRepoGremlin.java b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/retrievegroup/RetrieveGroupRepoGremlin.java index 07685d75fc12b9df82cfbea4b50d608df9de8af5..3594a4ed533d5455865a8df15aba19740feb5d2e 100644 --- a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/retrievegroup/RetrieveGroupRepoGremlin.java +++ b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/retrievegroup/RetrieveGroupRepoGremlin.java @@ -24,6 +24,7 @@ import org.springframework.stereotype.Repository; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -132,7 +133,17 @@ public class RetrieveGroupRepoGremlin implements RetrieveGroupRepo { @Override public ChildrenTreeDto loadAllChildrenUsers(EntityNode node) { - return ChildrenTreeDto.builder().childrenUserIds(new ArrayList<>()).build(); + if (node.isUser()) { + return ChildrenTreeDto.builder().childrenUserIds(Collections.singletonList(node.getNodeId())).build(); + } + Traversal traversal = gremlinConnector.getGraphTraversalSource().V() + .has(VertexPropertyNames.DATA_PARTITION_ID, node.getDataPartitionId()) + .has(VertexPropertyNames.NODE_ID, node.getNodeId()) + .emit(__.hasLabel(NodeType.USER.toString())) + .repeat(__.outE(EdgePropertyNames.CHILD_EDGE_LB).inV()); + List vertices = gremlinConnector.getVertices(traversal); + return ChildrenTreeDto.builder() + .childrenUserIds(vertices.stream().map(NodeVertex::getNodeId).distinct().collect(Collectors.toList())).build(); } public Set filterParentsByAppId(Set parentReferences, String partitionId, String appId) { diff --git a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/updateappids/UpdateAppIdsRepoGremlin.java b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/updateappids/UpdateAppIdsRepoGremlin.java index 1b82a99f5f72d74a6f3112ed8a89a89812697ff0..bdc008c243bfc50ada3e276be033c284db4eb050 100644 --- a/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/updateappids/UpdateAppIdsRepoGremlin.java +++ b/provider/entitlements-v2-azure/src/main/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/updateappids/UpdateAppIdsRepoGremlin.java @@ -10,29 +10,37 @@ import org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.connection.GremlinCo import org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.constant.VertexPropertyNames; import org.opengroup.osdu.entitlements.v2.logging.AuditLogger; import org.opengroup.osdu.entitlements.v2.model.EntityNode; +import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.opengroup.osdu.entitlements.v2.spi.updateappids.UpdateAppIdsRepo; import org.springframework.stereotype.Repository; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; import java.util.Set; @Repository @RequiredArgsConstructor public class UpdateAppIdsRepoGremlin implements UpdateAppIdsRepo { private final GremlinConnector gremlinConnector; + private final RetrieveGroupRepo retrieveGroupRepo; private final AuditLogger auditLogger; @Override - public void updateAppIds(EntityNode groupNode, Set appIds) { + public Set updateAppIds(EntityNode groupNode, Set appIds) { + Set impactedUsers; try { - executeUpdateAppIdsOperation(groupNode, appIds); + impactedUsers = executeUpdateAppIdsOperation(groupNode, appIds); auditLogger.updateAppIds(AuditStatus.SUCCESS, groupNode.getNodeId(), appIds); } catch (Exception e) { auditLogger.updateAppIds(AuditStatus.FAILURE, groupNode.getNodeId(), appIds); throw e; } + return impactedUsers; } - private void executeUpdateAppIdsOperation(EntityNode groupNode, Set appIds) { + private Set executeUpdateAppIdsOperation(EntityNode groupNode, Set appIds) { + List impactedUsers = retrieveGroupRepo.loadAllChildrenUsers(groupNode).getChildrenUserIds(); GraphTraversal traversal = gremlinConnector.getGraphTraversalSource().V() .has(VertexPropertyNames.NODE_ID, groupNode.getNodeId()) .has(VertexPropertyNames.DATA_PARTITION_ID, groupNode.getDataPartitionId()) @@ -40,5 +48,6 @@ public class UpdateAppIdsRepoGremlin implements UpdateAppIdsRepo { .barrier(); appIds.forEach(appId -> traversal.property(Cardinality.list, VertexPropertyNames.APP_ID, appId)); gremlinConnector.updateVertex(traversal); + return (impactedUsers == null) ? Collections.emptySet() : new HashSet<>(impactedUsers); } } diff --git a/provider/entitlements-v2-azure/src/main/resources/application.properties b/provider/entitlements-v2-azure/src/main/resources/application.properties index e0aaae8220ed2c98743241b8ec329c754667ce1a..41407b3680417ffe6efd466bb73b0158dbd46d00 100644 --- a/provider/entitlements-v2-azure/src/main/resources/application.properties +++ b/provider/entitlements-v2-azure/src/main/resources/application.properties @@ -55,3 +55,5 @@ redisson.lock.expiration=5000 cache.retry.max=15 cache.retry.interval=200 cache.retry.random.factor=0.1 +cache.flush.ttl.base=500 +cache.flush.ttl.jitter=1000 \ No newline at end of file diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/service/GroupCacheServiceAzureTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/service/GroupCacheServiceAzureTest.java index ccbc7439f29606600cac9357367b3853d5e85a3a..7291d6bbce415c351d2e2f0fef981f8d182e8a93 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/service/GroupCacheServiceAzureTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/service/GroupCacheServiceAzureTest.java @@ -8,6 +8,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.AdditionalAnswers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.stubbing.Answer; import org.opengroup.osdu.core.common.cache.RedisCache; @@ -34,6 +35,7 @@ import org.springframework.test.context.junit4.SpringRunner; import redis.embedded.RedisServer; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -42,10 +44,13 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import static org.awaitility.Awaitility.await; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; @@ -57,7 +62,9 @@ import static org.mockito.Mockito.when; "redisson.lock.expiration=5000", "cache.retry.max=15", "cache.retry.interval=200", - "cache.retry.random.factor=0.1"}) + "cache.retry.random.factor=0.1", + "cache.flush.ttl.base=500", + "cache.flush.ttl.jitter=1000"}) @RunWith(SpringRunner.class) public class GroupCacheServiceAzureTest { @TestConfiguration @@ -77,7 +84,8 @@ public class GroupCacheServiceAzureTest { private Set parents = new HashSet<>(); private ParentReferences parentReferences = new ParentReferences(); - private EntityNode requester; + private EntityNode requester1; + private EntityNode requester2; @MockBean private RetrieveGroupRepo retrieveGroupRepo; @@ -132,28 +140,32 @@ public class GroupCacheServiceAzureTest { parents.add(parent2); parentReferences.setParentReferencesOfUser(parents); - requester = EntityNode.createMemberNodeForNewUser("requesterId", "dp"); + requester1 = EntityNode.createMemberNodeForNewUser("requesterId1", "dp"); + requester2 = EntityNode.createMemberNodeForNewUser("requesterId2", "dp"); when(partitionCacheTtlService.getCacheTtlOfPartition("dp")).thenReturn(2000L); + when(partitionCacheTtlService.getCacheFlushTtlBaseOfPartition("dp")).thenReturn(500L); + when(partitionCacheTtlService.getCacheFlushTtlJitterOfPartition("dp")).thenReturn(1000L); + } @Test public void shouldGetAllParentsFromRepoForTheFirstTime() { - when(this.redisGroupCache.get("requesterId-dp")).thenReturn(null); - when(this.retrieveGroupRepo.loadAllParents(this.requester)).thenReturn(this.parentTreeDto); + when(this.redisGroupCache.get("requesterId1-dp")).thenReturn(null); + when(this.retrieveGroupRepo.loadAllParents(this.requester1)).thenReturn(this.parentTreeDto); when(this.parentTreeDto.getParentReferences()).thenReturn(this.parents); - Set result = this.sut.getFromPartitionCache("requesterId", "dp"); + Set result = this.sut.getFromPartitionCache("requesterId1", "dp"); assertEquals(this.parents, result); - verify(this.retrieveGroupRepo).loadAllParents(this.requester); - verify(this.redisGroupCache).put("requesterId-dp", 2000L, this.parentReferences); + verify(this.retrieveGroupRepo).loadAllParents(this.requester1); + verify(this.redisGroupCache).put("requesterId1-dp", 2000L, this.parentReferences); verify(this.metricService).sendMissesMetric(); } @Test public void shouldGetAllParentsFromCacheForTheSecondTime() { - when(this.redisGroupCache.get("requesterId-dp")).thenReturn(this.parentReferences); + when(this.redisGroupCache.get("requesterId1-dp")).thenReturn(this.parentReferences); - Set result = this.sut.getFromPartitionCache("requesterId", "dp"); + Set result = this.sut.getFromPartitionCache("requesterId1", "dp"); assertEquals(this.parents, result); verifyNoInteractions(this.retrieveGroupRepo); verify(this.metricService, times(1)).sendHitsMetric(); @@ -166,8 +178,8 @@ public class GroupCacheServiceAzureTest { cacheValues.add(null); } cacheValues.add(this.parentReferences); - when(this.redisGroupCache.get("requesterId-dp")).thenAnswer(AdditionalAnswers.returnsElementsOf(cacheValues)); - when(this.retrieveGroupRepo.loadAllParents(this.requester)).thenAnswer((Answer) invocationOnMock -> { + when(this.redisGroupCache.get("requesterId1-dp")).thenAnswer(AdditionalAnswers.returnsElementsOf(cacheValues)); + when(this.retrieveGroupRepo.loadAllParents(this.requester1)).thenAnswer((Answer) invocationOnMock -> { await().pollDelay(Duration.FIVE_SECONDS).until(() -> true); return parentTreeDto; }); @@ -178,14 +190,14 @@ public class GroupCacheServiceAzureTest { List>> tasks = new ArrayList<>(); for (int i = 0; i < threads; i++) { - Callable> task = () -> sut.getFromPartitionCache("requesterId", "dp"); + Callable> task = () -> sut.getFromPartitionCache("requesterId1", "dp"); tasks.add(task); } List>> responses = executor.invokeAll(tasks); executor.shutdown(); - verify(this.retrieveGroupRepo, times(1)).loadAllParents(this.requester); + verify(this.retrieveGroupRepo, times(1)).loadAllParents(this.requester1); responses.forEach(result -> { try { assertEquals(this.parents, result.get()); @@ -197,8 +209,8 @@ public class GroupCacheServiceAzureTest { @Test public void shouldThrowExceptionIfTimeout() throws InterruptedException { - when(this.redisGroupCache.get("requesterId-dp")).thenReturn(null); - when(this.retrieveGroupRepo.loadAllParents(this.requester)).thenAnswer((Answer) invocationOnMock -> { + when(this.redisGroupCache.get("requesterId1-dp")).thenReturn(null); + when(this.retrieveGroupRepo.loadAllParents(this.requester1)).thenAnswer((Answer) invocationOnMock -> { await().pollDelay(Duration.FIVE_SECONDS).until(() -> true); return parentTreeDto; }); @@ -209,14 +221,14 @@ public class GroupCacheServiceAzureTest { List>> tasks = new ArrayList<>(); for (int i = 0; i < threads; i++) { - Callable> task = () -> sut.getFromPartitionCache("requesterId", "dp"); + Callable> task = () -> sut.getFromPartitionCache("requesterId1", "dp"); tasks.add(task); } List>> responses = executor.invokeAll(tasks); executor.shutdown(); - verify(this.retrieveGroupRepo, times(1)).loadAllParents(this.requester); + verify(this.retrieveGroupRepo, times(1)).loadAllParents(this.requester1); assertEquals(1, responses.stream().filter(result -> { try { return this.parents.equals(result.get()); @@ -236,4 +248,43 @@ public class GroupCacheServiceAzureTest { return false; }).count()); } + + @Test + public void shouldRefreshListGroupCache() { + this.redisGroupCache.put("requesterId1-dp", 600000L, this.parentReferences); + this.redisGroupCache.put("requesterId2-dp", 600000L, this.parentReferences); + when(this.redisGroupCache.getTtl("requesterId1-dp")).thenReturn(600000L); + when(this.redisGroupCache.getTtl("requesterId2-dp")).thenReturn(600000L); + ArgumentCaptor ttlCapture1 = ArgumentCaptor.forClass(Long.class); + ArgumentCaptor ttlCapture2 = ArgumentCaptor.forClass(Long.class); + this.sut.refreshListGroupCache(new HashSet<>(Arrays.asList("requesterId1", "requesterId2")), "dp"); + + verify(this.redisGroupCache, times(1)).getTtl("requesterId1-dp"); + verify(this.redisGroupCache, times(1)).getTtl("requesterId2-dp"); + verify(this.redisGroupCache, times(1)).updateTtl(eq("requesterId1-dp"), ttlCapture1.capture()); + verify(this.redisGroupCache, times(1)).updateTtl(eq("requesterId2-dp"), ttlCapture2.capture()); + await().pollDelay(ttlCapture1.getValue(), TimeUnit.MILLISECONDS); + assertNull(this.redisGroupCache.get("requesterId1-dp")); + await().pollDelay(ttlCapture2.getValue(), TimeUnit.MILLISECONDS); + assertNull(this.redisGroupCache.get("requesterId2-dp")); + } + + @Test + public void shouldFlushListGroupCacheForUserIfRedisEntryExists() { + this.redisGroupCache.put("requesterId1-dp", 600000L, this.parentReferences); + when(this.redisGroupCache.getTtl("requesterId1-dp")).thenReturn(600000L); + ArgumentCaptor ttlCapture = ArgumentCaptor.forClass(Long.class); + this.sut.flushListGroupCacheForUser("requesterId1", "dp"); + verify(this.redisGroupCache, times(1)).getTtl("requesterId1-dp"); + verify(this.redisGroupCache, times(1)).updateTtl(eq("requesterId1-dp"), ttlCapture.capture()); + await().pollDelay(ttlCapture.getValue(), TimeUnit.MILLISECONDS); + assertNull(this.redisGroupCache.get("requesterId1-dp")); + } + + @Test + public void shouldDoNothingWhenFlushListGroupCacheAndRedisEntryDoesNotExist() { + this.sut.flushListGroupCacheForUser("requesterId1", "dp"); + verify(this.redisGroupCache, times(1)).getTtl("requesterId1-dp"); + assertNull(this.redisGroupCache.get("requesterId1-dp")); + } } diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/service/PartitionCacheTtlServiceTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/service/PartitionCacheTtlServiceTest.java index ff47d419e4bcb921d2139013a4a405e135108d7a..5433f6ea402c35e5618b94e0d8efe65b60860a7c 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/service/PartitionCacheTtlServiceTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/service/PartitionCacheTtlServiceTest.java @@ -58,6 +58,70 @@ public class PartitionCacheTtlServiceTest { Assert.assertEquals(new Long(3000L), actual); } + @Test + public void shouldReturnBaseTtlOfKnownDataPartitionId() { + ConcurrentMap baseTtlPerDataPartition = new ConcurrentHashMap<>(); + baseTtlPerDataPartition.put("common", 500L); + Whitebox.setInternalState(partitionCacheTtlService, "baseTtlPerDataPartition", baseTtlPerDataPartition); + + Long actual = partitionCacheTtlService.getCacheFlushTtlBaseOfPartition("common"); + + Assert.assertEquals(new Long(500L), actual); + } + + @Test + public void shouldReturnDefaultBaseTtlOfUnknownDataPartitionId() { + Whitebox.setInternalState(partitionCacheTtlService, "cacheFlushTtlBase", 500L); + + Long actual = partitionCacheTtlService.getCacheFlushTtlBaseOfPartition("common"); + + Assert.assertEquals(new Long(500L), actual); + } + + @Test + public void shouldReturnDefaultBaseTtlOfKnownDataPartitionIdIfGreaterThanMax() { + Whitebox.setInternalState(partitionCacheTtlService, "cacheFlushTtlBase", 500L); + ConcurrentMap baseTtlPerDataPartition = new ConcurrentHashMap<>(); + baseTtlPerDataPartition.put("common", 10001L); + Whitebox.setInternalState(partitionCacheTtlService, "baseTtlPerDataPartition", baseTtlPerDataPartition); + + Long actual = partitionCacheTtlService.getCacheFlushTtlBaseOfPartition("common"); + + Assert.assertEquals(new Long(500L), actual); + } + + @Test + public void shouldReturnJitterTtlOfKnownDataPartitionId() { + ConcurrentMap jitterTtlPerDataPartition = new ConcurrentHashMap<>(); + jitterTtlPerDataPartition.put("common", 1000L); + Whitebox.setInternalState(partitionCacheTtlService, "jitterTtlPerDataPartition", jitterTtlPerDataPartition); + + Long actual = partitionCacheTtlService.getCacheFlushTtlJitterOfPartition("common"); + + Assert.assertEquals(new Long(1000L), actual); + } + + @Test + public void shouldReturnBaseJitterTtlOfKnownDataPartitionIdIfGreaterThanMax() { + Whitebox.setInternalState(partitionCacheTtlService, "cacheFlushTtlJitter", 1000L); + ConcurrentMap jitterTtlPerDataPartition = new ConcurrentHashMap<>(); + jitterTtlPerDataPartition.put("common", 50001L); + Whitebox.setInternalState(partitionCacheTtlService, "jitterTtlPerDataPartition", jitterTtlPerDataPartition); + + Long actual = partitionCacheTtlService.getCacheFlushTtlJitterOfPartition("common"); + + Assert.assertEquals(new Long(1000L), actual); + } + + @Test + public void shouldReturnDefaultJitterTtlOfUnknownDataPartitionId() { + Whitebox.setInternalState(partitionCacheTtlService, "cacheFlushTtlJitter", 1000L); + + Long actual = partitionCacheTtlService.getCacheFlushTtlJitterOfPartition("common"); + + Assert.assertEquals(new Long(1000L), actual); + } + @Test public void shouldDoInitSuccessfully() throws Exception { Mockito.when(azureServicePrincipleTokenService.getAuthorizationToken()).thenReturn("token"); @@ -69,6 +133,8 @@ public class PartitionCacheTtlServiceTest { Property property = new Property(); property.setValue(ttl); properties.put("ent-cache-ttl", property); + properties.put("ent-cache-flush-ttl-min", property); + properties.put("ent-cache-flush-ttl-max", property); PartitionInfo partitionInfo = PartitionInfo.builder().properties(properties).build(); Mockito.when(provider.get("dp1")).thenReturn(partitionInfo); diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/addmember/AddMemberRepoGremlinTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/addmember/AddMemberRepoGremlinTest.java index f9f3da6d924124f5e718b987b8692bf874bc4a09..3c6d2269ece966f102c0592d1a4bf287e41a1edb 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/addmember/AddMemberRepoGremlinTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/addmember/AddMemberRepoGremlinTest.java @@ -14,17 +14,24 @@ import org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.connection.GremlinCo import org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.constant.EdgePropertyNames; import org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.constant.VertexPropertyNames; import org.opengroup.osdu.entitlements.v2.logging.AuditLogger; +import org.opengroup.osdu.entitlements.v2.model.ChildrenTreeDto; import org.opengroup.osdu.entitlements.v2.model.EntityNode; import org.opengroup.osdu.entitlements.v2.model.NodeType; import org.opengroup.osdu.entitlements.v2.model.Role; import org.opengroup.osdu.entitlements.v2.model.addmember.AddMemberRepoDto; import org.opengroup.osdu.entitlements.v2.spi.addmember.AddMemberRepo; +import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; +import java.util.Collections; import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.when; @SpringBootTest @RunWith(SpringRunner.class) @@ -42,6 +49,9 @@ public class AddMemberRepoGremlinTest { @MockBean private CacheConfig cacheConfig; + @MockBean + private RetrieveGroupRepo retrieveGroupRepo; + @After public void cleanup() { gremlinConnector.getGraphTraversalSource().V().drop().iterate(); @@ -57,8 +67,10 @@ public class AddMemberRepoGremlinTest { EntityNode member = EntityNode.builder().nodeId("memberId").dataPartitionId("dp").type(NodeType.USER).build(); AddMemberRepoDto addMemberRepoDto = AddMemberRepoDto.builder().memberNode(member) .partitionId("dp").role(Role.OWNER).build(); + ChildrenTreeDto childrenTreeDto = ChildrenTreeDto.builder().childrenUserIds(Collections.singletonList("memberId")).build(); + when(retrieveGroupRepo.loadAllChildrenUsers(member)).thenReturn(childrenTreeDto); - addMemberRepo.addMember(group, addMemberRepoDto); + Set impactedUsers = addMemberRepo.addMember(group, addMemberRepoDto); List members = graphTraversalSource.V() .has(VertexPropertyNames.NODE_ID, group.getNodeId()) @@ -67,6 +79,8 @@ public class AddMemberRepoGremlinTest { .inV() .toList(); Assert.assertEquals(1, members.size()); + Assert.assertEquals(1, impactedUsers.size()); + assertTrue(impactedUsers.contains("memberId")); Assert.assertEquals(member.getNodeId(), members.iterator().next().value(VertexPropertyNames.NODE_ID)); List edges = graphTraversalSource.V().has(VertexPropertyNames.NODE_ID, group.getNodeId()).bothE().toList(); Assert.assertEquals(2, edges.size()); diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/creategroup/CreateGroupRepoGremlinTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/creategroup/CreateGroupRepoGremlinTest.java index 637d99614b7d02bbaacc325e1c11313065ed622b..425244f9afe5ee04bf0d9290acea3de91639b4d9 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/creategroup/CreateGroupRepoGremlinTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/creategroup/CreateGroupRepoGremlinTest.java @@ -3,7 +3,6 @@ package org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.creategroup; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.junit.After; -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; @@ -30,6 +29,9 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + @SpringBootTest @RunWith(SpringRunner.class) public class CreateGroupRepoGremlinTest { @@ -67,13 +69,13 @@ public class CreateGroupRepoGremlinTest { .requesterNode(requesterNode) .partitionId("dp").build(); - createGroupRepo.createGroup(entityNode, createGroupRepoDto); + Set impactedUsers = createGroupRepo.createGroup(entityNode, createGroupRepoDto); Vertex vertex = gremlinConnector.getGraphTraversalSource().V().has(VertexPropertyNames.NODE_ID, "groupId").next(); - Assert.assertEquals("groupId", vertex.value(VertexPropertyNames.NODE_ID)); - Assert.assertEquals("name", vertex.value(VertexPropertyNames.NAME)); - Assert.assertEquals("desc", vertex.value(VertexPropertyNames.DESCRIPTION)); - Assert.assertEquals("dp", vertex.value(VertexPropertyNames.DATA_PARTITION_ID)); + assertEquals("groupId", vertex.value(VertexPropertyNames.NODE_ID)); + assertEquals("name", vertex.value(VertexPropertyNames.NAME)); + assertEquals("desc", vertex.value(VertexPropertyNames.DESCRIPTION)); + assertEquals("dp", vertex.value(VertexPropertyNames.DATA_PARTITION_ID)); Set appIds = new HashSet<>(); Iterator values = vertex.values(VertexPropertyNames.APP_ID); @@ -81,10 +83,12 @@ public class CreateGroupRepoGremlinTest { appIds.add(values.next()); } - Assert.assertEquals(new HashSet<>(Arrays.asList("App1", "App2")), appIds); + assertEquals(1, impactedUsers.size()); + assertTrue(impactedUsers.contains("test@test.com")); + assertEquals(new HashSet<>(Arrays.asList("App1", "App2")), appIds); ChildrenReference childrenReference = ChildrenReference.builder() .id("test@test.com").type(NodeType.USER).dataPartitionId("dp").role(Role.OWNER).build(); - Assert.assertTrue(retrieveGroupRepo.hasDirectChild(entityNode, childrenReference)); + assertTrue(retrieveGroupRepo.hasDirectChild(entityNode, childrenReference)); Mockito.verify(auditLogger).createGroup(AuditStatus.SUCCESS, "groupId"); } @@ -102,14 +106,14 @@ public class CreateGroupRepoGremlinTest { .dataRootGroupNode(dataRootGroupNode) .partitionId("dp").build(); - createGroupRepo.createGroup(entityNode, createGroupRepoDto); + Set impactedUsers = createGroupRepo.createGroup(entityNode, createGroupRepoDto); List vertices = gremlinConnector.getGraphTraversalSource().V().toList(); Vertex vertex = vertices.stream().filter(v -> "groupId".equals(v.value(VertexPropertyNames.NODE_ID))).findFirst().get(); - Assert.assertEquals("groupId", vertex.value(VertexPropertyNames.NODE_ID)); - Assert.assertEquals("name", vertex.value(VertexPropertyNames.NAME)); - Assert.assertEquals("desc", vertex.value(VertexPropertyNames.DESCRIPTION)); - Assert.assertEquals("dp", vertex.value(VertexPropertyNames.DATA_PARTITION_ID)); + assertEquals("groupId", vertex.value(VertexPropertyNames.NODE_ID)); + assertEquals("name", vertex.value(VertexPropertyNames.NAME)); + assertEquals("desc", vertex.value(VertexPropertyNames.DESCRIPTION)); + assertEquals("dp", vertex.value(VertexPropertyNames.DATA_PARTITION_ID)); Set appIds = new HashSet<>(); Iterator values = vertex.values(VertexPropertyNames.APP_ID); @@ -117,14 +121,16 @@ public class CreateGroupRepoGremlinTest { appIds.add(values.next()); } - Assert.assertEquals(new HashSet<>(Arrays.asList("App1", "App2")), appIds); + assertEquals(1, impactedUsers.size()); + assertTrue(impactedUsers.contains("test@test.com")); + assertEquals(new HashSet<>(Arrays.asList("App1", "App2")), appIds); ChildrenReference childrenReference = ChildrenReference.builder() .id("test@test.com").type(NodeType.USER).dataPartitionId("dp").role(Role.OWNER).build(); - Assert.assertTrue(retrieveGroupRepo.hasDirectChild(entityNode, childrenReference)); + assertTrue(retrieveGroupRepo.hasDirectChild(entityNode, childrenReference)); ChildrenReference childrenReferenceOfDataGroup = ChildrenReference.builder() .id(dataRootGroupNode.getNodeId()).type(dataRootGroupNode.getType()) .dataPartitionId(dataRootGroupNode.getDataPartitionId()).role(Role.MEMBER).build(); - Assert.assertTrue(retrieveGroupRepo.hasDirectChild(entityNode, childrenReferenceOfDataGroup)); + assertTrue(retrieveGroupRepo.hasDirectChild(entityNode, childrenReferenceOfDataGroup)); Mockito.verify(auditLogger).createGroup(AuditStatus.SUCCESS, "groupId"); } } diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/deletegroup/DeleteGroupRepoGremlinTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/deletegroup/DeleteGroupRepoGremlinTest.java index f943900c56052521cbfc813a19ac77f19c7cd79e..a2824a78376b0a5f7a2387f0b3fdd3fa23aa6464 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/deletegroup/DeleteGroupRepoGremlinTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/deletegroup/DeleteGroupRepoGremlinTest.java @@ -16,11 +16,14 @@ import org.opengroup.osdu.entitlements.v2.model.NodeType; import org.opengroup.osdu.entitlements.v2.model.Role; import org.opengroup.osdu.entitlements.v2.model.addmember.AddMemberRepoDto; import org.opengroup.osdu.entitlements.v2.spi.deletegroup.DeleteGroupRepo; +import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; +import java.util.Set; + @SpringBootTest @RunWith(SpringRunner.class) public class DeleteGroupRepoGremlinTest { @@ -31,6 +34,9 @@ public class DeleteGroupRepoGremlinTest { @Autowired private GremlinConnector gremlinConnector; + @Autowired + private RetrieveGroupRepo retrieveGroupRepo; + @Autowired private AddMemberRepoGremlin addMemberRepoGremlin; @@ -57,11 +63,13 @@ public class DeleteGroupRepoGremlinTest { AddMemberRepoDto addUserMemberRepoDto = AddMemberRepoDto.builder().memberNode(userNode).role(Role.MEMBER).partitionId("dp").build(); addMemberRepoGremlin.addMember(groupMemberNode, addUserMemberRepoDto); - deleteGroupRepo.deleteGroup(groupMemberNode); + Set impactedUsers = deleteGroupRepo.deleteGroup(groupMemberNode); Assert.assertFalse(gremlinConnector.getGraphTraversalSource().V().has(VertexPropertyNames.NODE_ID, "groupMemberId").hasNext()); Assert.assertTrue(gremlinConnector.getGraphTraversalSource().E().toList().isEmpty()); Mockito.verify(auditLogger).deleteGroup(AuditStatus.SUCCESS, "groupMemberId"); + Assert.assertEquals(1, impactedUsers.size()); + Assert.assertTrue(impactedUsers.contains("userId")); } private void createGroup(String nodeId) { diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/removemember/RemoveMemberRepoGremlinTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/removemember/RemoveMemberRepoGremlinTest.java index 1969aef0820aad71606525c6fcedc0baf2fa162b..de9e380689320493c6ed9869b30ae1a35cdb5444 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/removemember/RemoveMemberRepoGremlinTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/removemember/RemoveMemberRepoGremlinTest.java @@ -24,6 +24,8 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; +import java.util.Set; + @SpringBootTest @RunWith(SpringRunner.class) public class RemoveMemberRepoGremlinTest { @@ -72,8 +74,10 @@ public class RemoveMemberRepoGremlinTest { addMemberRepoGremlin.addMember(groupNode, addMemberRepoDto); Assert.assertTrue(retrieveGroupRepo.hasDirectChild(groupNode, childrenReference)); - removeMemberRepoGremlin.removeMember(groupNode, memberNode, RemoveMemberServiceDto.builder().build()); + Set impactedUsers = removeMemberRepoGremlin.removeMember(groupNode, memberNode, RemoveMemberServiceDto.builder().build()); + Assert.assertEquals(1, impactedUsers.size()); + Assert.assertTrue(impactedUsers.contains("userId")); Assert.assertFalse(retrieveGroupRepo.hasDirectChild(groupNode, childrenReference)); Assert.assertTrue(graphTraversalSource.E().toList().isEmpty()); Mockito.verify(auditLogger).removeMember(AuditStatus.SUCCESS, "groupId", "userId", null); diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/renamegroup/RenameGroupRepoGremlinTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/renamegroup/RenameGroupRepoGremlinTest.java index c1a89691f197860c52ffba31f6cbb7f6ead81d09..26d202c906c1f43f2e5600b31f2b4cd8d5c8100e 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/renamegroup/RenameGroupRepoGremlinTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/renamegroup/RenameGroupRepoGremlinTest.java @@ -23,6 +23,7 @@ import org.opengroup.osdu.entitlements.v2.model.NodeType; import org.opengroup.osdu.entitlements.v2.model.ParentReference; import org.opengroup.osdu.entitlements.v2.model.Role; import org.opengroup.osdu.entitlements.v2.spi.renamegroup.RenameGroupRepo; +import org.opengroup.osdu.entitlements.v2.spi.retrievegroup.RetrieveGroupRepo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -48,6 +49,8 @@ public class RenameGroupRepoGremlinTest { @Autowired private RenameGroupRepo renameGroupRepo; @Autowired + private RetrieveGroupRepo retrieveGroupRepo; + @Autowired private GremlinConnector gremlinConnector; @Autowired private VertexUtilService vertexUtilService; @@ -94,8 +97,10 @@ public class RenameGroupRepoGremlinTest { .build(); Set impactedUsers = renameGroupRepo.run(groupNode, "users.y"); - // TODO: 589276 Check impacted users when the logic will be implemented. - // Assert.assertEquals(new HashSet<>(), impactedUsers); + + Assert.assertEquals(2, impactedUsers.size()); + Assert.assertTrue(impactedUsers.contains("users.owner@dp.contoso.com")); + Assert.assertTrue(impactedUsers.contains("users.member@dp.contoso.com")); Assert.assertFalse(graphTraversalSource.V().has(VertexPropertyNames.NODE_ID, "users.x" + "@" + TEST_DOMAIN) .has(VertexPropertyNames.DATA_PARTITION_ID, TEST_PARTITION_ID) .hasNext()); @@ -201,8 +206,9 @@ public class RenameGroupRepoGremlinTest { .description("") .build(); Set impactedUsers = renameGroupRepo.run(groupNode, "users.z"); - // TODO: 589276 Check impacted users when the logic will be implemented. - // Assert.assertEquals(new HashSet<>(), impactedUsers); + + Assert.assertEquals(1, impactedUsers.size()); + Assert.assertTrue(impactedUsers.contains("member@xxx.com")); Assert.assertFalse(graphTraversalSource.V().has(VertexPropertyNames.NODE_ID, "users.x@dp.contoso.com") .has(VertexPropertyNames.DATA_PARTITION_ID, "dp") .hasNext()); diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/retrievegroup/RetrieveGroupRepoGremlinTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/retrievegroup/RetrieveGroupRepoGremlinTest.java index c9da229ad34e693e9a4ae53de75367999939b438..e0002934966eb51b702a12c88e83abf490c364a7 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/retrievegroup/RetrieveGroupRepoGremlinTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/retrievegroup/RetrieveGroupRepoGremlinTest.java @@ -15,6 +15,7 @@ import org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.constant.EdgePropert import org.opengroup.osdu.entitlements.v2.azure.spi.gremlin.constant.VertexPropertyNames; import org.opengroup.osdu.entitlements.v2.logging.AuditLogger; import org.opengroup.osdu.entitlements.v2.model.ChildrenReference; +import org.opengroup.osdu.entitlements.v2.model.ChildrenTreeDto; import org.opengroup.osdu.entitlements.v2.model.EntityNode; import org.opengroup.osdu.entitlements.v2.model.NodeType; import org.opengroup.osdu.entitlements.v2.model.ParentReference; @@ -449,6 +450,129 @@ public class RetrieveGroupRepoGremlinTest { List member = retrieveGroupRepo.loadDirectParents("dp", "member@xxx.com"); Assert.assertEquals(2, member.size()); } + @Test + public void shouldReturnItSelfIfNoChildrenWhenLoadAllChildrenUsers() { + EntityNode groupNode = EntityNode.createMemberNodeForNewUser("member@xxx.com", "dp"); + ChildrenTreeDto childrenUsers = retrieveGroupRepo.loadAllChildrenUsers(groupNode); + Assert.assertEquals(1, childrenUsers.getChildrenUserIds().size()); + } + + @Test + public void shouldReturnAllChildrenUsersWhenLoadAllChildrenUsers1() { + GraphTraversalSource graphTraversalSource = gremlinConnector.getGraphTraversalSource(); + graphTraversalSource.addV(NodeType.GROUP.toString()) + .property(VertexPropertyNames.NODE_ID, "users.x@dp.domain.com") + .property(VertexPropertyNames.NAME, "users.x") + .property(VertexPropertyNames.DESCRIPTION, "xxx") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp") + .next(); + graphTraversalSource.addV(NodeType.GROUP.toString()) + .property(VertexPropertyNames.NODE_ID, "users.y@dp.domain.com") + .property(VertexPropertyNames.NAME, "users.y") + .property(VertexPropertyNames.DESCRIPTION, "xxx") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp") + .next(); + graphTraversalSource.addV(NodeType.GROUP.toString()) + .property(VertexPropertyNames.NODE_ID, "data.x@dp.domain.com") + .property(VertexPropertyNames.NAME, "data.x") + .property(VertexPropertyNames.DESCRIPTION, "xxx") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp") + .next(); + graphTraversalSource.addV(NodeType.GROUP.toString()) + .property(VertexPropertyNames.NODE_ID, "data.y@dp.domain.com") + .property(VertexPropertyNames.NAME, "data.y") + .property(VertexPropertyNames.DESCRIPTION, "xxx") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp") + .next(); + graphTraversalSource.addV(NodeType.USER.toString()).property(VertexPropertyNames.NODE_ID, "member1@xxx.com") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp").next(); + graphTraversalSource.addV(NodeType.USER.toString()).property(VertexPropertyNames.NODE_ID, "member2@xxx.com") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp").next(); + + addMember("member1@xxx.com", NodeType.USER, "data.x@dp.domain.com", Role.MEMBER); + addMember("member2@xxx.com", NodeType.USER, "data.y@dp.domain.com", Role.MEMBER); + addMember("member2@xxx.com", NodeType.USER, "users.x@dp.domain.com", Role.OWNER); + addMember("data.y@dp.domain.com", NodeType.GROUP, "data.x@dp.domain.com", Role.MEMBER); + addMember("users.x@dp.domain.com", NodeType.GROUP, "data.y@dp.domain.com", Role.MEMBER); + addMember("users.y@dp.domain.com", NodeType.GROUP, "data.y@dp.domain.com", Role.MEMBER); + + EntityNode groupNode = EntityNode.createNodeFromGroupEmail("data.x@dp.domain.com"); + ChildrenTreeDto childrenUserDto = retrieveGroupRepo.loadAllChildrenUsers(groupNode); + Assert.assertEquals(2, childrenUserDto.getChildrenUserIds().size()); + Assert.assertTrue(childrenUserDto.getChildrenUserIds().containsAll(Arrays.asList("member1@xxx.com", "member2@xxx.com"))); + } + + /* + data.x@dp.domain.com + ^ + | + |-------------------------------|---------------------------| + data.y@dp.domain.com data.z@dp.domain.com member1@xxx.com + ^ ^----------- + |-------------------|---------------------| | +users.x@dp.domain.com users.y@dp.domain.com member2@xxx.com ----------- + ^ ^ + | |--------------| + ------------ member3@xxx.com member4@xxx.com + */ + @Test + public void shouldReturnAllChildrenUsersWhenLoadAllChildrenUsers2() { + GraphTraversalSource graphTraversalSource = gremlinConnector.getGraphTraversalSource(); + graphTraversalSource.addV(NodeType.GROUP.toString()) + .property(VertexPropertyNames.NODE_ID, "users.x@dp.domain.com") + .property(VertexPropertyNames.NAME, "users.x") + .property(VertexPropertyNames.DESCRIPTION, "xxx") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp") + .next(); + graphTraversalSource.addV(NodeType.GROUP.toString()) + .property(VertexPropertyNames.NODE_ID, "users.y@dp.domain.com") + .property(VertexPropertyNames.NAME, "users.y") + .property(VertexPropertyNames.DESCRIPTION, "xxx") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp") + .next(); + graphTraversalSource.addV(NodeType.GROUP.toString()) + .property(VertexPropertyNames.NODE_ID, "data.x@dp.domain.com") + .property(VertexPropertyNames.NAME, "data.x") + .property(VertexPropertyNames.DESCRIPTION, "xxx") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp") + .next(); + graphTraversalSource.addV(NodeType.GROUP.toString()) + .property(VertexPropertyNames.NODE_ID, "data.y@dp.domain.com") + .property(VertexPropertyNames.NAME, "data.y") + .property(VertexPropertyNames.DESCRIPTION, "xxx") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp") + .next(); + graphTraversalSource.addV(NodeType.GROUP.toString()) + .property(VertexPropertyNames.NODE_ID, "data.z@dp.domain.com") + .property(VertexPropertyNames.NAME, "data.z") + .property(VertexPropertyNames.DESCRIPTION, "xxx") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp") + .next(); + graphTraversalSource.addV(NodeType.USER.toString()).property(VertexPropertyNames.NODE_ID, "member1@xxx.com") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp").next(); + graphTraversalSource.addV(NodeType.USER.toString()).property(VertexPropertyNames.NODE_ID, "member2@xxx.com") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp").next(); + graphTraversalSource.addV(NodeType.USER.toString()).property(VertexPropertyNames.NODE_ID, "member3@xxx.com") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp").next(); + graphTraversalSource.addV(NodeType.USER.toString()).property(VertexPropertyNames.NODE_ID, "member4@xxx.com") + .property(VertexPropertyNames.DATA_PARTITION_ID, "dp").next(); + + addMember("member1@xxx.com", NodeType.USER, "data.x@dp.domain.com", Role.OWNER); + addMember("member2@xxx.com", NodeType.USER, "data.z@dp.domain.com", Role.OWNER); + addMember("member2@xxx.com", NodeType.USER, "data.y@dp.domain.com", Role.MEMBER); + addMember("member3@xxx.com", NodeType.USER, "users.x@dp.domain.com", Role.OWNER); + addMember("member3@xxx.com", NodeType.USER, "users.y@dp.domain.com", Role.MEMBER); + addMember("member4@xxx.com", NodeType.USER, "users.y@dp.domain.com", Role.OWNER); + addMember("data.y@dp.domain.com", NodeType.GROUP, "data.x@dp.domain.com", Role.MEMBER); + addMember("data.z@dp.domain.com", NodeType.GROUP, "data.x@dp.domain.com", Role.MEMBER); + addMember("users.x@dp.domain.com", NodeType.GROUP, "data.y@dp.domain.com", Role.MEMBER); + addMember("users.y@dp.domain.com", NodeType.GROUP, "data.y@dp.domain.com", Role.MEMBER); + + EntityNode groupNode = EntityNode.createNodeFromGroupEmail("data.x@dp.domain.com"); + ChildrenTreeDto childrenUsers = retrieveGroupRepo.loadAllChildrenUsers(groupNode); + Assert.assertEquals(4, childrenUsers.getChildrenUserIds().size()); + Assert.assertTrue(childrenUsers.getChildrenUserIds().containsAll(Arrays.asList("member1@xxx.com", "member2@xxx.com", "member3@xxx.com", "member4@xxx.com"))); + } @Test public void shouldFilterAccessibleParentReferencesWhenGivenValidAppId() { diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/updateappids/UpdateAppIdsRepoGremlinTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/updateappids/UpdateAppIdsRepoGremlinTest.java index f7bb0dc8444dc3fe6adc2bd2b3d04ed354db332b..a6868aff641934ed0e8d76f2dda8514300ebd1c0 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/updateappids/UpdateAppIdsRepoGremlinTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/spi/gremlin/updateappids/UpdateAppIdsRepoGremlinTest.java @@ -110,7 +110,7 @@ public class UpdateAppIdsRepoGremlinTest { allowedAppIds.add("testApp1"); allowedAppIds.add("testApp2"); - updateAppIdsRepo.updateAppIds(groupNode, allowedAppIds); + Set impactedUsers = updateAppIdsRepo.updateAppIds(groupNode, allowedAppIds); Set appIds = new HashSet<>(); Iterator values = graphTraversalSource.V().has(VertexPropertyNames.NODE_ID, "users.x@dp.contoso.com") @@ -121,6 +121,9 @@ public class UpdateAppIdsRepoGremlinTest { appIds.add(values.next()); } + Assert.assertEquals(2, impactedUsers.size()); + Assert.assertTrue(impactedUsers.contains("users.owner@dp.contoso.com")); + Assert.assertTrue(impactedUsers.contains("users.member@dp.contoso.com")); Assert.assertEquals(new HashSet<>(Arrays.asList("testApp1", "testApp2")), appIds); List usersYMembers = gremlinConnector.getGraphTraversalSource().V().has(VertexPropertyNames.NODE_ID, "users.x@dp.contoso.com") .outE(EdgePropertyNames.CHILD_EDGE_LB) @@ -200,7 +203,7 @@ public class UpdateAppIdsRepoGremlinTest { allowedAppIds.add("testApp1"); allowedAppIds.add("testApp2"); - updateAppIdsRepo.updateAppIds(groupNode, allowedAppIds); + Set impactedUsers = updateAppIdsRepo.updateAppIds(groupNode, allowedAppIds); Set appIds = new HashSet<>(); Iterator values = graphTraversalSource.V().has(VertexPropertyNames.NODE_ID, "users.x@dp.contoso.com") @@ -211,6 +214,8 @@ public class UpdateAppIdsRepoGremlinTest { appIds.add(values.next()); } + Assert.assertEquals(1, impactedUsers.size()); + Assert.assertTrue(impactedUsers.contains("member@xxx.com")); Assert.assertEquals(new HashSet<>(Arrays.asList("testApp1", "testApp2")), appIds); List members = gremlinConnector.getGraphTraversalSource().V().has(VertexPropertyNames.NODE_ID, "users.x@dp.contoso.com") .outE(EdgePropertyNames.CHILD_EDGE_LB) diff --git a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/workflow/CreateMembershipsWorkflowSinglePartitionTest.java b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/workflow/CreateMembershipsWorkflowSinglePartitionTest.java index 46233cd34a3e05a78cc7d2e387e72434d3c2913d..b3752c2d3577fca647d772b719c557f14f2c22c9 100644 --- a/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/workflow/CreateMembershipsWorkflowSinglePartitionTest.java +++ b/provider/entitlements-v2-azure/src/test/java/org/opengroup/osdu/entitlements/v2/azure/workflow/CreateMembershipsWorkflowSinglePartitionTest.java @@ -23,6 +23,7 @@ import org.opengroup.osdu.entitlements.v2.auth.AuthorizationService; import org.opengroup.osdu.entitlements.v2.azure.AzureAppProperties; import org.opengroup.osdu.entitlements.v2.azure.config.CacheConfig; import org.opengroup.osdu.entitlements.v2.azure.service.PartitionCacheTtlService; +import org.opengroup.osdu.entitlements.v2.azure.service.metrics.hitsnmisses.HitsNMissesMetricService; import org.opengroup.osdu.entitlements.v2.logging.AuditLogger; import org.opengroup.osdu.entitlements.v2.model.GroupType; import org.opengroup.osdu.entitlements.v2.model.ParentReference; @@ -34,7 +35,6 @@ import org.opengroup.osdu.entitlements.v2.model.listgroup.ListGroupResponseDto; import org.opengroup.osdu.entitlements.v2.model.listmember.ListMemberResponseDto; import org.opengroup.osdu.entitlements.v2.model.listmember.MemberDto; import org.opengroup.osdu.entitlements.v2.model.updategroup.UpdateGroupOperation; -import org.opengroup.osdu.entitlements.v2.azure.service.metrics.hitsnmisses.HitsNMissesMetricService; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; @@ -408,6 +408,25 @@ public class CreateMembershipsWorkflowSinglePartitionTest { "data.default.viewers@common.contoso.com", "users.myusers.operators@common.contoso.com"}, performListGroupRequestWithAppId(userA, audience)); + assertGroupsEquals(new String[]{ + "users@common.contoso.com", + "data.default.owners@common.contoso.com", + "data.default.viewers@common.contoso.com", + "users.myusers.operators@common.contoso.com"}, performListGroupsOnBehalfOfRequest(userA, "NONE", "test.com")); + + assertGroupsEquals(new String[]{ + "users@common.contoso.com", + "data.default.owners@common.contoso.com", + "data.default.viewers@common.contoso.com", + "users.myusers.operators@common.contoso.com", + "data.mydata1.operators@common.contoso.com"}, performListGroupsOnBehalfOfRequest(userA, "NONE", "App1")); + + assertGroupsEquals(new String[]{ + "users@common.contoso.com", + "data.default.owners@common.contoso.com", + "data.default.viewers@common.contoso.com", + "users.myusers.operators@common.contoso.com", + "data.mydata1.operators@common.contoso.com"}, performListGroupsOnBehalfOfRequest(userA, "NONE", "App2")); //update group metadata with audience performUpdateGroupRequest(Collections.singletonList(getUpdateAppIdsOperation(audience)), @@ -419,6 +438,13 @@ public class CreateMembershipsWorkflowSinglePartitionTest { "data.default.viewers@common.contoso.com", "data.mydata1.operators@common.contoso.com"}, performListGroupRequestWithAppId(userA, audience)); + assertGroupsEquals(new String[]{ + "users@common.contoso.com", + "users.myusers.operators@common.contoso.com", + "data.default.owners@common.contoso.com", + "data.default.viewers@common.contoso.com", + "data.mydata1.operators@common.contoso.com"}, performListGroupsOnBehalfOfRequest(userA, "NONE", "test.com")); + //update group metadata with empty list performUpdateGroupRequest(Collections.singletonList(getUpdateAppIdsOperation(Collections.emptyList())), "data.mydata1.operators@common.contoso.com", userA, audience); @@ -428,6 +454,13 @@ public class CreateMembershipsWorkflowSinglePartitionTest { "data.default.owners@common.contoso.com", "data.default.viewers@common.contoso.com", "data.mydata1.operators@common.contoso.com"}, performListGroupRequestWithAppId(userA, audience)); + + assertGroupsEquals(new String[]{ + "users@common.contoso.com", + "users.myusers.operators@common.contoso.com", + "data.default.owners@common.contoso.com", + "data.default.viewers@common.contoso.com", + "data.mydata1.operators@common.contoso.com"}, performListGroupsOnBehalfOfRequest(userA, "NONE", "test.com")); } private void testGroupUpdateApi() throws Exception { @@ -760,6 +793,25 @@ public class CreateMembershipsWorkflowSinglePartitionTest { return ListGroupResponseDto.builder().build(); } + private ListGroupResponseDto performListGroupsOnBehalfOfRequest(String memberId, String groupType, String appId) { + try { + ResultActions result = mockMvc.perform(get("/members/{member_email}/groups", memberId) + .contentType(MediaType.APPLICATION_JSON) + .characterEncoding(StandardCharsets.UTF_8.name()) + .header(DpsHeaders.AUTHORIZATION, "Bearer token") + .header(DpsHeaders.USER_ID, servicePrincipal) + .header(DpsHeaders.DATA_PARTITION_ID, "common") + .queryParam("type", groupType) + .queryParam("appid", appId)); + return objectMapper.readValue( + result.andExpect(status().isOk()).andReturn().getResponse().getContentAsString(), + ListGroupResponseDto.class); + } catch (Exception e) { + Assert.fail("Exception shouldn't take place here"); + } + return ListGroupResponseDto.builder().build(); + } + private ListMemberResponseDto performListMemberRequest(String groupEmail, String userId) { try { ResultActions result = mockMvc.perform(get("/groups/{group_email}/members", groupEmail) diff --git a/provider/entitlements-v2-azure/src/test/resources/application.properties b/provider/entitlements-v2-azure/src/test/resources/application.properties index 563db90570bd50390f604085d77210f85526274e..4ae313205c35d803c575c4426665a9e2abb6a9c7 100644 --- a/provider/entitlements-v2-azure/src/test/resources/application.properties +++ b/provider/entitlements-v2-azure/src/test/resources/application.properties @@ -35,4 +35,6 @@ redisson.lock.acquisition.timeout=10 redisson.lock.expiration=5000 cache.retry.max=15 cache.retry.interval=200 -cache.retry.random.factor=0.1 \ No newline at end of file +cache.retry.random.factor=0.1 +cache.flush.ttl.base=500 +cache.flush.ttl.jitter=1000 \ No newline at end of file diff --git a/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/service/GroupCacheServiceGcp.java b/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/service/GroupCacheServiceGcp.java index eaf20fad417bc6490c11dda5678ddf4a7b80c061..f02cb9b1ed2edd18d607b533f79113487f4d48b9 100644 --- a/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/service/GroupCacheServiceGcp.java +++ b/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/service/GroupCacheServiceGcp.java @@ -14,10 +14,11 @@ import java.util.Set; public class GroupCacheServiceGcp implements GroupCacheService { private final RetrieveGroupRepo retrieveGroupRepo; private final VmGroupCache vmGroupCache; + private static final String REDIS_KEY_FORMAT = "%s-%s"; @Override public Set getFromPartitionCache(String requesterId, String partitionId) { - String key = String.format("%s-%s", requesterId, partitionId); + String key = String.format(REDIS_KEY_FORMAT, requesterId, partitionId); Set result = vmGroupCache.getGroupCache(key); if (result == null) { EntityNode entityNode = EntityNode.createMemberNodeForNewUser(requesterId, partitionId); @@ -26,4 +27,19 @@ public class GroupCacheServiceGcp implements GroupCacheService { } return result; } + + @Override + public void refreshListGroupCache(Set userIds, String partitionId) { + for (String userId: userIds) { + String key = String.format(REDIS_KEY_FORMAT, userId, partitionId); + EntityNode entityNode = EntityNode.createMemberNodeForNewUser(userId, partitionId); + vmGroupCache.addGroupCache(key, retrieveGroupRepo.loadAllParents(entityNode).getParentReferences()); + } + } + + @Override + public void flushListGroupCacheForUser(String userId, String partitionId) { + String key = String.format(REDIS_KEY_FORMAT, userId, partitionId); + vmGroupCache.deleteGroupCache(key); + } } diff --git a/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/service/VmGroupCache.java b/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/service/VmGroupCache.java index 4da3ecac1182fd9a7ba2b2abbd6b48113d40b850..4eb2cb67ef4979e86ea197bba35d022517ccc532 100644 --- a/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/service/VmGroupCache.java +++ b/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/service/VmGroupCache.java @@ -20,4 +20,8 @@ public class VmGroupCache { public void addGroupCache(String requesterId, Set parents) { this.groupMap.put(requesterId, parents); } + + public void deleteGroupCache(String requesterId) { + this.groupMap.remove(requesterId); + } } diff --git a/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/spi/redis/updateappids/UpdateAppIdsRepoRedis.java b/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/spi/redis/updateappids/UpdateAppIdsRepoRedis.java index 99b5c40794d74dfeb29c83b8d2b569d800b52111..9d7d43834670b206672f655deabc40d3b40fa406 100644 --- a/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/spi/redis/updateappids/UpdateAppIdsRepoRedis.java +++ b/provider/entitlements-v2-gcp/src/main/java/org/opengroup/osdu/entitlements/v2/gcp/spi/redis/updateappids/UpdateAppIdsRepoRedis.java @@ -14,6 +14,7 @@ import org.opengroup.osdu.entitlements.v2.spi.updateappids.UpdateAppIdsRepo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; +import java.util.HashSet; import java.util.Set; @Repository @@ -35,7 +36,7 @@ public class UpdateAppIdsRepoRedis extends BaseRepo implements UpdateAppIdsRepo private Retry retry; @Override - public void updateAppIds(EntityNode groupNode, Set allowedAppIds) { + public Set updateAppIds(EntityNode groupNode, Set allowedAppIds) { log.info(String.format("Updating allowed appids for group %s to %s in redis", groupNode, allowedAppIds)); try { executeAppIdUpdate(groupNode, allowedAppIds); @@ -47,6 +48,7 @@ public class UpdateAppIdsRepoRedis extends BaseRepo implements UpdateAppIdsRepo executedCommands.clear(); } auditLogger.updateAppIds(AuditStatus.SUCCESS, groupNode.getNodeId(), allowedAppIds); + return new HashSet<>(); } private void executeAppIdUpdate(EntityNode groupEntityNode, Set appIds) { diff --git a/provider/entitlements-v2-gcp/src/test/java/org/opengroup/osdu/entitlements/v2/gcp/service/VmGroupCacheTest.java b/provider/entitlements-v2-gcp/src/test/java/org/opengroup/osdu/entitlements/v2/gcp/service/VmGroupCacheTest.java index 78a22f7d56bbe49f4a734c0bc691841ec418f5bb..f164fabd3ec4db662ac2743fe0ac4012ca9b91d8 100644 --- a/provider/entitlements-v2-gcp/src/test/java/org/opengroup/osdu/entitlements/v2/gcp/service/VmGroupCacheTest.java +++ b/provider/entitlements-v2-gcp/src/test/java/org/opengroup/osdu/entitlements/v2/gcp/service/VmGroupCacheTest.java @@ -45,6 +45,19 @@ public class VmGroupCacheTest { this.sut.addGroupCache(key, this.parents); Set secondResult = this.sut.getGroupCache(key); Assert.assertEquals(this.parents, secondResult); + } + + @Test + public void shouldDeleteKeyInCache() { + String key = "requesterId-dp"; + Set firstResult = this.sut.getGroupCache(key); + Assert.assertEquals(null, firstResult); + + this.sut.addGroupCache(key, this.parents); + Set secondResult = this.sut.getGroupCache(key); + Assert.assertEquals(this.parents, secondResult); + this.sut.deleteGroupCache(key); + Assert.assertNull(this.sut.getGroupCache(key)); } } diff --git a/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/CreateGroupTest.java b/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/CreateGroupTest.java index 3a1025a532f04df21f5120d04753c8106878e3c9..6ca0f8f9b2c0d4e2dffaa2f518cf075a23ac423e 100644 --- a/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/CreateGroupTest.java +++ b/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/CreateGroupTest.java @@ -8,12 +8,10 @@ import org.opengroup.osdu.entitlements.v2.acceptance.model.GroupItem; import org.opengroup.osdu.entitlements.v2.acceptance.model.Token; import org.opengroup.osdu.entitlements.v2.acceptance.model.request.RequestData; import org.opengroup.osdu.entitlements.v2.acceptance.model.response.ErrorResponse; -import org.opengroup.osdu.entitlements.v2.acceptance.model.response.ListGroupResponse; import org.opengroup.osdu.entitlements.v2.acceptance.util.ConfigurationService; import org.opengroup.osdu.entitlements.v2.acceptance.util.TokenService; public abstract class CreateGroupTest extends AcceptanceBaseTest { - private final ErrorResponse expectedConflictResponse = ErrorResponse.builder().code(409).reason("Conflict") .message("This group already exists").build(); @@ -31,8 +29,6 @@ public abstract class CreateGroupTest extends AcceptanceBaseTest { Assert.assertEquals(expectedGroup, entitlementsV2Service.createGroup(groupName, token.getValue())); - verifyGroupCanBeRetrieved(expectedGroup, token); - verifyConflictException(groupName, token.getValue()); } @@ -42,17 +38,6 @@ public abstract class CreateGroupTest extends AcceptanceBaseTest { entitlementsV2Service.deleteGroup(configurationService.getIdOfGroup("groupName-" + currentTime), tokenValue); } - private void verifyGroupCanBeRetrieved(GroupItem expectedGroup, Token token) throws Exception { - ListGroupResponse listGroupResponse = entitlementsV2Service.getGroups(token.getValue()); - Assert.assertEquals(token.getUserId(), listGroupResponse.getDesId()); - Assert.assertEquals(token.getUserId(), listGroupResponse.getMemberEmail()); - GroupItem groupItemFromGetGroups = listGroupResponse.getGroups() - .stream() - .filter(groupItem -> groupItem.getEmail().equals(configurationService.getIdOfGroup(expectedGroup.getName()))) - .findFirst().orElse(null); - Assert.assertEquals(expectedGroup, groupItemFromGetGroups); - } - private void verifyConflictException(String groupName, String token) throws Exception { RequestData requestData = RequestData.builder() .method("POST").dataPartitionId(configurationService.getTenantId()) diff --git a/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/ListGroupOnBehalfOfTest.java b/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/ListGroupOnBehalfOfTest.java index 2b2a5e0a7d7124efd0faf14496aec0d879c7e23c..a76da54309c04bdb7622770bd613913c982256b5 100644 --- a/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/ListGroupOnBehalfOfTest.java +++ b/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/ListGroupOnBehalfOfTest.java @@ -14,16 +14,12 @@ import org.opengroup.osdu.entitlements.v2.acceptance.util.TokenService; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; public abstract class ListGroupOnBehalfOfTest extends AcceptanceBaseTest { - private static final String TEST_APP_ID_1 = "test-app-id-1"; - private static final String TEST_APP_ID_2 = "test-app-id-2"; private final List groupsForFurtherDeletion; private final Token token; @@ -67,33 +63,6 @@ public abstract class ListGroupOnBehalfOfTest extends AcceptanceBaseTest { assertEquals(createdGroups.get(2).getEmail(), foundGroups.get(2)); } - @Test - public void shouldReturnAllFilteredGroupsByAppIdThatGivenMemberBelongsTo() throws Exception { - String memberEmail = "testMember@test.com"; - - List createdGroups = setup(memberEmail); - - GetGroupsRequestData getGroupsRequestData = GetGroupsRequestData.builder() - .memberEmail(memberEmail) - .type(GroupType.NONE) - .appId(TEST_APP_ID_1) - .build(); - ListGroupResponse groups = entitlementsV2Service.getGroups(getGroupsRequestData, token.getValue()); - - assertEquals(memberEmail.toLowerCase(), groups.getDesId()); - assertEquals(memberEmail.toLowerCase(), groups.getMemberEmail()); - List foundGroups = groups.getGroups().stream() - .filter(group -> group.getEmail().equals(createdGroups.get(0).getEmail()) - || group.getEmail().equals(createdGroups.get(1).getEmail()) - || group.getEmail().equals(createdGroups.get(2).getEmail())) - .map(GroupItem::getEmail) - .sorted(String::compareTo) - .collect(Collectors.toList()); - assertEquals(2, foundGroups.size()); - assertEquals(createdGroups.get(0).getEmail(), foundGroups.get(0)); - assertEquals(createdGroups.get(1).getEmail(), foundGroups.get(1)); - } - @Test public void shouldReturn400WhenGroupsTypeIsMissed() throws Exception { RequestData requestData = RequestData.builder() @@ -141,18 +110,10 @@ public abstract class ListGroupOnBehalfOfTest extends AcceptanceBaseTest { groups.add(group1Item); GroupItem group2Item = entitlementsV2Service.createGroup(group2Name, token.getValue()); - Set appIds2 = new HashSet() {{ - add(TEST_APP_ID_1); - }}; - entitlementsV2Service.updateGroupAppIds(group2Name, appIds2, token.getValue()); groupsForFurtherDeletion.add(group2Item.getEmail()); groups.add(group2Item); GroupItem group3Item = entitlementsV2Service.createGroup(group3Name, token.getValue()); - Set appIds3 = new HashSet() {{ - add(TEST_APP_ID_2); - }}; - entitlementsV2Service.updateGroupAppIds(group3Name, appIds3, token.getValue()); groupsForFurtherDeletion.add(group3Item.getEmail()); groups.add(group3Item); diff --git a/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/UpdateGroupTest.java b/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/UpdateGroupTest.java index 63a72874758905740ec498eb91d4cb68d339f06d..e81961b5f6fdb2d15030a6a6e68308aad3368243 100644 --- a/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/UpdateGroupTest.java +++ b/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/UpdateGroupTest.java @@ -31,22 +31,13 @@ public abstract class UpdateGroupTest extends AcceptanceBaseTest { String newGroupName = "newGroupName-" + currentTime; entitlementsV2Service.createGroup(oldGroupName, token.getValue()); - GroupItem newGroupItem = GroupItem.builder().name(newGroupName.toLowerCase()) - .description("desc") - .email(configurationService.getIdOfGroup(newGroupName)).build(); ClientResponse response = httpClientService.send(getRenameGroupRequestData(oldGroupName, newGroupName, token.getValue())); UpdateGroupResponse updateGroupResponse = new Gson().fromJson(response.getEntity(String.class), UpdateGroupResponse.class); Assert.assertEquals(200, response.getStatus()); Assert.assertEquals(newGroupName.toLowerCase(), updateGroupResponse.getName()); Assert.assertEquals(configurationService.getIdOfGroup(newGroupName).toLowerCase(), updateGroupResponse.getEmail()); - - ListGroupResponse listGroupResponse = entitlementsV2Service.getGroups(token.getValue()); - GroupItem groupItemFromGetGroups = listGroupResponse.getGroups() - .stream() - .filter(groupItem -> groupItem.getEmail().equals(configurationService.getIdOfGroup(newGroupName))) - .findFirst().orElse(null); - Assert.assertEquals(newGroupItem, groupItemFromGetGroups); + Assert.assertEquals(newGroupName.toLowerCase(), updateGroupResponse.getName().toLowerCase()); } @Test diff --git a/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/util/EntitlementsV2Service.java b/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/util/EntitlementsV2Service.java index f161ddf49ae6a72518e2d72d14943fd273909166..7987b6d0c0afc19fef8d1bc1932240f6a673093e 100644 --- a/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/util/EntitlementsV2Service.java +++ b/testing/entitlements-v2-test-core/src/main/java/org/opengroup/osdu/entitlements/v2/acceptance/util/EntitlementsV2Service.java @@ -137,22 +137,4 @@ public class EntitlementsV2Service { Assert.assertTrue(204 == response.getStatus() || 404 == response.getStatus()); return response; } - - public ClientResponse updateGroupAppIds(String groupName, Set newAppIds, String token) throws Exception { - UpdateGroupRequestData requestBody = UpdateGroupRequestData.builder() - .op("replace") - .path("/appIds") - .value(new ArrayList<>(newAppIds)).build(); - - RequestData requestData = RequestData.builder() - .method("PATCH") - .relativePath("groups/" + configurationService.getIdOfGroup(groupName)) - .dataPartitionId(configurationService.getTenantId()) - .token(token) - .body(gson.toJson(Collections.singletonList(requestBody))).build(); - - ClientResponse response = httpClientService.send(requestData); - Assert.assertEquals(200, response.getStatus()); - return response; - } }