Skip to content

Commit

Permalink
chore: add tests for update endorsement status (#117)
Browse files Browse the repository at this point in the history
* chore: create handleIllegalArgumentException

* chore: unit tests for updateEndorsementStatus

* fix: remove unnecessary stubbings

* add boilerplate code for feat: update-endorsement-status

* disable unit tests for update-endorsement-status for now

* fix: switch to InsufficientAuthenticationException (401, Unauthorized) if user in not superuser

* chore: add integration tests for update endorsement status

* fix: code formatting

* fix: assign userId instead of skillId in createEndorsement

* move user role setup to a common function named setupUpdateEndorsementTests

* fix: use superuser cookie in test 'Return 401 when request is made without using superuser cookie'

* fix: 'detached entity passed to persist' exception for integration tests

* fix: Formatting

* chore: update message in case of Unauthorized access for updateEndorsementStatus

* chore: Add more assertions to `UpdateEndorsementStatusGivenEndorsementId`

* fix: use correct pathParam format and clearer message for unauthorized access

* chore: update exception messages for update-endorsement-status

* fix: update exceptions and fix test cases

* chore: update tests according to the feature

* chore: add more test cases for endorsement already updated case

* chore: enable tests for update endorsement
  • Loading branch information
Atifsid authored May 16, 2024
1 parent 67524a7 commit c6f3764
Show file tree
Hide file tree
Showing 2 changed files with 290 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ private void cleanUp() {
userRepository.deleteAll();
}

private UUID createEndorsementModel(Boolean isStatusPending) {
EndorsementStatus endorsementStatus;
if (isStatusPending) {
endorsementStatus = EndorsementStatus.PENDING;
} else {
endorsementStatus = EndorsementStatus.APPROVED;
}
EndorsementModel endorsementModel =
EndorsementModel.builder().status(endorsementStatus).build();
return endorsementRepository.save(endorsementModel).getId();
}

@Test
@Disabled
@DisplayName("Fetch all the endorsements")
Expand Down Expand Up @@ -479,4 +491,99 @@ public void itShouldReturn401OnEndorsementSearchWithoutCookie() {
equalTo(
"The access token provided is expired, revoked, malformed, or invalid for other reasons."));
}

@Test
@DisplayName(
"Return 200, when request is made using super user cookie and status is APPROVED/REJECTED")
public void
itShouldReturn200OnUpdateEndorsementStatusWithSuperUserCookieAndAcceptOrRejectEndorsementStatus() {
UUID endorsementId = createEndorsementModel(true);
Response response =
given()
.cookies(RestAPIHelper.getSuperUserCookie())
.queryParam("status", EndorsementStatus.APPROVED.name())
.patch("/v1/endorsements/{id}", endorsementId);

response
.then()
.statusCode(200)
.body("data", equalTo(null))
.body("message", equalTo("Successfully updated endorsement status"));
}

@Test
@DisplayName(
"Return 403, when request is made without using super user cookie and status is APPROVED/REJECTED")
public void
itShouldReturn403OnUpdateEndorsementStatusWithOutSuperUserCookieAndAcceptOrRejectEndorsementStatus() {
UUID endorsementId = createEndorsementModel(true);
Response response =
given()
.cookies(RestAPIHelper.getUserCookie())
.queryParam("status", EndorsementStatus.APPROVED.name())
.patch("/v1/endorsements/{id}", endorsementId);

response
.then()
.statusCode(403)
.body("data", equalTo(null))
.body("message", equalTo("Unauthorized, Access is only available to super users"));
}

@Test
@DisplayName(
"Return 400, when request is made with using super user cookie and status is invalid")
public void
itShouldReturn400OnUpdateEndorsementStatusWithSuperUserCookieAndEndorsementStatusIsInvalid() {
UUID endorsementId = createEndorsementModel(true);
Response response =
given()
.cookies(RestAPIHelper.getSuperUserCookie())
.queryParam("status", "invalid-status")
.patch("/v1/endorsements/{id}", endorsementId);

response
.then()
.statusCode(400)
.body("data", equalTo(null))
.body("message", equalTo("Invalid parameter endorsement status: invalid-status"));
}

@Test
@DisplayName(
"Return 400, when request is made with using super user cookie and status is PENDING")
public void
itShouldReturn400OnUpdateEndorsementStatusWithSuperUserCookieAndEndorsementStatusIsPending() {
UUID endorsementId = createEndorsementModel(true);
Response response =
given()
.cookies(RestAPIHelper.getSuperUserCookie())
.queryParam("status", EndorsementStatus.PENDING.name())
.patch("/v1/endorsements/{id}", endorsementId);

response
.then()
.statusCode(400)
.body("data", equalTo(null))
.body("message", equalTo("Invalid parameter endorsement status: PENDING"));
}

