Skip to content

Commit

Permalink
Merge branch 'main' into story-610-write_db_enum
Browse files Browse the repository at this point in the history
  • Loading branch information
halprin authored Jan 16, 2024
2 parents 3cff506 + 7e3d873 commit 748eef3
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,31 @@ public Optional<PartnerMetadata> getMetadata(String receivedSubmissionId)

PartnerMetadata partnerMetadata = optionalPartnerMetadata.get();
var sentSubmissionId = partnerMetadata.sentSubmissionId();
if (partnerMetadata.receiver() == null && sentSubmissionId != null) {
if ((partnerMetadata.receiver() == null
|| partnerMetadata.deliveryStatus() == PartnerMetadataStatus.PENDING)
&& sentSubmissionId != null) {
logger.logInfo(
"Receiver name not found in metadata, looking up {} from RS history API",
"Receiver name not found in metadata or delivery status still pending, looking up {} from RS history API",
sentSubmissionId);

String receiver;
String rsStatus;
try {
String bearerToken = rsclient.getRsToken();
String responseBody =
rsclient.requestHistoryEndpoint(sentSubmissionId, bearerToken);
receiver = getReceiverName(responseBody);
var parsedResponseBody = getReceiverAndStatus(responseBody);
receiver = parsedResponseBody[0];
rsStatus = parsedResponseBody[1];
} catch (ReportStreamEndpointClientException | FormatterProcessingException e) {
throw new PartnerMetadataException(
"Unable to retrieve metadata from RS history API", e);
}

logger.logInfo("Updating metadata with receiver: {}", receiver);
partnerMetadata = partnerMetadata.withReceiver(receiver);
var ourStatus = ourStatusFromReportStreamStatus(rsStatus);

logger.logInfo("Updating metadata with receiver {} and status {}", receiver, ourStatus);
partnerMetadata = partnerMetadata.withReceiver(receiver).withDeliveryStatus(ourStatus);
partnerMetadataStorage.saveMetadata(partnerMetadata);
}

Expand Down Expand Up @@ -169,10 +176,12 @@ public void setMetadataStatus(String submissionId, PartnerMetadataStatus metadat
partnerMetadataStorage.saveMetadata(partnerMetadata);
}

String getReceiverName(String responseBody) throws FormatterProcessingException {
String[] getReceiverAndStatus(String responseBody) throws FormatterProcessingException {
// the expected json structure for the response is:
// {
// ...
// "overallStatus": "Waiting to Deliver",
// ...
// "destinations" : [ {
// ...
// "organization_id" : "flexion",
Expand All @@ -182,23 +191,46 @@ String getReceiverName(String responseBody) throws FormatterProcessingException
// ...
// }

String organizationId;
String service;
Map<String, Object> responseObject =
formatter.convertJsonToObject(responseBody, new TypeReference<>() {});

String receiver;
try {
Map<String, Object> responseObject =
formatter.convertJsonToObject(responseBody, new TypeReference<>() {});
ArrayList<?> destinations = (ArrayList<?>) responseObject.get("destinations");
Map<?, ?> destination = (Map<?, ?>) destinations.get(0);
organizationId = destination.get("organization_id").toString();
service = destination.get("service").toString();
String organizationId = destination.get("organization_id").toString();
String service = destination.get("service").toString();
receiver = organizationId + "." + service;
} catch (IndexOutOfBoundsException e) {
// the destinations have not been determined yet by RS
return null;
receiver = null;
} catch (Exception e) {
throw new FormatterProcessingException(
"Unable to extract receiver name from response due to unexpected format", e);
}

return organizationId + "." + service;
String overallStatus;
try {
overallStatus = (String) responseObject.get("overallStatus");
} catch (Exception e) {
throw new FormatterProcessingException(
"Unable to extract overallStatus from response due to unexpected format", e);
}

return new String[] {receiver, overallStatus};
}

PartnerMetadataStatus ourStatusFromReportStreamStatus(String rsStatus) {
if (rsStatus == null) {
return PartnerMetadataStatus.PENDING;
}

// based off of the Status enum in the SubmissionHistory.kt code in RS
// https://github.com/CDCgov/prime-reportstream/blob/master/prime-router/src/main/kotlin/history/SubmissionHistory.kt
return switch (rsStatus) {
case "Error", "Not Delivering" -> PartnerMetadataStatus.FAILED;
case "Delivered" -> PartnerMetadataStatus.DELIVERED;
default -> PartnerMetadataStatus.PENDING;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,40 @@ class PartnerMetadataOrchestratorTest extends Specification {

mockClient.getRsToken() >> bearerToken
mockClient.requestHistoryEndpoint(sentSubmissionId, bearerToken) >> rsHistoryApiResponse
mockFormatter.convertJsonToObject(rsHistoryApiResponse, _ as TypeReference) >> [destinations: [
mockFormatter.convertJsonToObject(rsHistoryApiResponse, _ as TypeReference) >> [
overallStatus: "Delivered",
destinations: [
[organization_id: "org", service: "service"]
]]

when:
Optional<PartnerMetadata> result = PartnerMetadataOrchestrator.getInstance().getMetadata(receivedSubmissionId)

then:
result.isPresent()
result.get() == expectedMetadata
1 * mockPartnerMetadataStorage.readMetadata(receivedSubmissionId) >> Optional.of(missingReceiverMetadata)
1 * mockPartnerMetadataStorage.saveMetadata(expectedMetadata)
}

def "getMetadata gets status if still pending in metadata"() {
given:
def receivedSubmissionId = "receivedSubmissionId"
def sentSubmissionId = "sentSubmissionId"
def sender = "senderName"
def receiver = "org.service"
def timestamp = Instant.now()
def hashCode = "123"
def bearerToken = "token"
def rsHistoryApiResponse = "{\"destinations\": [{\"organization_id\": \"org\", \"service\": \"service\"}]}"
def missingReceiverMetadata = new PartnerMetadata(receivedSubmissionId, sentSubmissionId, sender, receiver, timestamp, hashCode, PartnerMetadataStatus.PENDING)
def expectedMetadata = new PartnerMetadata(receivedSubmissionId, sentSubmissionId, sender, receiver, timestamp, hashCode, PartnerMetadataStatus.FAILED)

mockClient.getRsToken() >> bearerToken
mockClient.requestHistoryEndpoint(sentSubmissionId, bearerToken) >> rsHistoryApiResponse
mockFormatter.convertJsonToObject(rsHistoryApiResponse, _ as TypeReference) >> [
overallStatus: "Not Delivering",
destinations: [
[organization_id: "org", service: "service"]
]]

Expand Down Expand Up @@ -320,66 +353,120 @@ class PartnerMetadataOrchestratorTest extends Specification {
}
}

def "getReceiverName returns correct receiver name from valid JSON response"() {
def "getReceiverAndStatus returns correct status name and receiver name from valid JSON response"() {
given:
def validJson = "{\"destinations\": [{\"organization_id\": \"org_id\", \"service\": \"service_name\"}]}"
def organization = "org_id"
def sender = "service_name"
def status = "Not Delivering"
def validJson = """{"overallStatus": "${status}", "destinations": [{"organization_id": "${organization}", "service": "${sender}"}]}"""

TestApplicationContext.register(Formatter, Jackson.getInstance())
TestApplicationContext.injectRegisteredImplementations()

when:
def receiverName = PartnerMetadataOrchestrator.getInstance().getReceiverName(validJson)
def parsedResponse = PartnerMetadataOrchestrator.getInstance().getReceiverAndStatus(validJson)

then:
receiverName == "org_id.service_name"
parsedResponse[0] == "${organization}.${sender}"
parsedResponse[1] == status
}

def "getReceiverName throws FormatterProcessingException or returns null for unexpected format response"() {
def "getReceiverAndStatus throws FormatterProcessingException or returns null for unexpected format response"() {
given:
TestApplicationContext.register(Formatter, Jackson.getInstance())
TestApplicationContext.injectRegisteredImplementations()

when:
def invalidJson = "invalid JSON"
PartnerMetadataOrchestrator.getInstance().getReceiverName(invalidJson)
PartnerMetadataOrchestrator.getInstance().getReceiverAndStatus(invalidJson)

then:
thrown(FormatterProcessingException)

when:
def emptyJson = "{}"
PartnerMetadataOrchestrator.getInstance().getReceiverName(emptyJson)
PartnerMetadataOrchestrator.getInstance().getReceiverAndStatus(emptyJson)

then:
thrown(FormatterProcessingException)

when:
def jsonWithoutDestinations = "{\"someotherkey\": \"value\"}"
PartnerMetadataOrchestrator.getInstance().getReceiverName(jsonWithoutDestinations)
PartnerMetadataOrchestrator.getInstance().getReceiverAndStatus(jsonWithoutDestinations)

then:
thrown(FormatterProcessingException)

when:

def jsonWithEmptyDestinations = "{\"destinations\": []}"
def receiverName = PartnerMetadataOrchestrator.getInstance().getReceiverName(jsonWithEmptyDestinations)
def parsedData = PartnerMetadataOrchestrator.getInstance().getReceiverAndStatus(jsonWithEmptyDestinations)

then:
parsedData[0] == null

when:

def jsonWithNoStatus = "{\"destinations\": []}"
parsedData = PartnerMetadataOrchestrator.getInstance().getReceiverAndStatus(jsonWithNoStatus)

then:
receiverName == null
parsedData[1] == null

when:
def jsonWithoutOrgId = "{\"destinations\":[{\"service\":\"service\"}]}"
PartnerMetadataOrchestrator.getInstance().getReceiverName(jsonWithoutOrgId)
PartnerMetadataOrchestrator.getInstance().getReceiverAndStatus(jsonWithoutOrgId)

then:
thrown(FormatterProcessingException)

when:
def jsonWithoutService = "{\"destinations\":[{\"organization_id\":\"org_id\"}]}"
PartnerMetadataOrchestrator.getInstance().getReceiverName(jsonWithoutService)
PartnerMetadataOrchestrator.getInstance().getReceiverAndStatus(jsonWithoutService)

then:
thrown(FormatterProcessingException)
}

def "ourStatusFromReportStreamStatus returns FAILED"() {
when:
def ourStatus = PartnerMetadataOrchestrator.getInstance().ourStatusFromReportStreamStatus("Error")

then:
ourStatus == PartnerMetadataStatus.FAILED

when:
ourStatus = PartnerMetadataOrchestrator.getInstance().ourStatusFromReportStreamStatus("Not Delivering")

then:
ourStatus == PartnerMetadataStatus.FAILED
}

def "ourStatusFromReportStreamStatus returns DELIVERED"() {
when:
def ourStatus = PartnerMetadataOrchestrator.getInstance().ourStatusFromReportStreamStatus("Delivered")

then:
ourStatus == PartnerMetadataStatus.DELIVERED
}

def "ourStatusFromReportStreamStatus returns PENDING"() {
when:
def ourStatus = PartnerMetadataOrchestrator.getInstance().ourStatusFromReportStreamStatus("Waiting to Deliver")

then:
ourStatus == PartnerMetadataStatus.PENDING

when:
ourStatus = PartnerMetadataOrchestrator.getInstance().ourStatusFromReportStreamStatus("DogCow")

then:
ourStatus == PartnerMetadataStatus.PENDING

when:
ourStatus = PartnerMetadataOrchestrator.getInstance().ourStatusFromReportStreamStatus(null)

then:
ourStatus == PartnerMetadataStatus.PENDING
}
}

0 comments on commit 748eef3

Please sign in to comment.