Skip to content

Commit

Permalink
AYS-241 | Validations of AysRoleUpdateRequest Have Been Fixed (#345)
Browse files Browse the repository at this point in the history
  • Loading branch information
agitrubard authored Jul 21, 2024
1 parent f08ed0e commit 7311f7a
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,25 @@
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import org.ays.common.util.validation.NoSpecialCharacters;
import org.ays.common.util.validation.Name;
import org.hibernate.validator.constraints.UUID;

import java.util.Set;

/**
* Request object for updating a role.
* This class is used to encapsulate the data needed to update a role, including the role name and permission IDs.
*/
@Getter
@Setter
public class AysRoleUpdateRequest {

@Name
@NotBlank
@Size(min = 2, max = 255)
@NoSpecialCharacters
private String name;

@NotEmpty
private Set<@UUID String> permissionIds;
private Set<@NotBlank @UUID String> permissionIds;

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
import org.ays.auth.port.AysRoleReadPort;
import org.ays.auth.port.AysRoleSavePort;
import org.ays.auth.service.AysRoleUpdateService;
import org.ays.auth.util.exception.AysInvalidRoleStatusException;
import org.ays.auth.util.exception.AysPermissionNotExistException;
import org.ays.auth.util.exception.AysRoleAlreadyDeletedException;
import org.ays.auth.util.exception.AysRoleAlreadyExistsByNameException;
import org.ays.auth.util.exception.AysRoleAssignedToUserException;
import org.ays.auth.util.exception.AysRoleNotExistByIdException;
import org.ays.auth.util.exception.AysUserNotSuperAdminException;
import org.ays.auth.util.exception.AysInvalidRoleStatusException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -42,19 +42,24 @@ class AysRoleUpdateServiceImpl implements AysRoleUpdateService {

/**
* Updates an existing role identified by its ID.
* Performs checks to ensure the role name is unique and validates the existence of provided permissions.
* <p>
* This method performs checks to ensure the role name is unique and validates the existence of provided permissions.
* It also verifies that the role belongs to the same institution as the current user's institution.
* </p>
*
* @param id The ID of the role to update.
* @param updateRequest The request object containing updated data for the role.
* @throws AysRoleAlreadyExistsByNameException if a role with the same name already exists, excluding the current role ID.
* @throws AysPermissionNotExistException if any of the permission IDs provided do not exist.
* @throws AysUserNotSuperAdminException if the current user does not have super admin privileges required for assigning super permissions.
* @throws AysRoleNotExistByIdException if the role with the given ID does not exist or does not belong to the current user's institution.
*/
@Override
public void update(final String id,
final AysRoleUpdateRequest updateRequest) {

final AysRole role = roleReadPort.findById(id)
.filter(roleFromDatabase -> identity.getInstitutionId().equals(roleFromDatabase.getInstitution().getId()))
.orElseThrow(() -> new AysRoleNotExistByIdException(id));

this.checkExistingRoleNameByWithoutId(id, updateRequest.getName());
Expand All @@ -77,7 +82,7 @@ public void update(final String id,
* </p>
*
* @param id The ID of the role to activate.
* @throws AysRoleNotExistByIdException if a role with the given ID does not exist.
* @throws AysRoleNotExistByIdException if a role with the given ID does not exist.
* @throws AysInvalidRoleStatusException if the role's current status is not {@link AysRoleStatus#PASSIVE}.
*/
@Override
Expand Down
26 changes: 18 additions & 8 deletions src/test/java/org/ays/auth/controller/AysRoleControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@
import org.ays.util.AysMockResultMatchersBuilders;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -345,11 +347,11 @@ void givenValidRoleCreateRequest_whenUserUnauthorized_thenReturnAccessDeniedExce
"493268349068342",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec odio nec urna tincidunt fermentum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec odio nec urna tincidunt fermentum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec odio nec urna tincidunt fermentum."
})
void givenInvalidRoleCreateRequest_whenNameIsNotValid_thenReturnValidationError(String name) throws Exception {
void givenInvalidRoleCreateRequest_whenNameIsNotValid_thenReturnValidationError(String invalidName) throws Exception {
// Given
AysRoleCreateRequest mockCreateRequest = new AysRoleCreateRequestBuilder()
.withValidValues()
.withName(name)
.withName(invalidName)
.build();

// Then
Expand Down Expand Up @@ -427,11 +429,11 @@ void givenInvalidRoleCreateRequest_whenPermissionIdsAreEmpty_thenReturnValidatio
"",
"55aed4c4facb4b66bdb5-309eaaef4453"
})
void givenInvalidRoleCreateRequest_whenPermissionIdIsNotValid_thenReturnValidationError(String permissionId) throws Exception {
void givenInvalidRoleCreateRequest_whenPermissionIdIsNotValid_thenReturnValidationError(String invalidPermissionId) throws Exception {
// Given
AysRoleCreateRequest mockCreateRequest = new AysRoleCreateRequestBuilder()
.withValidValues()
.withPermissionIds(Set.of(permissionId))
.withPermissionIds(Set.of(invalidPermissionId))
.build();

// Then
Expand Down Expand Up @@ -544,17 +546,21 @@ void givenInvalidIdAndValidRoleUpdateRequest_whenIdNotValid_thenReturnValidation
@ValueSource(strings = {
"",
"A",
" Role",
"Role ",
"123Role",
".Role",
"% fsdh ",
"493268349068342",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec odio nec urna tincidunt fermentum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec odio nec urna tincidunt fermentum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla nec odio nec urna tincidunt fermentum."
})
void givenValidIdAndInvalidRoleUpdateRequest_whenNameIsNotValid_thenReturnValidationError(String name) throws Exception {
void givenValidIdAndInvalidRoleUpdateRequest_whenNameIsNotValid_thenReturnValidationError(String invalidName) throws Exception {

// Given
String mockId = AysRandomUtil.generateUUID();
AysRoleUpdateRequest mockUpdateRequest = new AysRoleUpdateRequestBuilder()
.withValidValues()
.withName(name)
.withName(invalidName)
.build();

// Then
Expand Down Expand Up @@ -632,17 +638,21 @@ void givenValidIdAndInvalidRoleUpdateRequest_whenPermissionIdsAreEmpty_thenRetur
}

@ParameterizedTest
@NullSource
@ValueSource(strings = {
"",
"55aed4c4facb4b66bdb5-309eaaef4453"
})
void givenValidIdAndInvalidRoleUpdateRequest_whenPermissionIdIsNotValid_thenReturnValidationError(String permissionId) throws Exception {
void givenValidIdAndInvalidRoleUpdateRequest_whenPermissionIdIsNotValid_thenReturnValidationError(String invalidPermissionId) throws Exception {

// Given
String mockId = AysRandomUtil.generateUUID();

Set<String> mockPermissionIds = new HashSet<>();
mockPermissionIds.add(invalidPermissionId);
AysRoleUpdateRequest mockUpdateRequest = new AysRoleUpdateRequestBuilder()
.withValidValues()
.withPermissionIds(Set.of(permissionId))
.withPermissionIds(mockPermissionIds)
.build();

// Then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ void givenValidIdAndRoleUpdateRequest_whenSuperRoleUpdated_thenReturnSuccess() t
.withoutId()
.withName("Admin Role 1")
.withPermissions(permissions)
.withInstitution(new InstitutionBuilder().withId(AysValidTestData.Admin.INSTITUTION_ID).build())
.withInstitution(new InstitutionBuilder().withId(AysValidTestData.SuperAdmin.INSTITUTION_ID).build())
.build()
);

Expand Down
4 changes: 3 additions & 1 deletion src/test/java/org/ays/auth/model/AysRoleBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.ays.common.model.TestDataBuilder;
import org.ays.common.util.AysRandomUtil;
import org.ays.institution.model.Institution;
import org.ays.institution.model.InstitutionBuilder;

import java.util.List;

Expand All @@ -23,7 +24,8 @@ public AysRoleBuilder withValidValues() {
.withId(AysRandomUtil.generateUUID())
.withName("admin")
.withPermissions(permissions)
.withStatus(AysRoleStatus.ACTIVE);
.withStatus(AysRoleStatus.ACTIVE)
.withInstitution(new InstitutionBuilder().withValidValues().build());
}

public AysRoleBuilder withId(String id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
import org.ays.auth.port.AysPermissionReadPort;
import org.ays.auth.port.AysRoleReadPort;
import org.ays.auth.port.AysRoleSavePort;
import org.ays.auth.util.exception.AysInvalidRoleStatusException;
import org.ays.auth.util.exception.AysPermissionNotExistException;
import org.ays.auth.util.exception.AysRoleAlreadyDeletedException;
import org.ays.auth.util.exception.AysRoleAlreadyExistsByNameException;
import org.ays.auth.util.exception.AysRoleAssignedToUserException;
import org.ays.auth.util.exception.AysRoleNotExistByIdException;
import org.ays.auth.util.exception.AysUserNotSuperAdminException;
import org.ays.auth.util.exception.AysInvalidRoleStatusException;
import org.ays.common.util.AysRandomUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
Expand All @@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

class AysRoleUpdateServiceImplTest extends AysUnitTest {

Expand All @@ -49,6 +50,7 @@ class AysRoleUpdateServiceImplTest extends AysUnitTest {
@Mock
private AysIdentity identity;


@Test
void givenIdAndRoleUpdateRequest_whenValuesValid_thenUpdateRoleWithSuperPermissions() {
// Given
Expand All @@ -65,6 +67,9 @@ void givenIdAndRoleUpdateRequest_whenValuesValid_thenUpdateRoleWithSuperPermissi
Mockito.when(roleReadPort.findById(Mockito.anyString()))
.thenReturn(Optional.of(mockRole));

Mockito.when(identity.getInstitutionId())
.thenReturn(mockRole.getInstitution().getId());

Mockito.when(roleReadPort.findByName(Mockito.anyString()))
.thenReturn(Optional.empty());

Expand Down Expand Up @@ -93,6 +98,9 @@ void givenIdAndRoleUpdateRequest_whenValuesValid_thenUpdateRoleWithSuperPermissi
Mockito.verify(roleReadPort, Mockito.times(1))
.findById(Mockito.anyString());

Mockito.verify(identity, Mockito.times(1))
.getInstitutionId();

Mockito.verify(roleReadPort, Mockito.times(1))
.findByName(Mockito.anyString());

Expand Down Expand Up @@ -125,6 +133,9 @@ void givenIdAndRoleUpdateRequest_whenValuesValid_thenUpdateRole() {
Mockito.when(roleReadPort.findById(Mockito.anyString()))
.thenReturn(Optional.of(mockRole));

Mockito.when(identity.getInstitutionId())
.thenReturn(mockRole.getInstitution().getId());

Mockito.when(roleReadPort.findByName(Mockito.anyString()))
.thenReturn(Optional.empty());

Expand All @@ -143,9 +154,6 @@ void givenIdAndRoleUpdateRequest_whenValuesValid_thenUpdateRole() {
Mockito.when(identity.isSuperAdmin())
.thenReturn(false);

Mockito.when(identity.getInstitutionId())
.thenReturn(AysRandomUtil.generateUUID());

Mockito.when(roleSavePort.save(Mockito.any(AysRole.class)))
.thenReturn(Mockito.mock(AysRole.class));

Expand All @@ -156,6 +164,9 @@ void givenIdAndRoleUpdateRequest_whenValuesValid_thenUpdateRole() {
Mockito.verify(roleReadPort, Mockito.times(1))
.findById(Mockito.anyString());

Mockito.verify(identity, Mockito.times(1))
.getInstitutionId();

Mockito.verify(roleReadPort, Mockito.times(1))
.findByName(Mockito.anyString());

Expand Down Expand Up @@ -194,6 +205,57 @@ void givenValidIdAndRoleUpdateRequest_whenRoleNotFound_thenThrowAysRoleNotExistB
Mockito.verify(roleReadPort, Mockito.times(1))
.findById(Mockito.anyString());

Mockito.verify(identity, Mockito.never())
.getInstitutionId();

Mockito.verify(roleReadPort, Mockito.never())
.findByName(Mockito.anyString());

Mockito.verify(permissionReadPort, Mockito.never())
.findAllByIds(Mockito.anySet());

Mockito.verify(identity, Mockito.never())
.isSuperAdmin();

Mockito.verify(identity, Mockito.never())
.getUserId();

Mockito.verify(roleSavePort, Mockito.never())
.save(Mockito.any(AysRole.class));
}

@Test
void givenValidIdAndRoleUpdateRequest_whenRoleNotMatchedWithInstitution_thenThrowAysRoleNotExistByIdException() {
// Given
String mockId = AysRandomUtil.generateUUID();
AysRoleUpdateRequest mockUpdateRequest = new AysRoleUpdateRequestBuilder()
.withValidValues()
.build();

// When
AysRole mockRole = new AysRoleBuilder()
.withValidValues()
.withId(mockId)
.build();
Mockito.when(roleReadPort.findById(Mockito.anyString()))
.thenReturn(Optional.of(mockRole));

Mockito.when(identity.getInstitutionId())
.thenReturn(UUID.randomUUID().toString());

// Then
Assertions.assertThrows(
AysRoleNotExistByIdException.class,
() -> roleUpdateService.update(mockId, mockUpdateRequest)
);

// Verify
Mockito.verify(roleReadPort, Mockito.times(1))
.findById(Mockito.anyString());

Mockito.verify(identity, Mockito.times(1))
.getInstitutionId();

Mockito.verify(roleReadPort, Mockito.never())
.findByName(Mockito.anyString());

Expand Down Expand Up @@ -226,6 +288,9 @@ void givenValidIdAndRoleUpdateRequest_whenNameAlreadyExist_thenThrowAysRoleAlrea
Mockito.when(roleReadPort.findById(Mockito.anyString()))
.thenReturn(Optional.of(mockRole));

Mockito.when(identity.getInstitutionId())
.thenReturn(mockRole.getInstitution().getId());

Mockito.when(roleReadPort.findByName(Mockito.anyString()))
.thenReturn(Optional.of(Mockito.mock(AysRole.class)));

Expand All @@ -239,6 +304,9 @@ void givenValidIdAndRoleUpdateRequest_whenNameAlreadyExist_thenThrowAysRoleAlrea
Mockito.verify(roleReadPort, Mockito.times(1))
.findById(Mockito.anyString());

Mockito.verify(identity, Mockito.times(1))
.getInstitutionId();

Mockito.verify(roleReadPort, Mockito.times(1))
.findByName(Mockito.anyString());

Expand Down Expand Up @@ -271,6 +339,9 @@ void givenValidIdAndRoleUpdateRequest_whenRequestHasSuperPermissionsAndUserIsNot
Mockito.when(roleReadPort.findById(Mockito.anyString()))
.thenReturn(Optional.of(mockRole));

Mockito.when(identity.getInstitutionId())
.thenReturn(mockRole.getInstitution().getId());

Mockito.when(roleReadPort.findByName(Mockito.anyString()))
.thenReturn(Optional.empty());

Expand Down Expand Up @@ -302,6 +373,9 @@ void givenValidIdAndRoleUpdateRequest_whenRequestHasSuperPermissionsAndUserIsNot
Mockito.verify(roleReadPort, Mockito.times(1))
.findById(Mockito.anyString());

Mockito.verify(identity, Mockito.times(1))
.getInstitutionId();

Mockito.verify(roleReadPort, Mockito.times(1))
.findByName(Mockito.anyString());

Expand Down Expand Up @@ -335,6 +409,9 @@ void givenValidIdAndRoleUpdateRequest_whenPermissionsNotExists_thenThrowAysPermi
Mockito.when(roleReadPort.findById(Mockito.anyString()))
.thenReturn(Optional.of(mockRole));

Mockito.when(identity.getInstitutionId())
.thenReturn(mockRole.getInstitution().getId());

Mockito.when(roleReadPort.findByName(Mockito.anyString()))
.thenReturn(Optional.empty());

Expand All @@ -351,6 +428,9 @@ void givenValidIdAndRoleUpdateRequest_whenPermissionsNotExists_thenThrowAysPermi
Mockito.verify(roleReadPort, Mockito.times(1))
.findById(Mockito.anyString());

Mockito.verify(identity, Mockito.times(1))
.getInstitutionId();

Mockito.verify(roleReadPort, Mockito.times(1))
.findByName(Mockito.anyString());

Expand Down

0 comments on commit 7311f7a

Please sign in to comment.