@Test
@DisplayName(
"Return 409, when request is made with using super user cookie and endorsement is already updated")
public void
itShouldReturn409OnUpdateEndorsementStatusWithSuperUserCookieAndEndorsementAlreadyUpdated() {
UUID endorsementId = createEndorsementModel(false);
Response response =
given()
.cookies(RestAPIHelper.getSuperUserCookie())
.queryParam("status", EndorsementStatus.APPROVED.name())
.patch("/v1/endorsements/{id}", endorsementId);

response
.then()
.statusCode(409)
.body("data", equalTo(null))
.body("message", equalTo("Endorsement is already updated. Cannot modify status"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import com.RDS.skilltree.Endorsement.EndorsementDRO;
import com.RDS.skilltree.Endorsement.EndorsementDTO;
import com.RDS.skilltree.Endorsement.EndorsementModel;
import com.RDS.skilltree.Endorsement.EndorsementModelFromJSON;
import com.RDS.skilltree.Endorsement.EndorsementRepository;
import com.RDS.skilltree.Endorsement.EndorsementServiceImpl;
import com.RDS.skilltree.Common.Response.GenericResponse;
import com.RDS.skilltree.Endorsement.*;
import com.RDS.skilltree.Exceptions.EntityAlreadyExistsException;
import com.RDS.skilltree.Exceptions.InvalidParameterException;
import com.RDS.skilltree.Exceptions.NoEntityException;
import com.RDS.skilltree.Skill.SkillModel;
import com.RDS.skilltree.Skill.SkillRepository;
import com.RDS.skilltree.User.UserModel;
import com.RDS.skilltree.User.UserRepository;
import com.RDS.skilltree.User.UserRole;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.persistence.EntityNotFoundException;
Expand All @@ -22,6 +21,7 @@
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand All @@ -34,6 +34,9 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.util.ReflectionTestUtils;

@ExtendWith(MockitoExtension.class)
Expand All @@ -48,12 +51,30 @@ public class EndorsementServiceTest {

@InjectMocks @Autowired private EndorsementServiceImpl endorsementService;

@Mock private Authentication auth;

@BeforeEach
public void setUp() {
ReflectionTestUtils.setField(
endorsementService, "dummyEndorsementDataPath", "dummy-data/endorsements.json");
}

@AfterEach
public void clearSecurityContext() {
SecurityContextHolder.clearContext();
}

private void setupUpdateEndorsementTests(Boolean useSuperUserRole) {
UserModel userModel = new UserModel();
if (useSuperUserRole) {
userModel.setRole(UserRole.SUPERUSER);
} else {
userModel.setRole(UserRole.USER);
}
when(auth.getPrincipal()).thenReturn(userModel);
SecurityContextHolder.getContext().setAuthentication(auth);
}

@Test
public void itShouldGetEndorsementsById() {
UUID endorsementId = UUID.randomUUID();
Expand Down Expand Up @@ -588,4 +609,160 @@ void testCreateEndorsementWithInvalidSkill() {
// Verify that save method is not called
verify(endorsementRepository, never()).save(any(EndorsementModel.class));
}

@Test
@DisplayName(
"Return unauthorized access, given user is not a super user to update endorsement status")
public void itShouldReturnUnauthorizedGivenUserIsNotSuperUser() {
setupUpdateEndorsementTests(false);

UUID endorsementId = UUID.randomUUID();
String status = EndorsementStatus.APPROVED.name();

AccessDeniedException exception =
assertThrows(
AccessDeniedException.class,
() -> endorsementService.updateEndorsementStatus(endorsementId, status));
assertEquals("Unauthorized, Access is only available to super users", exception.getMessage());
verify(endorsementRepository, never()).save(any(EndorsementModel.class));
}

@Test
@DisplayName("Return invalid status given status is pending")
public void itShouldReturnInvalidStatusGivenEndorsementStatusIsPending() {
setupUpdateEndorsementTests(true);

UUID endorsementId = UUID.randomUUID();
String status = EndorsementStatus.PENDING.name();

InvalidParameterException exception =
assertThrows(
InvalidParameterException.class,
() -> endorsementService.updateEndorsementStatus(endorsementId, status));
assertEquals("Invalid parameter endorsement status: " + status, exception.getMessage());
verify(endorsementRepository, never()).save(any(EndorsementModel.class));
}

@Test
@DisplayName("Return invalid status given status is invalid")
public void itShouldReturnInvalidStatusGivenInvalidEndorsementStatus() {
setupUpdateEndorsementTests(true);

UUID endorsementId = UUID.randomUUID();
String status = "invalid-status";

InvalidParameterException exception =
assertThrows(
InvalidParameterException.class,
() -> endorsementService.updateEndorsementStatus(endorsementId, status));
assertEquals("Invalid parameter endorsement status: " + status, exception.getMessage());
verify(endorsementRepository, never()).save(any(EndorsementModel.class));
}

@Test
@DisplayName("Return cannot modify status given status is already updated")
public void itShouldThrowEntityAlreadyExistsExceptionGivenEndorsementIsUpdated() {
setupUpdateEndorsementTests(true);

UUID userId = UUID.randomUUID();
UUID skillId = UUID.randomUUID();
UUID endorsementId = UUID.randomUUID();

UserModel mockUser = UserModel.builder().id(userId).build();
SkillModel mockSkill = SkillModel.builder().id(skillId).build();
EndorsementModel mockEndorsement =
EndorsementModel.builder()
.id(endorsementId)
.status(EndorsementStatus.APPROVED)
.user(mockUser)
.skill(mockSkill)
.build();
mockEndorsement.setCreatedAt(Instant.now());
mockEndorsement.setUpdatedAt(Instant.now());
mockEndorsement.setCreatedBy(mockUser);
mockEndorsement.setUpdatedBy(mockUser);

when(endorsementRepository.findById(endorsementId)).thenReturn(Optional.of(mockEndorsement));

EntityAlreadyExistsException exception =
assertThrows(
EntityAlreadyExistsException.class,
() ->
endorsementService.updateEndorsementStatus(
endorsementId, EndorsementStatus.APPROVED.name()));
assertEquals("Endorsement is already updated. Cannot modify status", exception.getMessage());
verify(endorsementRepository, never()).save(any(EndorsementModel.class));
}

@Test
@DisplayName("Return endorsement not found given an unknown endorsement id")
public void itShouldReturnEndorsementNotFoundGivenUnknownEndorsementId() {
setupUpdateEndorsementTests(true);

UUID nonExistentEndorsementId = UUID.randomUUID();
String status = EndorsementStatus.APPROVED.name();

when(endorsementRepository.findById(nonExistentEndorsementId)).thenReturn(Optional.empty());

NoEntityException exception =
assertThrows(
NoEntityException.class,
() -> endorsementService.updateEndorsementStatus(nonExistentEndorsementId, status));
assertEquals(
"No endorsement with id " + nonExistentEndorsementId + " was found",
exception.getMessage());
verify(endorsementRepository, never()).save(any(EndorsementModel.class));
}

@Test
@DisplayName(
"Update endorsement status given a valid endorsement id and status is approved or rejected")
public void itShouldUpdateEndorsementStatusGivenEndorsementIdAndStatusApprovedOrRejected() {
setupUpdateEndorsementTests(true);

UUID userId = UUID.randomUUID();
UUID skillId = UUID.randomUUID();
UUID endorsementId = UUID.randomUUID();
EndorsementStatus status = EndorsementStatus.APPROVED;

UserModel mockUser = UserModel.builder().id(userId).build();
SkillModel mockSkill = SkillModel.builder().id(skillId).build();
EndorsementModel mockEndorsement =
EndorsementModel.builder()
.id(endorsementId)
.status(EndorsementStatus.PENDING)
.user(mockUser)
.skill(mockSkill)
.build();
mockEndorsement.setCreatedAt(Instant.now());
mockEndorsement.setUpdatedAt(Instant.now());
mockEndorsement.setCreatedBy(mockUser);
mockEndorsement.setUpdatedBy(mockUser);

when(endorsementRepository.findById(endorsementId)).thenReturn(Optional.of(mockEndorsement));

GenericResponse<Void> result =
endorsementService.updateEndorsementStatus(endorsementId, status.name());
assertEquals("Successfully updated endorsement status", result.getMessage());

verify(endorsementRepository, times(1)).save(any(EndorsementModel.class));

EndorsementModel updatedMockEndorsement =
EndorsementModel.builder()
.id(endorsementId)
.user(mockUser)
.skill(mockSkill)
.status(EndorsementStatus.APPROVED)
.build();
mockEndorsement.setCreatedAt(Instant.now());
mockEndorsement.setUpdatedAt(Instant.now());
mockEndorsement.setCreatedBy(mockUser);
mockEndorsement.setUpdatedBy(mockUser);

when(endorsementRepository.findById(endorsementId))
.thenReturn(Optional.of(updatedMockEndorsement));
Optional<EndorsementModel> updatedEndorsement = endorsementRepository.findById(endorsementId);
assertTrue(updatedEndorsement.isPresent());
assertEquals(EndorsementStatus.APPROVED, updatedEndorsement.get().getStatus());
}
}

0 comments on commit c6f3764

Please sign in to comment.