From d5adc8a95ec5667d2d077955e3437ce42939ff7a Mon Sep 17 00:00:00 2001 From: Azizbek <113523904+azizbekxm@users.noreply.github.com> Date: Mon, 10 Jul 2023 17:54:59 +0500 Subject: [PATCH] [MODCON - 73] - Test simultaneous create tenant requests and apply improvements found after automated pipeline work --- .../client/SyncPrimaryAffiliationClient.java | 7 +- .../controller/TenantController.java | 18 ++--- .../SyncPrimaryAffiliationService.java | 14 ++-- .../SyncPrimaryAffiliationServiceImpl.java | 67 ++++++------------- .../service/impl/TenantServiceImpl.java | 2 +- .../service/impl/UserServiceImpl.java | 1 + src/main/resources/swagger.api/tenants.yaml | 9 +++ .../controller/TenantControllerTest.java | 2 +- ...SyncPrimaryAffiliationServiceImplTest.java | 5 +- 9 files changed, 56 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/folio/consortia/client/SyncPrimaryAffiliationClient.java b/src/main/java/org/folio/consortia/client/SyncPrimaryAffiliationClient.java index 6d91ef57..da24d280 100644 --- a/src/main/java/org/folio/consortia/client/SyncPrimaryAffiliationClient.java +++ b/src/main/java/org/folio/consortia/client/SyncPrimaryAffiliationClient.java @@ -7,14 +7,17 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "consortia", configuration = FeignClientConfiguration.class) public interface SyncPrimaryAffiliationClient { @PostMapping(value = "/{consortiumId}/tenants/{tenantId}/sync-primary-affiliations") - void syncPrimaryAffiliations(@PathVariable("consortiumId") String consortiumId, @PathVariable("tenantId") String tenantId); + void syncPrimaryAffiliations(@PathVariable("consortiumId") String consortiumId, @PathVariable("tenantId") String tenantId, + @RequestParam("centralTenantId") String centralTenantId); @PostMapping(value = "/{consortiumId}/tenants/{tenantId}/create-primary-affiliations", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) SyncPrimaryAffiliationBody savePrimaryAffiliations(@RequestBody SyncPrimaryAffiliationBody syncPrimaryAffiliationBody, - @PathVariable("consortiumId") String consortiumId, @PathVariable("tenantId") String tenantId); + @PathVariable("consortiumId") String consortiumId, @PathVariable("tenantId") String tenantId, + @RequestParam("centralTenantId") String centralTenantId); } diff --git a/src/main/java/org/folio/consortia/controller/TenantController.java b/src/main/java/org/folio/consortia/controller/TenantController.java index ed94ba85..59239fb9 100644 --- a/src/main/java/org/folio/consortia/controller/TenantController.java +++ b/src/main/java/org/folio/consortia/controller/TenantController.java @@ -14,9 +14,8 @@ import org.folio.consortia.rest.resource.TenantsApi; import org.folio.consortia.service.SyncPrimaryAffiliationService; import org.folio.consortia.service.TenantService; -import org.folio.spring.DefaultFolioExecutionContext; import org.folio.spring.FolioExecutionContext; -import org.folio.spring.scope.FolioExecutionContextSetter; +import org.jetbrains.annotations.NotNull; import org.springframework.core.task.TaskExecutor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -57,23 +56,18 @@ public ResponseEntity deleteTenantById(UUID consortiumId, String tenantId) } @Override - public ResponseEntity syncPrimaryAffiliations(UUID consortiumId, String tenantId) { -// var context = prepareContextForTenant("diku", folioExecutionContext.getFolioModuleMetadata(), folioExecutionContext); + public ResponseEntity syncPrimaryAffiliations(UUID consortiumId, String tenantId, @NotNull String centralTenantId) { asyncTaskExecutor.execute(getRunnableWithCurrentFolioContext( - () -> syncPrimaryAffiliationService.syncPrimaryAffiliations(consortiumId, tenantId))); + () -> syncPrimaryAffiliationService.syncPrimaryAffiliations(consortiumId, tenantId, centralTenantId))); return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); } @Override - public ResponseEntity createPrimaryAffiliations(UUID consortiumId, String tenantId, + public ResponseEntity createPrimaryAffiliations(UUID consortiumId, String tenantId, @NotNull String centralTenantId, SyncPrimaryAffiliationBody syncPrimaryAffiliationBody) { -// try (var comtext = new FolioExecutionContextSetter(prepareContextForTenant("diku", folioExecutionContext.getFolioModuleMetadata(), folioExecutionContext))) { -// syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, syncPrimaryAffiliationBody); -// } - var context = prepareContextForTenant("diku", folioExecutionContext.getFolioModuleMetadata(), folioExecutionContext); - + var context = prepareContextForTenant(centralTenantId, folioExecutionContext.getFolioModuleMetadata(), folioExecutionContext); asyncTaskExecutor.execute(getRunnableWithFolioContext(context, - () -> syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, syncPrimaryAffiliationBody))); + () -> syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, centralTenantId, syncPrimaryAffiliationBody))); return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); } } diff --git a/src/main/java/org/folio/consortia/service/SyncPrimaryAffiliationService.java b/src/main/java/org/folio/consortia/service/SyncPrimaryAffiliationService.java index 6fa4a239..970ef9bb 100644 --- a/src/main/java/org/folio/consortia/service/SyncPrimaryAffiliationService.java +++ b/src/main/java/org/folio/consortia/service/SyncPrimaryAffiliationService.java @@ -5,14 +5,20 @@ import java.util.UUID; public interface SyncPrimaryAffiliationService { - void syncPrimaryAffiliations(UUID consortiumId, String syncPrimaryAffiliationBody); + /** + * Sync primary affiliation for user + * @param consortiumId - consortium unique identifier + * @param centralTenantId - central tenant unique identifier + * @param syncPrimaryAffiliationBody - consortia tenant record + */ + void syncPrimaryAffiliations(UUID consortiumId, String centralTenantId, String syncPrimaryAffiliationBody); /** - * Create primary affiliation for user - * + * Create affiliations between central tenant and user + * primary affiliation between local tenant and its user * @param consortiumId - consortium unique identifier * @param syncPrimaryAffiliationBody - consortia tenant record */ - void createPrimaryUserAffiliations(UUID consortiumId, SyncPrimaryAffiliationBody syncPrimaryAffiliationBody); + void createPrimaryUserAffiliations(UUID consortiumId, String centralTenantId, SyncPrimaryAffiliationBody syncPrimaryAffiliationBody); } diff --git a/src/main/java/org/folio/consortia/service/impl/SyncPrimaryAffiliationServiceImpl.java b/src/main/java/org/folio/consortia/service/impl/SyncPrimaryAffiliationServiceImpl.java index f2b57309..a88bc7a6 100644 --- a/src/main/java/org/folio/consortia/service/impl/SyncPrimaryAffiliationServiceImpl.java +++ b/src/main/java/org/folio/consortia/service/impl/SyncPrimaryAffiliationServiceImpl.java @@ -1,7 +1,5 @@ package org.folio.consortia.service.impl; -import static org.folio.consortia.utils.TenantContextUtils.prepareContextForTenant; - import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -10,7 +8,6 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.folio.consortia.client.SyncPrimaryAffiliationClient; -import org.folio.consortia.config.FolioExecutionContextHelper; import org.folio.consortia.config.kafka.KafkaService; import org.folio.consortia.domain.dto.PrimaryAffiliationEvent; import org.folio.consortia.domain.dto.SyncPrimaryAffiliationBody; @@ -20,17 +17,12 @@ import org.folio.consortia.domain.entity.TenantEntity; import org.folio.consortia.domain.entity.UserTenantEntity; import org.folio.consortia.repository.UserTenantRepository; -import org.folio.consortia.service.ConsortiaConfigurationService; import org.folio.consortia.service.SyncPrimaryAffiliationService; import org.folio.consortia.service.TenantService; import org.folio.consortia.service.UserService; import org.folio.consortia.service.UserTenantService; -import org.folio.spring.FolioExecutionContext; -import org.folio.spring.FolioModuleMetadata; -import org.folio.spring.scope.FolioExecutionContextSetter; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import com.fasterxml.jackson.databind.ObjectMapper; @@ -47,17 +39,12 @@ public class SyncPrimaryAffiliationServiceImpl implements SyncPrimaryAffiliation private final UserTenantService userTenantService; private final TenantService tenantService; private final UserTenantRepository userTenantRepository; - private final ConsortiaConfigurationService consortiaConfigurationService; - private final FolioModuleMetadata folioModuleMetadata; - private final FolioExecutionContext folioExecutionContext; - private final FolioExecutionContextHelper contextHelper; private final ObjectMapper objectMapper = new ObjectMapper(); private final KafkaService kafkaService; private final SyncPrimaryAffiliationClient syncPrimaryAffiliationClient; @Override -// @Async("asyncTaskExecutor") - public void syncPrimaryAffiliations(UUID consortiumId, String tenantId) { + public void syncPrimaryAffiliations(UUID consortiumId, String tenantId, String centralTenantId) { log.info("Start syncing user primary affiliations for tenant {}", tenantId); List users = new ArrayList<>(); try { @@ -67,7 +54,7 @@ public void syncPrimaryAffiliations(UUID consortiumId, String tenantId) { } if (CollectionUtils.isNotEmpty(users)) { SyncPrimaryAffiliationBody spab = buildSyncPrimaryAffiliationBody(tenantId, users); - syncPrimaryAffiliationClient.savePrimaryAffiliations(spab, consortiumId.toString(), tenantId); + syncPrimaryAffiliationClient.savePrimaryAffiliations(spab, consortiumId.toString(), tenantId, centralTenantId); } } @@ -81,44 +68,30 @@ private SyncPrimaryAffiliationBody buildSyncPrimaryAffiliationBody(String tenant } @Override -// @Async("asyncTaskExecutor") - public void createPrimaryUserAffiliations(UUID consortiumId, SyncPrimaryAffiliationBody syncPrimaryAffiliationBody) { -// FolioExecutionContext currentTenantContext = (FolioExecutionContext) folioExecutionContext.getInstance(); + public void createPrimaryUserAffiliations(UUID consortiumId, String centralTenantId, + SyncPrimaryAffiliationBody syncPrimaryAffiliationBody) { log.info("Start creating user primary affiliation for tenant {}", syncPrimaryAffiliationBody.getTenantId()); var tenantId = syncPrimaryAffiliationBody.getTenantId(); var userList = syncPrimaryAffiliationBody.getUsers(); - var centralTenantId = consortiaConfigurationService.getCentralTenantId(tenantId); -// try (var context = new FolioExecutionContextSetter(prepareContextForTenant(centralTenantId, folioModuleMetadata, currentTenantContext))) { - TenantEntity tenantEntity = tenantService.getByTenantId(tenantId); - IntStream.range(0, userList.size()) - .sequential() - .forEach(idx -> { - var user = userList.get(idx); - log.info("Processing users: {} of {}", idx + 1, userList.size()); + TenantEntity tenantEntity = tenantService.getByTenantId(tenantId); + IntStream.range(0, userList.size()).sequential().forEach(idx -> { + var user = userList.get(idx); + log.info("Processing users: {} of {}", idx + 1, userList.size()); + Page userTenantPage = userTenantRepository.findByUserId(UUID.fromString(user.getId()), PageRequest.of(0, 1)); - // context changes in every iteration and folioExecutionContext become an empty, so we should set saved context again. -// try (var context2 = new FolioExecutionContextSetter(prepareContextForTenant(centralTenantId, folioModuleMetadata, currentTenantContext))) { - Page userTenantPage = userTenantRepository.findByUserId(UUID.fromString(user.getId()), PageRequest.of(0, 1)); - if (userTenantPage.getTotalElements() > 0) { - log.info("Primary affiliation already exists for tenant/user: {}/{}", tenantId, user.getUsername()); - } else { - userTenantService.createPrimaryUserTenantAffiliation(consortiumId, tenantEntity, user.getId(), user.getUsername()); - if (ObjectUtils.notEqual(centralTenantId, tenantEntity.getId())) { - userTenantService.save(consortiumId, createUserTenant(centralTenantId, user), true); - } - // context changes in userTenantService.save(), so we should set saved context again. -// try (var context3 = new FolioExecutionContextSetter(prepareContextForTenant(centralTenantId, folioModuleMetadata, currentTenantContext))) { - sendCreatePrimaryAffiliationEvent(tenantEntity, user); -// } - } -// } + if (userTenantPage.getTotalElements() > 0) { + log.info("Primary affiliation already exists for tenant/user: {}/{}", tenantId, user.getUsername()); + } else { + userTenantService.createPrimaryUserTenantAffiliation(consortiumId, tenantEntity, user.getId(), user.getUsername()); + if (ObjectUtils.notEqual(centralTenantId, tenantEntity.getId())) { + userTenantService.save(consortiumId, createUserTenant(centralTenantId, user), true); + } + sendCreatePrimaryAffiliationEvent(tenantEntity, user); + } - }); - log.info("Successfully created primary affiliations for tenant {}", tenantId); -// } catch (Exception e) { -// log.error("Failed to create primary affiliations for tenant {}", tenantId, e); -// } + }); + log.info("Successfully created primary affiliations for tenant {}", tenantId); } @SneakyThrows diff --git a/src/main/java/org/folio/consortia/service/impl/TenantServiceImpl.java b/src/main/java/org/folio/consortia/service/impl/TenantServiceImpl.java index 195a454a..d4aefe16 100644 --- a/src/main/java/org/folio/consortia/service/impl/TenantServiceImpl.java +++ b/src/main/java/org/folio/consortia/service/impl/TenantServiceImpl.java @@ -120,7 +120,7 @@ public Tenant save(UUID consortiumId, UUID adminUserId, Tenant tenantDto) { createUserTenantWithDummyUser(tenantDto.getId()); createShadowAdminUserWithPermissions(shadowAdminUser); //NOSONAR } - syncPrimaryAffiliationClient.syncPrimaryAffiliations(consortiumId.toString(), tenantDto.getId()); + syncPrimaryAffiliationClient.syncPrimaryAffiliations(consortiumId.toString(), tenantDto.getId(), centralTenantId); } log.info("save:: saved consortia configuration with centralTenantId={} by tenantId={} context", centralTenantId, tenantDto.getId()); return savedTenant; diff --git a/src/main/java/org/folio/consortia/service/impl/UserServiceImpl.java b/src/main/java/org/folio/consortia/service/impl/UserServiceImpl.java index 0278d527..14231eb2 100644 --- a/src/main/java/org/folio/consortia/service/impl/UserServiceImpl.java +++ b/src/main/java/org/folio/consortia/service/impl/UserServiceImpl.java @@ -82,6 +82,7 @@ public void deleteById(String userId) { public User prepareShadowUser(UUID userId, String tenantId) { try (var context = new FolioExecutionContextSetter(prepareContextForTenant(tenantId, folioModuleMetadata, (FolioExecutionContext) folioExecutionContext.getInstance()))) { + log.debug("prepareShadowUser:: Try to get user of tenant={} ", folioExecutionContext.getTenantId()); User user = new User(); User userOptional = usersClient.getUsersByUserId(userId.toString()); diff --git a/src/main/resources/swagger.api/tenants.yaml b/src/main/resources/swagger.api/tenants.yaml index 28f2d93b..1fbf4ba7 100644 --- a/src/main/resources/swagger.api/tenants.yaml +++ b/src/main/resources/swagger.api/tenants.yaml @@ -84,6 +84,7 @@ paths: parameters: - $ref: "#/components/parameters/consortiumId" - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/centralTenantId" responses: "201": $ref: "#/components/responses/NoContent" @@ -104,6 +105,7 @@ paths: parameters: - $ref: "#/components/parameters/consortiumId" - $ref: "#/components/parameters/tenantId" + - $ref: "#/components/parameters/centralTenantId" requestBody: $ref: "#/components/requestBodies/SyncPrimaryAffiliationsRequest" responses: @@ -206,6 +208,13 @@ components: type: string required: true description: The ID of the tenant + centralTenantId: + in: query + name: centralTenantId + schema: + type: string + required: true + description: The ID of the central tenant trait_pageable_offset: name: offset in: query diff --git a/src/test/java/org/folio/consortia/controller/TenantControllerTest.java b/src/test/java/org/folio/consortia/controller/TenantControllerTest.java index f34f0add..906aca35 100644 --- a/src/test/java/org/folio/consortia/controller/TenantControllerTest.java +++ b/src/test/java/org/folio/consortia/controller/TenantControllerTest.java @@ -166,7 +166,7 @@ void shouldSaveTenant(String contentString) throws Exception { when(tenantRepository.existsById(any())).thenReturn(false); when(tenantRepository.save(any(TenantEntity.class))).thenReturn(tenantEntity); when(tenantRepository.findCentralTenant()).thenReturn(Optional.of(centralTenant)); - doNothing().when(syncPrimaryAffiliationClient).syncPrimaryAffiliations(anyString(), anyString());//.thenReturn(new SyncPrimaryAffiliationBody()); + doNothing().when(syncPrimaryAffiliationClient).syncPrimaryAffiliations(anyString(), anyString(), anyString());//.thenReturn(new SyncPrimaryAffiliationBody()); doNothing().when(configurationClient).saveConfiguration(createConsortiaConfiguration(CENTRAL_TENANT_ID)); this.mockMvc.perform( diff --git a/src/test/java/org/folio/consortia/service/impl/SyncPrimaryAffiliationServiceImplTest.java b/src/test/java/org/folio/consortia/service/impl/SyncPrimaryAffiliationServiceImplTest.java index 5ea6357f..5782b6e7 100644 --- a/src/test/java/org/folio/consortia/service/impl/SyncPrimaryAffiliationServiceImplTest.java +++ b/src/test/java/org/folio/consortia/service/impl/SyncPrimaryAffiliationServiceImplTest.java @@ -80,6 +80,7 @@ class SyncPrimaryAffiliationServiceImplTest { void createPrimaryUserAffiliationsWhenCentralTenantSaving() throws JsonProcessingException { var consortiumId = UUID.randomUUID(); var tenantId = "ABC1"; + var centralTenantId = "diku"; TenantEntity tenantEntity1 = createTenantEntity(tenantId, "TestName1"); tenantEntity1.setConsortiumId(consortiumId); @@ -106,7 +107,7 @@ void createPrimaryUserAffiliationsWhenCentralTenantSaving() throws JsonProcessin okapiHeaders.put(XOkapiHeaders.TENANT, List.of(tenantId)); when(folioExecutionContext.getOkapiHeaders()).thenReturn(okapiHeaders); - syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, spab); + syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, centralTenantId, spab); verify(kafkaService, timeout(2000)).send(any(), anyString(), anyString()); } @@ -142,7 +143,7 @@ void createPrimaryUserAffiliationsWhenLocalTenantSaving() throws JsonProcessingE okapiHeaders.put(XOkapiHeaders.TENANT, List.of(centralTenantId)); when(folioExecutionContext.getOkapiHeaders()).thenReturn(okapiHeaders); - syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, spab); + syncPrimaryAffiliationService.createPrimaryUserAffiliations(consortiumId, centralTenantId, spab); verify(kafkaService, timeout(2000)).send(any(), anyString(), anyString()); }