Skip to content

Commit

Permalink
Feature/grad2 3060 - gdc messaging (#701)
Browse files Browse the repository at this point in the history
* start of gdc messaging

* gdc messaging

* use grad student service

* clean

* extend base integration test

* required fields for grad student record payload

* clean

* test
  • Loading branch information
alexmcdermid authored Nov 20, 2024
1 parent b3301c0 commit 698092f
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public enum Topics {
* GradStatus events topic.
*/
GRAD_STATUS_EVENT_TOPIC,
GRAD_STUDENT_API_FETCH_GRAD_STATUS_TOPIC
GRAD_STUDENT_API_FETCH_GRAD_STATUS_TOPIC,
GRAD_STUDENT_API_FETCH_GRAD_STUDENT_TOPIC,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package ca.bc.gov.educ.api.gradstudent.messaging.jetstream;

import ca.bc.gov.educ.api.gradstudent.constant.Topics;
import ca.bc.gov.educ.api.gradstudent.exception.EntityNotFoundException;
import ca.bc.gov.educ.api.gradstudent.model.dc.Event;
import ca.bc.gov.educ.api.gradstudent.model.dc.GradStatusPayload;
import ca.bc.gov.educ.api.gradstudent.model.dc.GradStudentRecordPayload;
import ca.bc.gov.educ.api.gradstudent.model.dto.messaging.GradStudentRecord;
import ca.bc.gov.educ.api.gradstudent.service.GradStudentService;
import ca.bc.gov.educ.api.gradstudent.util.EducGradStudentApiConstants;
import ca.bc.gov.educ.api.gradstudent.util.EducGradStudentApiUtils;
import ca.bc.gov.educ.api.gradstudent.util.JsonUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.nats.client.*;
import lombok.val;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.UUID;

@Component
public class FetchGradStudentRecordSubscriber implements MessageHandler {

private final Connection natsConnection;
private Dispatcher dispatcher;
private final GradStudentService gradStudentService;
public static final String RESPONDING_BACK_TO_NATS_ON_CHANNEL = "responding back to NATS on {} channel ";
public static final String PAYLOAD_LOG = "payload is :: {}";



private static final String TOPIC = Topics.GRAD_STUDENT_API_FETCH_GRAD_STUDENT_TOPIC.toString();
private static final Logger log = LoggerFactory.getLogger(FetchGradStudentRecordSubscriber.class);

@Autowired
public FetchGradStudentRecordSubscriber(final Connection natsConnection, GradStudentService gradStudentService, EducGradStudentApiConstants constants) {
this.natsConnection = natsConnection;
this.gradStudentService = gradStudentService;
}

@PostConstruct
public void subscribe() {
this.dispatcher = this.natsConnection.createDispatcher(this);
this.dispatcher.subscribe(TOPIC);
}

@Override
public void onMessage(Message message) {
val eventString = new String(message.getData());
log.debug("Received message: {}", eventString);
String response;

try {
Event event = JsonUtil.getJsonObjectFromString(Event.class, eventString);
log.info("received GET_STUDENT event :: {}", event.getSagaId());
log.trace(PAYLOAD_LOG, event.getEventPayload());
UUID studentId = JsonUtil.getJsonObjectFromString(UUID.class, event.getEventPayload());
GradStudentRecord studentRecord = gradStudentService.getGraduationStudentRecord(studentId);
response = getResponse(studentRecord);
log.info(RESPONDING_BACK_TO_NATS_ON_CHANNEL, message.getReplyTo() != null ? message.getReplyTo() : event.getReplyTo());
this.natsConnection.publish(message.getReplyTo(), response.getBytes());
} catch (Exception e) {
log.error("Error while processing GET_STUDENT event", e);
}
}

private String getResponse(GradStudentRecord studentRecord) throws JsonProcessingException {
GradStudentRecordPayload gradStudentRecordPayload = GradStudentRecordPayload.builder()
.program(studentRecord.getProgram())
.programCompletionDate(studentRecord.getProgramCompletionDate() != null ? EducGradStudentApiUtils.formatDate(studentRecord.getProgramCompletionDate()) : null)
.schoolOfRecord(studentRecord.getSchoolOfRecord())
.build();
return JsonUtil.getJsonStringFromObject(gradStudentRecordPayload);
}

private String getErrorResponse(Exception e) {
String ex = (e instanceof EntityNotFoundException) ? "not found" : "error";
GradStatusPayload gradStatusPayload = GradStatusPayload.builder()
.exception(ex)
.build();
try {
return JsonUtil.getJsonStringFromObject(gradStatusPayload);
} catch (JsonProcessingException exc) {
log.error("Error while serializing error response", exc);
return "{\"program\": \"\", \"programCompletionDate\": \"\", \"schoolOfRecord\": \"\", \"exception\": \"JSON Parsing exception\"}";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package ca.bc.gov.educ.api.gradstudent.model.dc;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class GradStudentRecordPayload {

private String exception;
private String program;
private String programCompletionDate;
private String schoolOfRecord;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ca.bc.gov.educ.api.gradstudent.model.dto.messaging;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Date;
import java.util.UUID;

@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class GradStudentRecord {

private UUID studentID;
private String program;
private Date programCompletionDate;
private String schoolOfRecord;

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ca.bc.gov.educ.api.gradstudent.service;

import ca.bc.gov.educ.api.gradstudent.exception.EntityNotFoundException;
import ca.bc.gov.educ.api.gradstudent.model.dto.*;
import ca.bc.gov.educ.api.gradstudent.model.dto.messaging.GradStudentRecord;
import ca.bc.gov.educ.api.gradstudent.model.entity.GraduationStudentRecordEntity;
import ca.bc.gov.educ.api.gradstudent.model.entity.GraduationStudentRecordView;
import ca.bc.gov.educ.api.gradstudent.model.transformer.GraduationStatusTransformer;
Expand Down Expand Up @@ -50,6 +52,7 @@ public class GradStudentService {
private static final String PAGE_NUMBER="pageNumber";
private static final String PAGE_SIZE="pageSize";
private static final String SEARCH_CRITERIA_LIST = "searchCriteriaList";
private static final String STD_NOT_FOUND_MSG = "Student with ID: %s not found";

final EducGradStudentApiConstants constants;
final WebClient webClient;
Expand Down Expand Up @@ -417,4 +420,18 @@ public List<UUID> getStudentIDsBySearchCriteriaOrAll(StudentSearchRequest search
}
return result;
}

/**
* Returns a condensed version of GraduationStudentRecord for GDC
* @param studentID
* @return
* @throws EntityNotFoundException
*/
public GradStudentRecord getGraduationStudentRecord(UUID studentID) {
GradStudentRecord response = graduationStatusRepository.findByStudentID(studentID, GradStudentRecord.class);
if (response != null) {
return response;
}
throw new EntityNotFoundException(String.format(STD_NOT_FOUND_MSG, studentID));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ca.bc.gov.educ.api.gradstudent.service;

import ca.bc.gov.educ.api.gradstudent.controller.BaseIntegrationTest;
import ca.bc.gov.educ.api.gradstudent.messaging.NatsConnection;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.FetchGradStatusSubscriber;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.Publisher;
Expand Down Expand Up @@ -34,8 +35,7 @@

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class CommonServiceTest {
public class CommonServiceTest extends BaseIntegrationTest {

@Autowired EducGradStudentApiConstants constants;
@Autowired CommonService commonService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ca.bc.gov.educ.api.gradstudent.constant.FieldName;
import ca.bc.gov.educ.api.gradstudent.constant.FieldType;
import ca.bc.gov.educ.api.gradstudent.constant.TraxEventType;
import ca.bc.gov.educ.api.gradstudent.controller.BaseIntegrationTest;
import ca.bc.gov.educ.api.gradstudent.messaging.NatsConnection;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.FetchGradStatusSubscriber;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.Publisher;
Expand Down Expand Up @@ -39,8 +40,7 @@

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class DataConversionServiceTest {
public class DataConversionServiceTest extends BaseIntegrationTest {
@Autowired
EducGradStudentApiConstants constants;
@Autowired
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ca.bc.gov.educ.api.gradstudent.service;

import ca.bc.gov.educ.api.gradstudent.controller.BaseIntegrationTest;
import ca.bc.gov.educ.api.gradstudent.messaging.NatsConnection;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.FetchGradStatusSubscriber;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.Publisher;
Expand Down Expand Up @@ -31,8 +32,7 @@

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class EdwSnapshotServiceTest {
public class EdwSnapshotServiceTest extends BaseIntegrationTest {

@Autowired
EdwSnapshotService edwSnapshotService;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package ca.bc.gov.educ.api.gradstudent.service;

import ca.bc.gov.educ.api.gradstudent.controller.BaseIntegrationTest;
import ca.bc.gov.educ.api.gradstudent.exception.EntityNotFoundException;
import ca.bc.gov.educ.api.gradstudent.messaging.NatsConnection;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.FetchGradStatusSubscriber;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.Publisher;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.Subscriber;
import ca.bc.gov.educ.api.gradstudent.model.dto.*;
import ca.bc.gov.educ.api.gradstudent.model.dto.messaging.GradStudentRecord;
import ca.bc.gov.educ.api.gradstudent.model.entity.GraduationStudentRecordEntity;
import ca.bc.gov.educ.api.gradstudent.model.entity.GraduationStudentRecordView;
import ca.bc.gov.educ.api.gradstudent.model.transformer.GraduationStatusTransformer;
Expand Down Expand Up @@ -41,15 +44,16 @@
import java.util.function.Function;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class GradStudentServiceTest {
public class GradStudentServiceTest extends BaseIntegrationTest {

@Autowired
EducGradStudentApiConstants constants;
Expand Down Expand Up @@ -853,6 +857,25 @@ public void testGetStudentIDsBySearchCriterias() {
assertThat(results).isNotEmpty();
}

@Test
public void testGetGraduationStudentRecord_GivenValidProgramCompletionDate_ExpectTrue() throws EntityNotFoundException {
UUID studentID = UUID.randomUUID();
GraduationStudentRecordEntity graduationStudentRecordEntity = new GraduationStudentRecordEntity();
graduationStudentRecordEntity.setProgramCompletionDate(new java.util.Date());
when(graduationStatusRepository.findByStudentID(studentID, GradStudentRecord.class)).thenReturn(new GradStudentRecord(studentID, "2018-EN", new java.util.Date(), "schoolOfRecord"));
GradStudentRecord result = gradStudentService.getGraduationStudentRecord(studentID);
assertNotNull(result);
}

@Test
public void testGetGraduationStudentRecord_givenNotFound_ExpectEntityNotFoundExcetpion() {
UUID studentID = UUID.randomUUID();
when(graduationStatusRepository.findByStudentID(studentID, GradStudentRecord.class)).thenReturn(null);
assertThrows(EntityNotFoundException.class, () -> {
gradStudentService.getGraduationStudentRecord(studentID);
});
}

@SneakyThrows
protected Object createDataObjectFromJson(String jsonPath, Class<?> clazz) {
String json = readFile(jsonPath);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ca.bc.gov.educ.api.gradstudent.service;

import ca.bc.gov.educ.api.gradstudent.controller.BaseIntegrationTest;
import ca.bc.gov.educ.api.gradstudent.exception.EntityNotFoundException;
import ca.bc.gov.educ.api.gradstudent.messaging.NatsConnection;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.FetchGradStatusSubscriber;
Expand Down Expand Up @@ -50,8 +51,7 @@

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class GraduationStatusServiceTest {
public class GraduationStatusServiceTest extends BaseIntegrationTest {

@Autowired EducGradStudentApiConstants constants;
@Autowired GraduationStatusService graduationStatusService;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ca.bc.gov.educ.api.gradstudent.service;

import ca.bc.gov.educ.api.gradstudent.controller.BaseIntegrationTest;
import ca.bc.gov.educ.api.gradstudent.messaging.NatsConnection;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.FetchGradStatusSubscriber;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.Publisher;
Expand Down Expand Up @@ -51,8 +52,7 @@

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class HistoryServiceTest {
public class HistoryServiceTest extends BaseIntegrationTest {

@Autowired EducGradStudentApiConstants constants;
@Autowired HistoryService historyService;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ca.bc.gov.educ.api.gradstudent.service;

import ca.bc.gov.educ.api.gradstudent.controller.BaseIntegrationTest;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.FetchGradStatusSubscriber;
import ca.bc.gov.educ.api.gradstudent.model.dto.ChoreographedEvent;
import ca.bc.gov.educ.api.gradstudent.model.entity.GradStatusEvent;
Expand All @@ -8,16 +9,12 @@
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.Subscriber;
import ca.bc.gov.educ.api.gradstudent.repository.GradStatusEventRepository;
import ca.bc.gov.educ.api.gradstudent.util.EducGradStudentApiConstants;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.Optional;
Expand All @@ -27,10 +24,7 @@
import static ca.bc.gov.educ.api.gradstudent.constant.EventStatus.MESSAGE_PUBLISHED;
import static org.mockito.MockitoAnnotations.openMocks;

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class JetStreamEventHandlerServiceTest {
class JetStreamEventHandlerServiceTest extends BaseIntegrationTest {

@Autowired
EducGradStudentApiConstants constants;
Expand Down Expand Up @@ -59,18 +53,18 @@ public class JetStreamEventHandlerServiceTest {
@MockBean
private Subscriber subscriber;

@Before
@BeforeEach
public void setUp() {
openMocks(this);
}

@After
@AfterEach
public void tearDown() {

}

@Test
public void testUpdateEventStatus() {
void testUpdateEventStatus() {
UUID eventId = UUID.randomUUID();

ChoreographedEvent choreographedEvent = new ChoreographedEvent();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import ca.bc.gov.educ.api.gradstudent.messaging.NatsConnection;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.FetchGradStatusSubscriber;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.FetchGradStudentRecordSubscriber;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.Publisher;
import ca.bc.gov.educ.api.gradstudent.messaging.jetstream.Subscriber;
import io.nats.client.Connection;
Expand Down Expand Up @@ -56,6 +57,11 @@ public FetchGradStatusSubscriber fetchGradStatusSubscriber() {
return Mockito.mock(FetchGradStatusSubscriber.class);
}

@Bean
@Primary
public FetchGradStudentRecordSubscriber fetchGradStudentRecordSubscriber() {return Mockito.mock(FetchGradStudentRecordSubscriber.class);
}

@Bean
@Primary
public Connection connection() {
Expand Down

0 comments on commit 698092f

Please sign in to comment.