Skip to content

Commit

Permalink
Merge pull request #21 from bcgov/feature/eas-13
Browse files Browse the repository at this point in the history
Creates endpoint for fetching student merges
  • Loading branch information
eckermania authored Oct 22, 2024
2 parents b069850 + 216262e commit b8849e1
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public enum EventType {
INITIATED, //Default. Used by BaseOrchestrator.
MARK_SAGA_COMPLETE, //Default. Used by BaseOrchestrator.
GET_PAGINATED_SCHOOLS,
GET_MERGED_STUDENT_IDS,
CREATE_STUDENT_REGISTRATION,
GET_STUDENT_REGISTRATION,
PUBLISH_STUDENT_REGISTRATION,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ public enum TopicsEnum {
EAS_API_TOPIC,
INSTITUTE_API_TOPIC,
EAS_EVENTS_TOPIC,
PEN_SERVICES_API_TOPIC,
CREATE_STUDENT_REGISTRATION_SAGA_TOPIC
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ca.bc.gov.educ.eas.api.controller.v1;

import ca.bc.gov.educ.eas.api.endpoint.v1.StudentMergeEndpoint;
import ca.bc.gov.educ.eas.api.service.v1.StudentMergeService;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@Slf4j
@RestController
public class StudentMergeController implements StudentMergeEndpoint {
private final StudentMergeService studentMergeService;

public StudentMergeController(StudentMergeService studentMergeService){
this.studentMergeService = studentMergeService;
}

@Override
public List<StudentMerge> getMergedStudentsForDateRange(String createDateStart, String createDateEnd){
return studentMergeService.getMergedStudentsForDateRange(createDateStart, createDateEnd);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ca.bc.gov.educ.eas.api.endpoint.v1;

import ca.bc.gov.educ.eas.api.constants.v1.URL;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@RequestMapping(URL.BASE_URL + "/student-merges")
public interface StudentMergeEndpoint {

@GetMapping()
@PreAuthorize("hasAuthority('SCOPE_READ_EAS_STUDENT')")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
@Tag(name = "PEN Records", description = "Endpoints to retrieve PEN records.")
List<StudentMerge> getMergedStudentsForDateRange(@RequestParam(name = "createDateStart") String createDateStart, @RequestParam(name = "createDateEnd") String createDateEnd) throws JsonProcessingException;

}
24 changes: 24 additions & 0 deletions api/src/main/java/ca/bc/gov/educ/eas/api/rest/RestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import ca.bc.gov.educ.eas.api.properties.ApplicationProperties;
import ca.bc.gov.educ.eas.api.struct.Event;
import ca.bc.gov.educ.eas.api.struct.external.institute.v1.*;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import ca.bc.gov.educ.eas.api.util.JsonUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
Expand Down Expand Up @@ -45,6 +46,8 @@ public class RestUtils {
private final Map<String, FacilityTypeCode> facilityTypeCodesMap = new ConcurrentHashMap<>();
private final Map<String, SchoolCategoryCode> schoolCategoryCodesMap = new ConcurrentHashMap<>();
public static final String PAGE_SIZE = "pageSize";
public static final String CREATE_DATE_START = "createDateStart";
public static final String CREATE_DATE_END = "createDateEnd";
private final WebClient webClient;
private final MessagePublisher messagePublisher;
private final ObjectMapper objectMapper = new ObjectMapper();
Expand Down Expand Up @@ -324,4 +327,25 @@ public List<School> getAllSchoolList(UUID correlationID) {
throw new EasAPIRuntimeException(NATS_TIMEOUT + correlationID + ex.getMessage());
}
}

public List<StudentMerge> getMergedStudentsForDateRange(UUID correlationID, String createDateStart, String createDateEnd) {
try {
final TypeReference<Event> refEventResponse = new TypeReference<>() {};
final TypeReference<List<StudentMerge>> refMergedStudentResponse = new TypeReference<>() {};
Object event = Event.builder().sagaId(correlationID).eventType(EventType.GET_MERGED_STUDENT_IDS).eventPayload(CREATE_DATE_START.concat("=").concat(createDateStart).concat("&").concat(CREATE_DATE_END).concat("=").concat(createDateEnd)).build();
val responseMessage = this.messagePublisher.requestMessage(TopicsEnum.PEN_SERVICES_API_TOPIC.toString(), JsonUtil.getJsonBytesFromObject(event)).completeOnTimeout(null, 120, TimeUnit.SECONDS).get();
if (responseMessage == null) {
log.error("Received null response from PEN SERVICES API for correlationID: {}", correlationID);
throw new EasAPIRuntimeException(NATS_TIMEOUT + correlationID);
} else {
val eventResponse = objectMapper.readValue(responseMessage.getData(), refEventResponse);
return objectMapper.readValue(eventResponse.getEventPayload(), refMergedStudentResponse);
}

} catch (final Exception ex) {
log.error("Error occurred calling PEN SERVICES API service :: " + ex.getMessage());
Thread.currentThread().interrupt();
throw new EasAPIRuntimeException(ex.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package ca.bc.gov.educ.eas.api.service.v1;

import ca.bc.gov.educ.eas.api.rest.RestUtils;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

@Service
@Slf4j
public class StudentMergeService {

private final RestUtils restUtils;

@Autowired
public StudentMergeService(RestUtils restUtils){
this.restUtils = restUtils;
}

public List<StudentMerge> getMergedStudentsForDateRange(String createDateStart, String createDateEnd){
UUID correlationID = UUID.randomUUID();
log.info("Fetching student merge records created between {} and {} with correlation ID: {}", createDateStart, createDateEnd, correlationID);
return restUtils.getMergedStudentsForDateRange(correlationID, createDateStart, createDateEnd);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package ca.bc.gov.educ.eas.api.struct.v1;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

import java.io.Serializable;

/**
* The type Student merge.
*/
@EqualsAndHashCode(callSuper = true)
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class StudentMerge extends BaseRequest implements Serializable {
/**
* The constant serialVersionUID.
*/
private static final long serialVersionUID = 1L;

/**
* The Student merge id.
*/
@NotNull(message = "Student Merge ID cannot be null")
String studentMergeID;
/**
* The Student id.
*/
@NotNull(message = "Student ID cannot be null.")
String studentID;
/**
* The Merge student id.
*/
@NotNull(message = "Merge Student ID cannot be null.")
String mergeStudentID;
/**
* The Student merge direction code.
*/
@NotNull(message = "Student Merge Direction Code cannot be null.")
String studentMergeDirectionCode;
/**
* The Student merge source code.
*/
@NotNull(message = "Student Merge Source Code cannot be null.")
String studentMergeSourceCode;
}
36 changes: 36 additions & 0 deletions api/src/test/java/ca/bc/gov/educ/eas/api/rest/RestUtilsTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ca.bc.gov.educ.eas.api.rest;

import ca.bc.gov.educ.eas.api.exception.EasAPIRuntimeException;
import ca.bc.gov.educ.eas.api.messaging.MessagePublisher;
import ca.bc.gov.educ.eas.api.properties.ApplicationProperties;
import ca.bc.gov.educ.eas.api.struct.external.institute.v1.District;
Expand All @@ -14,6 +15,9 @@
import org.springframework.web.reactive.function.client.WebClient;

import java.util.*;
import java.util.concurrent.CompletableFuture;

import static org.junit.jupiter.api.Assertions.*;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
Expand Down Expand Up @@ -274,4 +278,36 @@ void testGetSchoolFromMincodeMap_WhenApiCallSucceeds_ShouldReturnSchool() {
assertEquals(school1, result.get());
}

@Test
void testGetAllMergedStudentsInRange_WhenRequestTimesOut_ShouldThrowEASAPIRuntimeException() {
UUID correlationID = UUID.randomUUID();
String createStartDate = "2024-02-01T00:00:00";
String createEndDate = "2024-09-01T00:00:00";

when(messagePublisher.requestMessage(anyString(), any(byte[].class)))
.thenReturn(CompletableFuture.completedFuture(null));

EasAPIRuntimeException exception = assertThrows(
EasAPIRuntimeException.class,
() -> restUtils.getMergedStudentsForDateRange(correlationID, createStartDate, createEndDate)
);

assertEquals(RestUtils.NATS_TIMEOUT + correlationID, exception.getMessage());
}

@Test
void testGetMergedStudentsInRange_WhenExceptionOccurs_ShouldThrowEASAPIRuntimeException() {
UUID correlationID = UUID.randomUUID();
String createStartDate = "2024-02-01T00:00:00";
String createEndDate = "2024-09-01T00:00:00";
Exception mockException = new Exception("exception");

when(messagePublisher.requestMessage(anyString(), any(byte[].class)))
.thenReturn(CompletableFuture.failedFuture(mockException));

assertThrows(
EasAPIRuntimeException.class,
() -> restUtils.getMergedStudentsForDateRange(correlationID, createStartDate, createEndDate)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package ca.bc.gov.educ.eas.api.service.v1;

import ca.bc.gov.educ.eas.api.exception.EasAPIRuntimeException;
import ca.bc.gov.educ.eas.api.rest.RestUtils;
import ca.bc.gov.educ.eas.api.struct.v1.StudentMerge;
import lombok.val;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.List;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;

class StudentMergeServiceTest {

@Mock
private RestUtils restUtils;

@InjectMocks
private StudentMergeService studentMergeService;

@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}

@Test
void testGetMergedStudentsForDateRange_ShouldReturnMergedStudents() {
String createDateStart = "2024-02-01T00:00:00";
String createDateEnd = "2024-09-01T00:00:00";
List<StudentMerge> mockMergedStudents = List.of(
StudentMerge.builder().studentMergeID(UUID.randomUUID().toString()).studentID(UUID.randomUUID().toString()).mergeStudentID(UUID.randomUUID().toString()).studentMergeDirectionCode("FROM").studentMergeSourceCode("MI").build(),
StudentMerge.builder().studentMergeID(UUID.randomUUID().toString()).studentID(UUID.randomUUID().toString()).mergeStudentID(UUID.randomUUID().toString()).studentMergeDirectionCode("TO").studentMergeSourceCode("API").build()
);
when(restUtils.getMergedStudentsForDateRange(any(UUID.class), eq(createDateStart), eq(createDateEnd)))
.thenReturn(mockMergedStudents);

val result = studentMergeService.getMergedStudentsForDateRange(createDateStart, createDateEnd);

assertEquals(mockMergedStudents, result);
verify(restUtils, times(1)).getMergedStudentsForDateRange(any(UUID.class), eq(createDateStart), eq(createDateEnd)); // Use any(UUID.class) here
}

@Test
void testGetMergedStudentsForDateRange_WhenRestUtilsThrowsException_ShouldThrowEasAPIRuntimeException() {
String createDateStart = "2024-02-01T00:00:00";
String createDateEnd = "2024-09-01T00:00:00";

when(restUtils.getMergedStudentsForDateRange(any(UUID.class), eq(createDateStart), eq(createDateEnd)))
.thenThrow(new EasAPIRuntimeException("PEN Services API failed"));

assertThrows(EasAPIRuntimeException.class, () -> studentMergeService.getMergedStudentsForDateRange(createDateStart, createDateEnd));
verify(restUtils, times(1)).getMergedStudentsForDateRange(any(UUID.class), eq(createDateStart), eq(createDateEnd)); // Use any(UUID.class) here
}
}

0 comments on commit b8849e1

Please sign in to comment.