diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json
index f8222c60..d921baa9 100644
--- a/descriptors/ModuleDescriptor-template.json
+++ b/descriptors/ModuleDescriptor-template.json
@@ -21,6 +21,14 @@
{
"id": "inventory",
"version": "13.0"
+ },
+ {
+ "id": "roles",
+ "version": "1.1"
+ },
+ {
+ "id": "policies",
+ "version": "1.1"
}
],
"optional": [
@@ -360,6 +368,26 @@
"consortia.sharing-policies.item.delete"
],
"modulePermissions": []
+ },
+ {
+ "methods": [
+ "POST"
+ ],
+ "pathPattern": "/consortia/{consortiumId}/sharing/roles",
+ "permissionsRequired": [
+ "consortia.sharing-roles.item.post"
+ ],
+ "modulePermissions": []
+ },
+ {
+ "methods": [
+ "DELETE"
+ ],
+ "pathPattern": "/consortia/{consortiumId}/sharing/roles/{rolesId}",
+ "permissionsRequired": [
+ "consortia.sharing-roles.item.delete"
+ ],
+ "modulePermissions": []
}
]
},
@@ -433,7 +461,9 @@
"consortia.sharing-settings.item.post",
"consortia.sharing-settings.item.delete",
"consortia.sharing-policies.item.post",
- "consortia.sharing-policies.item.delete"
+ "consortia.sharing-policies.item.delete",
+ "consortia.sharing-roles.item.post",
+ "consortia.sharing-roles.item.delete"
]
},
{
@@ -572,6 +602,16 @@
"permissionName": "consortia.sharing-policies.item.delete",
"displayName": "delete sharing policy",
"description": "Delete sharing policy"
+ },
+ {
+ "permissionName": "consortia.sharing-roles.item.post",
+ "displayName": "post sharing role",
+ "description": "Create sharing roles"
+ },
+ {
+ "permissionName": "consortia.sharing-roles.item.delete",
+ "displayName": "delete sharing role",
+ "description": "Delete sharing role"
}
],
"metadata": {
@@ -667,7 +707,13 @@
"user-settings.custom-fields.item.post",
"user-settings.custom-fields.collection.get",
"ui-users.editperms",
- "capabilities.collection.get"
+ "capabilities.collection.get",
+ "roles.item.post",
+ "roles.item.put",
+ "roles.item.delete",
+ "policies.item.post",
+ "policies.item.put",
+ "policies.item.delete"
]
}
},
diff --git a/pom.xml b/pom.xml
index 755498c2..06fded63 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,6 +55,8 @@
${project.basedir}/src/main/resources/swagger.api/sharing_instances.yaml
${project.basedir}/src/main/resources/swagger.api/sharing_settings.yaml
${project.basedir}/src/main/resources/swagger.api/sharing_policies.yaml
+ ${project.basedir}/src/main/resources/swagger.api/sharing_roles.yaml
+
8.1.2
@@ -559,6 +561,32 @@
+
+ sharing roles
+
+ generate
+
+
+ ${sharing_roles.yaml.file}
+
+ spring
+ ${project.groupId}.consortia.domain.dto
+ ${project.groupId}.consortia.rest.resource
+ true
+ true
+ true
+ true
+ false
+ true
+ ApiUtil.java
+ true
+
+ java
+ true
+ true
+
+
+
publish_coordinator
diff --git a/src/main/java/org/folio/consortia/controller/SharingRoleController.java b/src/main/java/org/folio/consortia/controller/SharingRoleController.java
new file mode 100644
index 00000000..a2afeb0b
--- /dev/null
+++ b/src/main/java/org/folio/consortia/controller/SharingRoleController.java
@@ -0,0 +1,39 @@
+package org.folio.consortia.controller;
+
+import static org.springframework.http.HttpStatus.CREATED;
+import static org.springframework.http.HttpStatus.OK;
+
+import java.util.UUID;
+
+import lombok.RequiredArgsConstructor;
+import org.folio.consortia.domain.dto.SharingRoleDeleteResponse;
+import org.folio.consortia.domain.dto.SharingRoleRequest;
+import org.folio.consortia.domain.dto.SharingRoleResponse;
+import org.folio.consortia.rest.resource.RolesApi;
+import org.folio.consortia.service.impl.SharingRoleService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/consortia/{consortiumId}/sharing")
+@RequiredArgsConstructor
+public class SharingRoleController implements RolesApi {
+
+ private final SharingRoleService sharingRoleService;
+
+ @Override
+ public ResponseEntity startSharingRole(UUID consortiumId, SharingRoleRequest sharingRoleRequest) {
+ return ResponseEntity
+ .status(CREATED)
+ .body(sharingRoleService.start(consortiumId, sharingRoleRequest));
+ }
+
+ @Override
+ public ResponseEntity deleteSharingRole(UUID consortiumId, UUID roleId,
+ SharingRoleRequest sharingRoleRequest) {
+ return ResponseEntity
+ .status(OK)
+ .body(sharingRoleService.delete(consortiumId, roleId, sharingRoleRequest));
+ }
+}
diff --git a/src/main/java/org/folio/consortia/domain/entity/SharingRoleEntity.java b/src/main/java/org/folio/consortia/domain/entity/SharingRoleEntity.java
new file mode 100644
index 00000000..d70e4f31
--- /dev/null
+++ b/src/main/java/org/folio/consortia/domain/entity/SharingRoleEntity.java
@@ -0,0 +1,41 @@
+package org.folio.consortia.domain.entity;
+
+import java.util.Objects;
+import java.util.UUID;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import org.folio.consortia.domain.entity.base.AuditableEntity;
+
+@Getter
+@Setter
+@ToString
+@RequiredArgsConstructor
+@Entity
+@Table(name = "sharing_role")
+public class SharingRoleEntity extends AuditableEntity {
+ @Id
+ private UUID id;
+ private UUID roleId;
+ private String tenantId;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SharingRoleEntity that = (SharingRoleEntity) o;
+ return Objects.equals(id, that.id)
+ && Objects.equals(roleId, that.roleId)
+ && Objects.equals(tenantId, that.tenantId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, roleId, tenantId);
+ }
+}
diff --git a/src/main/java/org/folio/consortia/repository/SharingRoleRepository.java b/src/main/java/org/folio/consortia/repository/SharingRoleRepository.java
new file mode 100644
index 00000000..c53c29ec
--- /dev/null
+++ b/src/main/java/org/folio/consortia/repository/SharingRoleRepository.java
@@ -0,0 +1,21 @@
+package org.folio.consortia.repository;
+
+import java.util.Set;
+import java.util.UUID;
+
+import org.folio.consortia.domain.entity.SharingRoleEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+
+public interface SharingRoleRepository extends JpaRepository {
+
+ @Query("SELECT sr.tenantId FROM SharingRoleEntity sr WHERE sr.roleId = ?1")
+ Set findTenantsByRoleId(UUID roleId);
+
+ boolean existsByRoleId(UUID roleId);
+
+ @Modifying
+ @Query("DELETE FROM SharingRoleEntity sr WHERE sr.roleId = ?1")
+ void deleteByRoleId(UUID roleId);
+}
diff --git a/src/main/java/org/folio/consortia/service/impl/SharingPolicyService.java b/src/main/java/org/folio/consortia/service/impl/SharingPolicyService.java
index a963efa8..964da3bb 100644
--- a/src/main/java/org/folio/consortia/service/impl/SharingPolicyService.java
+++ b/src/main/java/org/folio/consortia/service/impl/SharingPolicyService.java
@@ -82,10 +82,10 @@ protected PublicationRequest createPublicationRequest(SharingPolicyRequest shari
publicationRequest.setMethod(httpMethod);
String url = sharingPolicyRequest.getUrl();
if (httpMethod.equals(HttpMethod.PUT.toString()) || httpMethod.equals(HttpMethod.DELETE.toString())) {
- url += "/" + sharingPolicyRequest.getPolicyId();
+ url += "/" + getConfigId(sharingPolicyRequest);
}
publicationRequest.setUrl(url);
- publicationRequest.setPayload(sharingPolicyRequest.getPayload());
+ publicationRequest.setPayload(getPayload(sharingPolicyRequest));
publicationRequest.setTenants(new HashSet<>());
return publicationRequest;
}
diff --git a/src/main/java/org/folio/consortia/service/impl/SharingRoleService.java b/src/main/java/org/folio/consortia/service/impl/SharingRoleService.java
new file mode 100644
index 00000000..287b97bb
--- /dev/null
+++ b/src/main/java/org/folio/consortia/service/impl/SharingRoleService.java
@@ -0,0 +1,119 @@
+package org.folio.consortia.service.impl;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.ObjectUtils;
+import org.folio.consortia.domain.dto.PublicationRequest;
+import org.folio.consortia.domain.dto.SharingRoleDeleteResponse;
+import org.folio.consortia.domain.dto.SharingRoleRequest;
+import org.folio.consortia.domain.dto.SharingRoleResponse;
+import org.folio.consortia.domain.entity.SharingRoleEntity;
+import org.folio.consortia.exception.ResourceNotFoundException;
+import org.folio.consortia.repository.SharingRoleRepository;
+import org.folio.consortia.service.BaseSharingService;
+import org.folio.consortia.service.ConsortiumService;
+import org.folio.consortia.service.PublicationService;
+import org.folio.consortia.service.TenantService;
+import org.folio.spring.FolioExecutionContext;
+import org.folio.spring.service.SystemUserScopedExecutionService;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Service;
+
+@Service
+@Log4j2
+public class SharingRoleService extends BaseSharingService {
+
+ private final SharingRoleRepository sharingRoleRepository;
+
+ public SharingRoleService(TenantService tenantService,
+ ConsortiumService consortiumService,
+ SystemUserScopedExecutionService systemUserScopedExecutionService,
+ PublicationService publicationService, FolioExecutionContext folioExecutionContext,
+ ObjectMapper objectMapper, TaskExecutor asyncTaskExecutor,
+ SharingRoleRepository sharingRoleRepository) {
+ super(tenantService, consortiumService, systemUserScopedExecutionService, publicationService, folioExecutionContext, objectMapper, asyncTaskExecutor);
+ this.sharingRoleRepository = sharingRoleRepository;
+ }
+
+ @Override
+ protected UUID getConfigId(SharingRoleRequest sharingRoleRequest) {
+ return sharingRoleRequest.getRoleId();
+ }
+
+ @Override
+ protected Object getPayload(SharingRoleRequest sharingRoleRequest) {
+ return sharingRoleRequest.getPayload();
+ }
+
+ @Override
+ protected void validateSharingConfigRequestOrThrow(UUID roleId, SharingRoleRequest sharingRoleRequest) {
+ if (ObjectUtils.notEqual(getConfigId(sharingRoleRequest), roleId)) {
+ throw new IllegalArgumentException("Mismatch id in path to roleId in request body");
+ }
+ if (Objects.isNull(getPayload(sharingRoleRequest))) {
+ throw new IllegalArgumentException("Payload must not be null");
+ }
+ if (!sharingRoleRepository.existsByRoleId(roleId)) {
+ throw new ResourceNotFoundException("roleId", String.valueOf(roleId));
+ }
+ }
+
+ @Override
+ protected Set findTenantsByConfigId(UUID roleId) {
+ return sharingRoleRepository.findTenantsByRoleId(roleId);
+ }
+
+ @Override
+ protected void saveSharingConfig(List sharingRoleEntityList) {
+ sharingRoleRepository.saveAll(sharingRoleEntityList);
+ }
+
+ @Override
+ protected void deleteSharingConfig(UUID roleId) {
+ sharingRoleRepository.deleteByRoleId(roleId);
+ }
+
+ @Override
+ protected PublicationRequest createPublicationRequest(SharingRoleRequest sharingRoleRequest, String httpMethod) {
+ PublicationRequest publicationRequest = new PublicationRequest();
+ publicationRequest.setMethod(httpMethod);
+ String url = sharingRoleRequest.getUrl();
+ if (httpMethod.equals(HttpMethod.PUT.toString()) || httpMethod.equals(HttpMethod.DELETE.toString())) {
+ url += "/" + getConfigId(sharingRoleRequest);
+ }
+ publicationRequest.setUrl(url);
+ publicationRequest.setPayload(getPayload(sharingRoleRequest));
+ publicationRequest.setTenants(new HashSet<>());
+ return publicationRequest;
+ }
+
+ @Override
+ protected SharingRoleEntity createSharingConfigEntityFromRequest(SharingRoleRequest sharingRoleRequest, String tenantId) {
+ SharingRoleEntity sharingRoleEntity = new SharingRoleEntity();
+ sharingRoleEntity.setId(UUID.randomUUID());
+ sharingRoleEntity.setRoleId(sharingRoleEntity.getRoleId());
+ sharingRoleEntity.setTenantId(tenantId);
+ return sharingRoleEntity;
+ }
+
+ @Override
+ protected SharingRoleResponse createSharingConfigResponse(UUID createRolesPcId, UUID updateRolesPcId) {
+ return new SharingRoleResponse()
+ .createRolesPCId(createRolesPcId)
+ .updateRolesPCId(updateRolesPcId);
+ }
+
+ @Override
+ protected SharingRoleDeleteResponse createSharingConfigResponse(UUID publishRequestId) {
+ return new SharingRoleDeleteResponse()
+ .pcId(publishRequestId);
+ }
+}
diff --git a/src/main/java/org/folio/consortia/service/impl/SharingSettingService.java b/src/main/java/org/folio/consortia/service/impl/SharingSettingService.java
index 6d31f4d5..1a4682b0 100644
--- a/src/main/java/org/folio/consortia/service/impl/SharingSettingService.java
+++ b/src/main/java/org/folio/consortia/service/impl/SharingSettingService.java
@@ -89,10 +89,10 @@ protected PublicationRequest createPublicationRequest(SharingSettingRequest shar
publicationRequest.setMethod(httpMethod);
String url = sharingSettingRequest.getUrl();
if (httpMethod.equals(HttpMethod.PUT.toString()) || httpMethod.equals(HttpMethod.DELETE.toString())) {
- url += "/" + sharingSettingRequest.getSettingId();
+ url += "/" + getConfigId(sharingSettingRequest);
}
publicationRequest.setUrl(url);
- publicationRequest.setPayload(sharingSettingRequest.getPayload());
+ publicationRequest.setPayload(getPayload(sharingSettingRequest));
publicationRequest.setTenants(new HashSet<>());
return publicationRequest;
}
diff --git a/src/main/resources/swagger.api/schemas/sharingRole.yaml b/src/main/resources/swagger.api/schemas/sharingRole.yaml
new file mode 100644
index 00000000..2240c34d
--- /dev/null
+++ b/src/main/resources/swagger.api/schemas/sharingRole.yaml
@@ -0,0 +1,44 @@
+SharingRoleRequest:
+ description: "A JSON schema for the Sharing roles object"
+ type: object
+ properties:
+ roleId:
+ description: id of sharing role record
+ type: string
+ format: uuid
+ url:
+ description: URL for publishing requests for consortia tenants
+ type: string
+ payload:
+ description: Http request body
+ type: object
+ additionalProperties: false
+ required:
+ - roleId
+ - url
+
+SharingRoleResponse:
+ description: "A JSON schema for the Sharing roles object response for post request"
+ type: object
+ properties:
+ createRolesPCId:
+ type: string
+ format: uuid
+ updateRolesPCId:
+ type: string
+ format: uuid
+ additionalProperties: false
+ required:
+ - createRolesPCId
+ - updateRolesPCId
+
+SharingRoleDeleteResponse:
+ description: "A JSON schema for the Sharing roles object response for delete request"
+ type: object
+ properties:
+ pcId:
+ type: string
+ format: uuid
+ additionalProperties: false
+ required:
+ - pcId
diff --git a/src/main/resources/swagger.api/sharing_policies.yaml b/src/main/resources/swagger.api/sharing_policies.yaml
index 76d77a86..1ae1ea47 100644
--- a/src/main/resources/swagger.api/sharing_policies.yaml
+++ b/src/main/resources/swagger.api/sharing_policies.yaml
@@ -8,7 +8,7 @@ servers:
paths:
/policies:
post:
- summary: start policy sharing
+ summary: start sharing policy
operationId: startSharingPolicy
parameters:
- $ref: "#/components/parameters/consortiumId"
diff --git a/src/main/resources/swagger.api/sharing_roles.yaml b/src/main/resources/swagger.api/sharing_roles.yaml
new file mode 100644
index 00000000..63514a35
--- /dev/null
+++ b/src/main/resources/swagger.api/sharing_roles.yaml
@@ -0,0 +1,125 @@
+openapi: 3.0.0
+info:
+ title: Sharing role integration API
+ description: "Sharing role integration API"
+ version: 0.0.1
+servers:
+ - url: /consortia/{consortiumId}/sharing
+paths:
+ /roles:
+ post:
+ summary: start sharing role
+ operationId: startSharingRole
+ parameters:
+ - $ref: "#/components/parameters/consortiumId"
+ requestBody:
+ $ref: "#/components/requestBodies/SharingRoleBody"
+ responses:
+ "201":
+ $ref: "#/components/responses/SharingRoleResponse"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "409":
+ $ref: "#/components/responses/Conflict"
+ "422":
+ $ref: "#/components/responses/Conflict"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
+ /roles/{roleId}:
+ delete:
+ summary: delete sharing role
+ operationId: deleteSharingRole
+ parameters:
+ - $ref: "#/components/parameters/consortiumId"
+ - $ref: "#/components/parameters/roleId"
+ requestBody:
+ $ref: "#/components/requestBodies/SharingRoleBody"
+ responses:
+ "200":
+ $ref: "#/components/responses/SharingRoleDeleteResponse"
+ "400":
+ $ref: "#/components/responses/BadRequest"
+ "404":
+ $ref: "#/components/responses/NotFound"
+ "409":
+ $ref: "#/components/responses/Conflict"
+ "422":
+ $ref: "#/components/responses/Conflict"
+ "500":
+ $ref: "#/components/responses/InternalServerError"
+components:
+ requestBodies:
+ SharingRoleBody:
+ description: Sharing roles object
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "schemas/sharingRole.yaml#/SharingRoleRequest"
+ responses:
+ SharingRoleResponse:
+ description: Returns a sharing role object response for post operation
+ content:
+ application/json:
+ schema:
+ $ref: "schemas/sharingRole.yaml#/SharingRoleResponse"
+ SharingRoleDeleteResponse:
+ description: Returns a sharing role response for delete operation
+ content:
+ application/json:
+ schema:
+ $ref: "schemas/sharingRole.yaml#/SharingRoleDeleteResponse"
+ NoContent:
+ description: No content
+ Conflict:
+ description: Validation errors
+ content:
+ application/json:
+ schema:
+ $ref: "schemas/common.yaml#/Errors"
+ NotFound:
+ description: Resource not found
+ content:
+ application/json:
+ schema:
+ $ref: "schemas/common.yaml#/Errors"
+ BadRequest:
+ description: Bad request
+ content:
+ application/json:
+ schema:
+ $ref: "schemas/common.yaml#/Errors"
+ Unauthorized:
+ description: Not authorized to perform requested action
+ content:
+ text/plain:
+ example: unable to perform action -- unauthorized
+ UnprocessableEntity:
+ description: Validation errors
+ content:
+ application/json:
+ schema:
+ $ref: 'schemas/common.yaml#/Errors'
+ InternalServerError:
+ description: Internal server error
+ content:
+ application/json:
+ schema:
+ $ref: "schemas/common.yaml#/Error"
+ parameters:
+ consortiumId:
+ in: path
+ name: consortiumId
+ schema:
+ $ref: "schemas/common.yaml#/uuid"
+ required: true
+ description: The ID of consortium
+ roleId:
+ in: path
+ name: roleId
+ schema:
+ $ref: "schemas/common.yaml#/uuid"
+ required: true
+ description: The ID of role
diff --git a/src/test/java/org/folio/consortia/controller/SharingRoleControllerTest.java b/src/test/java/org/folio/consortia/controller/SharingRoleControllerTest.java
new file mode 100644
index 00000000..94b74a9b
--- /dev/null
+++ b/src/test/java/org/folio/consortia/controller/SharingRoleControllerTest.java
@@ -0,0 +1,63 @@
+package org.folio.consortia.controller;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.UUID;
+
+import org.folio.consortia.base.BaseIT;
+import org.folio.consortia.domain.dto.SharingRoleDeleteResponse;
+import org.folio.consortia.domain.dto.SharingRoleResponse;
+import org.folio.consortia.service.impl.SharingRoleService;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+
+class SharingRoleControllerTest extends BaseIT {
+ @MockBean
+ SharingRoleService sharingRoleService;
+
+ @ParameterizedTest
+ @ValueSource(strings = {"{\"roleId\":\"2844767a-8367-4926-9999-514c35840399\",\"url\":\"/role\",\"payload\":{\"name\":\"ROLE-NAME\",\"source\":\"local\"}}" })
+ void shouldStartSharingRole(String body) throws Exception {
+ var headers = defaultHeaders();
+ UUID createRolesPcId = UUID.randomUUID();
+ UUID updateRolesPcId = UUID.randomUUID();
+ SharingRoleResponse sharingRoleResponse = new SharingRoleResponse()
+ .createRolesPCId(createRolesPcId)
+ .updateRolesPCId(updateRolesPcId);
+
+ when(sharingRoleService.start(any(), any())).thenReturn(sharingRoleResponse);
+
+ this.mockMvc.perform(
+ post("/consortia/7698e46-c3e3-11ed-afa1-0242ac120002/sharing/roles")
+ .headers(headers)
+ .content(body)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("$.createRolesPCId").value(String.valueOf(createRolesPcId)))
+ .andExpect(jsonPath("$.updateRolesPCId").value(String.valueOf(updateRolesPcId)));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"{\"roleId\":\"2844767a-8367-4926-9999-514c35840399\",\"url\":\"/role\"}" })
+ void shouldDeleteSharingRole(String body) throws Exception {
+ var headers = defaultHeaders();
+ UUID pcId = UUID.randomUUID();
+ SharingRoleDeleteResponse sharingRoleDeleteResponse = new SharingRoleDeleteResponse().pcId(pcId);
+
+ when(sharingRoleService.delete(any(), any(), any())).thenReturn(sharingRoleDeleteResponse);
+
+ this.mockMvc.perform(
+ delete("/consortia/7698e46-c3e3-11ed-afa1-0242ac120002/sharing/roles/2844767a-8367-4926-9999-514c35840399")
+ .headers(headers)
+ .content(body)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().is2xxSuccessful());
+ }
+}
diff --git a/src/test/java/org/folio/consortia/service/SharingPolicyServiceTest.java b/src/test/java/org/folio/consortia/service/SharingPolicyServiceTest.java
index 0221c8fd..e25b50a6 100644
--- a/src/test/java/org/folio/consortia/service/SharingPolicyServiceTest.java
+++ b/src/test/java/org/folio/consortia/service/SharingPolicyServiceTest.java
@@ -2,7 +2,7 @@
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.folio.consortia.support.EntityUtils.createJsonNodeForGroupPayload;
-import static org.folio.consortia.support.EntityUtils.createJsonNodeForRolePayload;
+import static org.folio.consortia.support.EntityUtils.createJsonNodeForPolicyPayload;
import static org.folio.consortia.support.EntityUtils.createPublicationDetails;
import static org.folio.consortia.support.EntityUtils.createPublicationRequest;
import static org.folio.consortia.support.EntityUtils.createPublicationResultCollection;
@@ -126,7 +126,7 @@ void shouldStartSharingPolicy() throws JsonProcessingException {
when(sharingPolicyRepository.save(any())).thenReturn(new SharingPolicyEntity());
when(folioExecutionContext.getTenantId()).thenReturn("mobius");
when(systemUserScopedExecutionService.executeSystemUserScoped(eq("mobius"), any())).then(SharingPolicyServiceTest::callSecondArgument);
- when(objectMapper.convertValue(payload, JsonNode.class)).thenReturn(createJsonNodeForRolePayload());
+ when(objectMapper.convertValue(payload, JsonNode.class)).thenReturn(createJsonNodeForPolicyPayload());
var expectedResponse = createSharingPolicyResponse(createPoliciesPcId, updatePoliciesPcId);
var actualResponse = sharingPolicyService.start(CONSORTIUM_ID, sharingPolicyRequest);
@@ -220,7 +220,7 @@ void shouldUpdateFailedTenantPolicies() throws NoSuchMethodException, Invocation
void shouldThrowErrorForNotEqualPolicyIdWithPayloadId() throws JsonProcessingException {
var sharingPolicyRequest = getMockDataObject(SHARING_POLICY_REQUEST_SAMPLE_FOR_ROLES, SharingPolicyRequest.class);
sharingPolicyRequest.setPolicyId(UUID.randomUUID());
- JsonNode node = createJsonNodeForRolePayload();
+ JsonNode node = createJsonNodeForPolicyPayload();
when(consortiumRepository.existsById(CONSORTIUM_ID)).thenReturn(true);
when(objectMapper.convertValue(any(), eq(JsonNode.class))).thenReturn(node);
diff --git a/src/test/java/org/folio/consortia/service/SharingRoleServiceTest.java b/src/test/java/org/folio/consortia/service/SharingRoleServiceTest.java
new file mode 100644
index 00000000..a0f0463b
--- /dev/null
+++ b/src/test/java/org/folio/consortia/service/SharingRoleServiceTest.java
@@ -0,0 +1,290 @@
+package org.folio.consortia.service;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.folio.consortia.support.EntityUtils.createJsonNodeForGroupPayload;
+import static org.folio.consortia.support.EntityUtils.createJsonNodeForRolePayload;
+import static org.folio.consortia.support.EntityUtils.createPublicationDetails;
+import static org.folio.consortia.support.EntityUtils.createPublicationRequest;
+import static org.folio.consortia.support.EntityUtils.createPublicationResultCollection;
+import static org.folio.consortia.support.EntityUtils.createSharingRoleResponse;
+import static org.folio.consortia.support.EntityUtils.createSharingRoleResponseForDelete;
+import static org.folio.consortia.support.EntityUtils.createTenant;
+import static org.folio.consortia.support.EntityUtils.createTenantCollection;
+import static org.folio.consortia.support.TestConstants.CONSORTIUM_ID;
+import static org.folio.consortia.utils.InputOutputTestUtils.getMockDataObject;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import org.folio.consortia.domain.dto.PublicationRequest;
+import org.folio.consortia.domain.dto.PublicationResponse;
+import org.folio.consortia.domain.dto.PublicationStatus;
+import org.folio.consortia.domain.dto.SharingRoleRequest;
+import org.folio.consortia.domain.dto.Tenant;
+import org.folio.consortia.domain.dto.TenantCollection;
+import org.folio.consortia.domain.entity.SharingRoleEntity;
+import org.folio.consortia.exception.ResourceNotFoundException;
+import org.folio.consortia.repository.ConsortiumRepository;
+import org.folio.consortia.repository.PublicationStatusRepository;
+import org.folio.consortia.repository.SharingRoleRepository;
+import org.folio.consortia.service.impl.SharingRoleService;
+import org.folio.spring.DefaultFolioExecutionContext;
+import org.folio.spring.FolioExecutionContext;
+import org.folio.spring.FolioModuleMetadata;
+import org.folio.spring.integration.XOkapiHeaders;
+import org.folio.spring.scope.FolioExecutionContextSetter;
+import org.folio.spring.service.SystemUserScopedExecutionService;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.http.HttpMethod;
+import org.springframework.test.util.ReflectionTestUtils;
+
+@SpringBootTest
+class SharingRoleServiceTest {
+ private static final String SHARING_ROLE_REQUEST_SAMPLE = "mockdata/sharing_roles/sharing_role_request.json";
+ private static final String SHARING_ROLE_REQUEST_SAMPLE_WITHOUT_PAYLOAD = "mockdata/sharing_roles/sharing_role_request_without_payload.json";
+
+ @InjectMocks
+ private SharingRoleService sharingRoleService;
+ @Mock
+ private ConsortiumRepository consortiumRepository;
+ @Mock
+ private ConsortiumService consortiumService;
+ @Mock
+ private TaskExecutor asyncTaskExecutor;
+ @Mock
+ private TenantService tenantService;
+ @Mock
+ private PublicationService publicationService;
+ @Mock
+ private PublicationStatusRepository publicationStatusRepository;
+ @Mock
+ private SharingRoleRepository sharingRoleRepository;
+ @Mock
+ private FolioExecutionContext folioExecutionContext;
+ @Mock
+ private SystemUserScopedExecutionService systemUserScopedExecutionService;
+ @Mock
+ private ObjectMapper objectMapper;
+
+ @Test
+ void shouldStartSharingRole() throws JsonProcessingException {
+ UUID createRolesPcId = UUID.randomUUID();
+ UUID updateRolesPcId = UUID.randomUUID();
+ Tenant tenant1 = createTenant("tenant1", "tenant1");
+ Tenant tenant2 = createTenant("tenant2", "tenant2");
+ Set tenantAssociationsWithRole = Set.of("tenant1");
+ TenantCollection tenantCollection = createTenantCollection(List.of(tenant1, tenant2));
+ var sharingRoleRequest = getMockDataObject(SHARING_ROLE_REQUEST_SAMPLE, SharingRoleRequest.class);
+ Map payload = new LinkedHashMap<>();
+ payload.put("id", "3844767a-8367-4926-9999-514c35840399");
+ payload.put("name", "Role for policy: 104d7a66-c51d-402a-9c9f-3bdcdbbcdbe7");
+ payload.put("source", "local");
+
+ // "tenant1" exists in tenant role association so that tenant1 is in PUT request publication,
+ // "tenant2" is in POST method publication
+ var publicationRequestPut = createPublicationRequest(sharingRoleRequest, HttpMethod.PUT.toString());
+ publicationRequestPut.setMethod("PUT");
+ publicationRequestPut.setTenants(Set.of("tenant1"));
+ publicationRequestPut.setUrl("/role/3844767a-8367-4926-9999-514c35840399");
+ var publicationRequestPost = createPublicationRequest(sharingRoleRequest, HttpMethod.POST.toString());
+ publicationRequestPost.setMethod("POST");
+ publicationRequestPost.setTenants(Set.of("tenant2"));
+
+ var publicationResponsePost = new PublicationResponse().id(createRolesPcId);
+ var publicationResponsePut = new PublicationResponse().id(updateRolesPcId);
+
+ when(consortiumRepository.existsById(CONSORTIUM_ID)).thenReturn(true);
+ when(publicationService.publishRequest(CONSORTIUM_ID, publicationRequestPost)).thenReturn(publicationResponsePost);
+ when(publicationService.publishRequest(CONSORTIUM_ID, publicationRequestPut)).thenReturn(publicationResponsePut);
+ when(tenantService.getAll(CONSORTIUM_ID)).thenReturn(tenantCollection);
+ when(sharingRoleRepository.findTenantsByRoleId(sharingRoleRequest.getRoleId())).thenReturn(tenantAssociationsWithRole);
+ when(sharingRoleRepository.save(any())).thenReturn(new SharingRoleEntity());
+ when(folioExecutionContext.getTenantId()).thenReturn("mobius");
+ when(systemUserScopedExecutionService.executeSystemUserScoped(eq("mobius"), any())).then(SharingRoleServiceTest::callSecondArgument);
+ when(objectMapper.convertValue(payload, JsonNode.class)).thenReturn(createJsonNodeForRolePayload());
+
+ var expectedResponse = createSharingRoleResponse(createRolesPcId, updateRolesPcId);
+ var actualResponse = sharingRoleService.start(CONSORTIUM_ID, sharingRoleRequest);
+
+ assertThat(actualResponse.getCreateRolesPCId()).isEqualTo(expectedResponse.getCreateRolesPCId());
+ assertThat(actualResponse.getUpdateRolesPCId()).isEqualTo(expectedResponse.getUpdateRolesPCId());
+
+ verify(publicationService, times(2)).publishRequest(any(), any());
+ }
+
+ @Test
+ void shouldDeleteSharingRole() {
+ UUID pcId = UUID.randomUUID();
+ UUID roleId = UUID.fromString("3844767a-8367-4926-9999-514c35840399");
+ Tenant tenant1 = createTenant("tenant1", "tenant1");
+ Tenant tenant2 = createTenant("tenant2", "tenant2");
+ Set tenantAssociationsWithRole = Set.of("tenant1");
+ TenantCollection tenantCollection = createTenantCollection(List.of(tenant1, tenant2));
+ var sharingRoleRequest = getMockDataObject(SHARING_ROLE_REQUEST_SAMPLE, SharingRoleRequest.class);
+
+ // "tenant1" exists in tenant role association so that tenant1 is in DELETE request publication,
+ var expectedPublicationRequestDelete = createPublicationRequest(sharingRoleRequest, HttpMethod.DELETE.toString());
+ expectedPublicationRequestDelete.setTenants(Set.of("tenant1"));
+ expectedPublicationRequestDelete.setUrl("/role/3844767a-8367-4926-9999-514c35840399");
+ Map map = new LinkedHashMap<>();
+ map.put("id", "3844767a-8367-4926-9999-514c35840399");
+ map.put("name", "Role for policy: 104d7a66-c51d-402a-9c9f-3bdcdbbcdbe7");
+ map.put("source", "local");
+ expectedPublicationRequestDelete.setPayload(map);
+
+ var publicationResponse = new PublicationResponse().id(pcId);
+
+ when(consortiumRepository.existsById(CONSORTIUM_ID)).thenReturn(true);
+ when(sharingRoleRepository.existsByRoleId(roleId)).thenReturn(true);
+ when(publicationService.publishRequest(CONSORTIUM_ID, expectedPublicationRequestDelete)).thenReturn(publicationResponse);
+ when(tenantService.getAll(CONSORTIUM_ID)).thenReturn(tenantCollection);
+ when(sharingRoleRepository.findTenantsByRoleId(sharingRoleRequest.getRoleId())).thenReturn(tenantAssociationsWithRole);
+ when(folioExecutionContext.getTenantId()).thenReturn("mobius");
+ when(systemUserScopedExecutionService.executeSystemUserScoped(eq("mobius"), any())).then(SharingRoleServiceTest::callSecondArgument);
+
+ var expectedResponse = createSharingRoleResponseForDelete(pcId);
+ var actualResponse = sharingRoleService.delete(CONSORTIUM_ID, roleId, sharingRoleRequest);
+
+ assertThat(actualResponse.getPcId()).isEqualTo(expectedResponse.getPcId());
+
+ verify(publicationService, times(1)).publishRequest(any(), any());
+ }
+
+ @Test
+ void shouldUpdateFailedTenantPolicies() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, JsonProcessingException {
+ UUID publicationId = UUID.randomUUID();
+ UUID pcId = UUID.randomUUID();
+ var publicationResponse = new PublicationResponse().id(pcId);
+ var sharingRoleRequest = getMockDataObject(SHARING_ROLE_REQUEST_SAMPLE, SharingRoleRequest.class);
+ String centralTenant = "mobius";
+ String localTenant = "school";
+ var publicationResultCollection = createPublicationResultCollection(centralTenant, localTenant);
+ var publicationDetails = createPublicationDetails(PublicationStatus.ERROR);
+ JsonNode node = createJsonNodeForGroupPayload();
+ // expected data for publish request
+ Set expectedFailedTenantList = new HashSet<>(List.of(centralTenant, localTenant));
+ var expectedPublicationRequest = createExceptedPublicationRequest(sharingRoleRequest, expectedFailedTenantList, HttpMethod.PUT);
+
+ // set time interval and maxTries for Thread sleep cycle
+ ReflectionTestUtils.setField(sharingRoleService, "maxTries", 60);
+ ReflectionTestUtils.setField(sharingRoleService, "interval", 200);
+
+ when(publicationService.checkPublicationDetailsExists(CONSORTIUM_ID, publicationId))
+ .thenReturn(false)
+ .thenReturn(false)
+ .thenReturn(true);
+ when(publicationService.getPublicationDetails(CONSORTIUM_ID, publicationId)).thenReturn(publicationDetails);
+ when(publicationService.getPublicationResults(CONSORTIUM_ID, publicationId)).thenReturn(publicationResultCollection);
+ when(objectMapper.convertValue(any(), eq(JsonNode.class))).thenReturn(node);
+ when(folioExecutionContext.getTenantId()).thenReturn("mobius");
+ when(systemUserScopedExecutionService.executeSystemUserScoped(eq("mobius"), any())).then(SharingRoleServiceTest::callSecondArgument);
+ when(publicationService.publishRequest(CONSORTIUM_ID, expectedPublicationRequest)).thenReturn(publicationResponse);
+
+ // Use reflection to access the protected method in BaseSharingService
+ Method method = SharingRoleService.class.getSuperclass().getDeclaredMethod("updateConfigsForFailedTenantsWithRetry", UUID.class, UUID.class, Object.class);
+ method.setAccessible(true);
+ method.invoke(sharingRoleService, CONSORTIUM_ID, publicationId, sharingRoleRequest);
+
+ verify(publicationService).getPublicationDetails(CONSORTIUM_ID, publicationId);
+ verify(publicationService, times(3)).checkPublicationDetailsExists(CONSORTIUM_ID, publicationId);
+ verify(publicationService).publishRequest(CONSORTIUM_ID, expectedPublicationRequest);
+ }
+
+ // Negative cases
+ @Test
+ void shouldThrowErrorForNotEqualRoleIdWithPayloadId() throws JsonProcessingException {
+ var sharingRoleRequest = getMockDataObject(SHARING_ROLE_REQUEST_SAMPLE, SharingRoleRequest.class);
+ sharingRoleRequest.setRoleId(UUID.randomUUID());
+ JsonNode node = createJsonNodeForRolePayload();
+
+ when(consortiumRepository.existsById(CONSORTIUM_ID)).thenReturn(true);
+ when(objectMapper.convertValue(any(), eq(JsonNode.class))).thenReturn(node);
+
+ assertThrows(IllegalArgumentException.class, () -> sharingRoleService.start(CONSORTIUM_ID, sharingRoleRequest));
+ verify(publicationService, times(0)).publishRequest(any(), any());
+ }
+
+ @Test
+ void shouldThrowErrorForNotEqualRoleIdPathId() {
+ UUID roleId = UUID.fromString("999999-8367-4926-9999-514c35840399");
+
+ var sharingRoleRequest = getMockDataObject(SHARING_ROLE_REQUEST_SAMPLE, SharingRoleRequest.class);
+
+ when(consortiumRepository.existsById(CONSORTIUM_ID)).thenReturn(true);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> sharingRoleService.delete(CONSORTIUM_ID, roleId, sharingRoleRequest));
+ verify(publicationService, times(0)).publishRequest(any(), any());
+ }
+
+ @Test
+ void shouldThrowErrorForNotHavingPayloadOfRole() {
+ var sharingRoleRequest = getMockDataObject(SHARING_ROLE_REQUEST_SAMPLE_WITHOUT_PAYLOAD, SharingRoleRequest.class);
+
+ when(consortiumRepository.existsById(CONSORTIUM_ID)).thenReturn(true);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> sharingRoleService.delete(CONSORTIUM_ID, sharingRoleRequest.getRoleId(), sharingRoleRequest));
+ verify(publicationService, times(0)).publishRequest(any(), any());
+ }
+
+ @Test
+ void shouldThrowErrorForNotFound() {
+ UUID roleId = UUID.fromString("3844767a-8367-4926-9999-514c35840399");
+
+ var sharingRoleRequest = getMockDataObject(SHARING_ROLE_REQUEST_SAMPLE, SharingRoleRequest.class);
+
+ when(consortiumRepository.existsById(CONSORTIUM_ID)).thenReturn(true);
+ when(sharingRoleRepository.existsByRoleId(roleId)).thenReturn(false);
+
+ assertThrows(ResourceNotFoundException.class,
+ () -> sharingRoleService.delete(CONSORTIUM_ID, roleId, sharingRoleRequest));
+ verify(publicationService, times(0)).publishRequest(any(), any());
+ }
+
+ public static PublicationRequest createExceptedPublicationRequest(SharingRoleRequest sharingRoleRequest, Set tenantList, HttpMethod method) {
+ var expectedPublicationRequest = new PublicationRequest();
+ expectedPublicationRequest.setTenants(tenantList);
+ expectedPublicationRequest.setMethod(method.toString());
+ expectedPublicationRequest.setUrl(sharingRoleRequest.getUrl() + "/" + sharingRoleRequest.getRoleId());
+ final ObjectMapper mapper = new ObjectMapper();
+ final ObjectNode root = mapper.createObjectNode();
+ root.set("group", mapper.convertValue("space", JsonNode.class));
+ root.set("source", mapper.convertValue("user", JsonNode.class));
+ expectedPublicationRequest.setPayload(root);
+ return expectedPublicationRequest;
+ }
+
+ private static T callSecondArgument(InvocationOnMock invocation) throws Exception {
+ var headers = Map.>of(XOkapiHeaders.TENANT, List.of("mobius"));
+ var context = new DefaultFolioExecutionContext(mock(FolioModuleMetadata.class), headers);
+ try(var ignored = new FolioExecutionContextSetter(context)) {
+ return invocation.>getArgument(1).call();
+ }
+ }
+}
diff --git a/src/test/java/org/folio/consortia/support/EntityUtils.java b/src/test/java/org/folio/consortia/support/EntityUtils.java
index ca00f432..2e20e36f 100644
--- a/src/test/java/org/folio/consortia/support/EntityUtils.java
+++ b/src/test/java/org/folio/consortia/support/EntityUtils.java
@@ -26,6 +26,9 @@
import org.folio.consortia.domain.dto.SharingPolicyDeleteResponse;
import org.folio.consortia.domain.dto.SharingPolicyRequest;
import org.folio.consortia.domain.dto.SharingPolicyResponse;
+import org.folio.consortia.domain.dto.SharingRoleDeleteResponse;
+import org.folio.consortia.domain.dto.SharingRoleRequest;
+import org.folio.consortia.domain.dto.SharingRoleResponse;
import org.folio.consortia.domain.dto.SharingSettingDeleteResponse;
import org.folio.consortia.domain.dto.SharingSettingRequest;
import org.folio.consortia.domain.dto.SharingSettingResponse;
@@ -268,10 +271,21 @@ public static SharingPolicyResponse createSharingPolicyResponse(UUID createPolic
return new SharingPolicyResponse().createPoliciesPCId(createPolicyPcId).updatePoliciesPCId(updatePolicyPcId);
}
+
public static SharingPolicyDeleteResponse createSharingPolicyResponseForDelete(UUID pcId) {
return new SharingPolicyDeleteResponse().pcId(pcId);
}
+ public static SharingRoleResponse createSharingRoleResponse(UUID createRolePcId, UUID updateRolePcId) {
+ return new SharingRoleResponse().createRolesPCId(createRolePcId).updateRolesPCId(updateRolePcId);
+ }
+
+
+ public static SharingRoleDeleteResponse createSharingRoleResponseForDelete(UUID pcId) {
+ return new SharingRoleDeleteResponse().pcId(pcId);
+ }
+
+
public static TenantCollection createTenantCollection(List tenants) {
TenantCollection tenantCollection = new TenantCollection();
tenantCollection.setTenants(tenants);
@@ -305,6 +319,19 @@ public static PublicationRequest createPublicationRequest(SharingPolicyRequest s
return publicationRequest;
}
+ public static PublicationRequest createPublicationRequest(SharingRoleRequest sharingRoleRequest, String method){
+ PublicationRequest publicationRequest = new PublicationRequest();
+ publicationRequest.setUrl(sharingRoleRequest.getUrl());
+ publicationRequest.setMethod(method);
+ final ObjectMapper mapper = new ObjectMapper();
+ final ObjectNode root = mapper.createObjectNode();
+ root.set("id", mapper.convertValue("3844767a-8367-4926-9999-514c35840399", JsonNode.class));
+ root.set("name", mapper.convertValue("Role for policy: 104d7a66-c51d-402a-9c9f-3bdcdbbcdbe7", JsonNode.class));
+ root.set("source", mapper.convertValue("consortium", JsonNode.class));
+ publicationRequest.setPayload(root);
+ return publicationRequest;
+ }
+
public static PublicationResultCollection createPublicationResultCollection(String tenantId1, String tenantId2) {
var pbr1 = new PublicationResult();
pbr1.setTenantId(tenantId1);
@@ -333,7 +360,7 @@ public static JsonNode createJsonNodeForDepartmentPayload() throws JsonProcessin
return mapper.readTree(json);
}
- public static JsonNode createJsonNodeForRolePayload() throws JsonProcessingException {
+ public static JsonNode createJsonNodeForPolicyPayload() throws JsonProcessingException {
Map payload = new HashMap<>();
payload.put("id", "2844767a-8367-4926-9999-514c35840399");
payload.put("name", "Policy for role: 004d7a66-c51d-402a-9c9f-3bdcdbbcdbe7");
@@ -343,6 +370,16 @@ public static JsonNode createJsonNodeForRolePayload() throws JsonProcessingExcep
return mapper.readTree(json);
}
+ public static JsonNode createJsonNodeForRolePayload() throws JsonProcessingException {
+ Map payload = new HashMap<>();
+ payload.put("id", "3844767a-8367-4926-9999-514c35840399");
+ payload.put("name", "Role for policy: 104d7a66-c51d-402a-9c9f-3bdcdbbcdbe7");
+ payload.put("source", "local");
+ ObjectMapper mapper = new ObjectMapper();
+ String json = mapper.writeValueAsString(payload);
+ return mapper.readTree(json);
+ }
+
public static JsonNode createJsonNodeForGroupPayload() throws JsonProcessingException {
Map payload = new HashMap<>();
payload.put("group", "space");
diff --git a/src/test/resources/mockdata/sharing_roles/sharing_role_request.json b/src/test/resources/mockdata/sharing_roles/sharing_role_request.json
new file mode 100644
index 00000000..32554f83
--- /dev/null
+++ b/src/test/resources/mockdata/sharing_roles/sharing_role_request.json
@@ -0,0 +1,9 @@
+{
+ "roleId": "3844767a-8367-4926-9999-514c35840399",
+ "url": "/role",
+ "payload": {
+ "id": "3844767a-8367-4926-9999-514c35840399",
+ "name": "Role for policy: 104d7a66-c51d-402a-9c9f-3bdcdbbcdbe7",
+ "source": "local"
+ }
+}
diff --git a/src/test/resources/mockdata/sharing_roles/sharing_role_request_without_payload.json b/src/test/resources/mockdata/sharing_roles/sharing_role_request_without_payload.json
new file mode 100644
index 00000000..178989f4
--- /dev/null
+++ b/src/test/resources/mockdata/sharing_roles/sharing_role_request_without_payload.json
@@ -0,0 +1,4 @@
+{
+ "roleId": "3844767a-8367-4926-9999-514c35840399",
+ "url": "/role"
+}