Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/service-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ name: Services CI

on:
push:
branches:
- main
paths:
- "services/ehr-repo/**"
- "services/mesh-forwarder/**"
Expand Down
1 change: 1 addition & 0 deletions services/re-registration-service/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ dependencies {
implementation 'software.amazon.awssdk:cloudwatch'
implementation 'software.amazon.awssdk:sqs'
implementation 'software.amazon.awssdk:sns'
implementation 'software.amazon.awssdk:ssm'
implementation 'software.amazon.awssdk:dynamodb'

implementation 'com.google.code.gson:gson:2.13.2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ services:
network_mode: bridge
environment:
- DOCKER_HOST=unix:///var/run/docker.sock
- SERVICES=sqs,sns,dynamodb,s3
- SERVICES=sqs,sns,ssm,dynamodb,s3
- GATEWAY_LISTEN=4566
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
Expand Down
15 changes: 0 additions & 15 deletions services/re-registration-service/docker-compose.yaml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import static com.github.tomakehurst.wiremock.client.WireMock.delete;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.matching;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
Expand All @@ -53,8 +52,8 @@ public class DeleteEhrIntegrationTest {
@Autowired
ActiveSuspensionsDb activeSuspensionsDb;

@Value("${ehrRepoAuthKey}")
private String authKey;
private static final String EXPECTED_PDS_AUTH_HEADER = "Basic dXNlcm5hbWU6dGVzdA==";
private static final String EXPECTED_EHR_REPO_AUTH_HEADER = "test";

@Value("${aws.reRegistrationsQueueName}")
private String reRegistrationsQueueName;
Expand Down Expand Up @@ -120,7 +119,7 @@ private void stubResponses() {

private void setPds200SuccessState() {
stubPdsAdaptor.stubFor(get(urlEqualTo("/suspended-patient-status/" + NHS_NUMBER))
.withHeader("Authorization", equalTo("Basic cmUtcmVnaXN0cmF0aW9uLXNlcnZpY2U6ZGVmYXVsdA=="))
.withHeader("Authorization", equalTo(EXPECTED_PDS_AUTH_HEADER))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
Expand All @@ -129,15 +128,15 @@ private void setPds200SuccessState() {

private void ehrRepository200Response() {
stubPdsAdaptor.stubFor(delete(urlEqualTo("/patients/" + NHS_NUMBER))
.withHeader("Authorization", matching(authKey))
.withHeader("Authorization", equalTo(EXPECTED_EHR_REPO_AUTH_HEADER))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\n" +
" \"data\": {\n" +
" \"type\": \"patients\",\n" +
" \"id\": " + NHS_NUMBER + ",\n" +
" \"conversationIds\":[\"2431d4ff-f760-4ab9-8cd8-a3fc47846762\"," + "\"c184cc19-86e9-4a95-b5b5-2f156900bb3c\"]}}")
.withHeader("Content-Type", "application/json")));
" \"conversationIds\":[\"2431d4ff-f760-4ab9-8cd8-a3fc47846762\"," + "\"c184cc19-86e9-4a95-b5b5-2f156900bb3c\"]}}")));
}

private ReRegistrationEvent getReRegistrationEvent() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
Expand All @@ -29,17 +28,14 @@ public class EhrRepoServiceIntegrationTest {
@Autowired
private EhrRepoService ehrRepoService;

@Value("${ehrRepoAuthKey}")
private String authKey;

private WireMockServer stubEhrRepo;

public static final String NHS_NUMBER = "1234567890";
private static final String AUTHORIZATION_HEADER = "test";
private static final String NEMS_MESSAGE_ID = "nemsMessageId";
public static final String CONVERSATION_ID1 = "2431d4ff-f760-4ab9-8cd8-a3fc47846762";
public static final String CONVERSATION_ID2 = "c184cc19-86e9-4a95-b5b5-2f156900bb3c";


@BeforeEach
public void setUp() {
stubEhrRepo = initializeWebServer();
Expand Down Expand Up @@ -70,7 +66,7 @@ void shouldSendMessageWithActionOnAuditTopicWhenEhrRepoReturns200() throws JsonP

private void ehrRepo200Response() {
stubFor(delete(urlMatching("/patients/" + NHS_NUMBER))
.withHeader("Authorization", matching(authKey))
.withHeader("Authorization", equalTo(AUTHORIZATION_HEADER))
.willReturn(aResponse()
.withStatus(200)
.withBody("{\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
import software.amazon.awssdk.services.sqs.model.GetQueueAttributesRequest;
import software.amazon.awssdk.services.sqs.model.QueueAttributeName;
import software.amazon.awssdk.services.sqs.model.QueueDoesNotExistException;
import software.amazon.awssdk.services.ssm.SsmClient;
import software.amazon.awssdk.services.ssm.model.ParameterType;
import software.amazon.awssdk.services.ssm.model.PutParameterRequest;

import java.net.URI;
import java.util.ArrayList;
Expand All @@ -38,6 +41,10 @@

@TestConfiguration
public class LocalStackAwsConfig {
private static final Region LOCALSTACK_REGION = Region.EU_WEST_2;

private static final StaticCredentialsProvider LOCALSTACK_CREDENTIALS =
StaticCredentialsProvider.create(AwsBasicCredentials.create("LSIA5678901234567890", "LSIA5678901234567890"));

@Value("${aws.reRegistrationsQueueName}")
private String reRegistrationsQueueName;
Expand All @@ -57,57 +64,54 @@ public class LocalStackAwsConfig {
@Autowired
private SqsClient sqsClient;

@Autowired
private SsmClient ssmClient;

@Autowired
private DynamoDbClient dynamoDbClient;

@Value("${aws.activeSuspensionsDynamoDbTableName}")
private String activeSuspensionsDynamoDbTableName;

@Value("${pdsAdaptor.authPasswordSsmParameterName}")
private String authPasswordSsmParameterName;

@Value("${ehrRepoAuthKeySsmParameterName}")
private String ehrRepoAuthKeySsmParameterName;

@Bean
public static SqsClient sqsClient(@Value("${localstack.url}") String localstackUrl) {
return SqsClient.builder()
.credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("FAKE", "FAKE")))
.endpointOverride(URI.create(localstackUrl))
.region(Region.EU_WEST_2)
.region(LOCALSTACK_REGION)
.credentialsProvider(LOCALSTACK_CREDENTIALS)
.build();
}

@Bean
public static SnsClient snsClient(@Value("${localstack.url}") String localstackUrl) {
return SnsClient.builder()
.endpointOverride(URI.create(localstackUrl))
.region(Region.EU_WEST_2)
.credentialsProvider(StaticCredentialsProvider.create(new AwsCredentials() {
@Override
public String accessKeyId() {
return "FAKE";
}

@Override
public String secretAccessKey() {
return "FAKE";
}
}))
.region(LOCALSTACK_REGION)
.credentialsProvider(LOCALSTACK_CREDENTIALS)
.build();
}

@Bean
public static SsmClient ssmClient(@Value("${localstack.url}") String localstackUrl) {
return SsmClient.builder()
.endpointOverride(URI.create(localstackUrl))
.region(LOCALSTACK_REGION)
.credentialsProvider(LOCALSTACK_CREDENTIALS)
.build();
}

@Bean
public static DynamoDbClient dynamoDbClient(@Value("${localstack.url}") String localstackUrl) {
return DynamoDbClient.builder()
.endpointOverride(URI.create(localstackUrl))
.region(Region.EU_WEST_2)
.credentialsProvider(
StaticCredentialsProvider.create(new AwsCredentials() {
@Override
public String accessKeyId() {
return "FAKE";
}

@Override
public String secretAccessKey() {
return "FAKE";
}
}))
.region(LOCALSTACK_REGION)
.credentialsProvider(LOCALSTACK_CREDENTIALS)
.build();
}

Expand All @@ -121,9 +125,27 @@ public void setupTestQueuesTopicsAndDb() {

createSnsTestReceiverSubscription(topic, getQueueArn(reRegistrationsAuditQueue.queueUrl()));

setupSsmParameters();

setupDbAndTable();
}

private void setupSsmParameters() {
ssmClient.putParameter(PutParameterRequest.builder()
.name(authPasswordSsmParameterName)
.value("test")
.type(ParameterType.SECURE_STRING)
.overwrite(true)
.build());

ssmClient.putParameter(PutParameterRequest.builder()
.name(ehrRepoAuthKeySsmParameterName)
.value("test")
.type(ParameterType.SECURE_STRING)
.overwrite(true)
.build());
}

private void setupDbAndTable() {

var waiter = dynamoDbClient.waiter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class PdsAdaptorServiceIntegrationTest {
public static final String NHS_NUMBER = "1234567890";
public static final String STATUS_MESSAGE_FOR_WHEN_PATIENT_IS_STILL_SUSPENDED = "NO_ACTION:RE_REGISTRATION_FAILED_STILL_SUSPENDED";
public static final String STATUS_MESSAGE_FOR_WHEN_PDS_RETURNS_4XX_ERROR = "NO_ACTION:RE_REGISTRATION_FAILED_PDS_ERROR";
private static final String EXPECTED_PDS_AUTH_HEADER = "Basic dXNlcm5hbWU6dGVzdA==";

@Autowired
private SqsClient sqs;
Expand Down Expand Up @@ -136,7 +137,7 @@ void shouldPutTheAuditStatusMessageOnAuditTopicWhenPdsReturnsResponseWithStatusC

private void setPds200SuccessState(String startingState, int priority, String nhsNumber) {
stubPdsAdaptor.stubFor(get(urlEqualTo("/suspended-patient-status/" + nhsNumber)).atPriority(priority)
.withHeader("Authorization", equalTo("Basic cmUtcmVnaXN0cmF0aW9uLXNlcnZpY2U6ZGVmYXVsdA=="))
.withHeader("Authorization", equalTo(EXPECTED_PDS_AUTH_HEADER))
.inScenario("Retry Scenario")
.whenScenarioStateIs(startingState)
.willReturn(aResponse()
Expand All @@ -147,7 +148,7 @@ private void setPds200SuccessState(String startingState, int priority, String nh

private void setPdsErrorState(String startingState, String finishedState, int priority, String nhsNumber, int statusCode) {
stubPdsAdaptor.stubFor(get(urlEqualTo("/suspended-patient-status/" + nhsNumber)).atPriority(priority)
.withHeader("Authorization", equalTo("Basic cmUtcmVnaXN0cmF0aW9uLXNlcnZpY2U6ZGVmYXVsdA=="))
.withHeader("Authorization", equalTo(EXPECTED_PDS_AUTH_HEADER))
.inScenario("Retry Scenario")
.whenScenarioStateIs(startingState)
.willReturn(aResponse()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ aws.reRegistrationsQueueName=test-re-registrations-queue
aws.reRegistration.auditTopic.arn=arn:aws:sns:eu-west-2:000000000000:re_registration_audit_sns_topic
localstack.url=${LOCALSTACK_URL:http://localhost:4566}
pdsAdaptor.serviceUrl=http://localhost:8080
pdsAdaptor.authUserName=username
pdsAdaptor.authPasswordSsmParameterName=auth-key-ssm-parameter-name
pdsIntermittentError.retry.max.attempts=3
pdsIntermittentError.initial.interval.millisecond=1000
pdsIntermittentError.initial.interval.multiplier=2.0
toggle.canSendDeleteEhrRequest=true
spring.main.allow-bean-definition-overriding=true
ehrRepoUrl=http://localhost:8080
ehrRepoAuthKey=auth-key-2
ehrRepoAuthKeySsmParameterName=auth-key-ssm-parameter-name
aws.reRegistrationsAuditQueueName=test-re-registrations-audit-queue
aws.activeSuspensionsQueueName=test-active-suspensions
aws.activeSuspensionsDynamoDbTableName=test-active-suspensions-dynamodb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package uk.nhs.prm.repo.re_registration.config;

import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ssm.SsmClient;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@RequiredArgsConstructor
public class SsmClientSpringConfiguration {
@Bean
public SsmClient ssmClient() {
return SsmClient.builder()
.region(Region.EU_WEST_2)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,55 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import uk.nhs.prm.repo.re_registration.config.Tracer;
import uk.nhs.prm.repo.re_registration.http.HttpClient;
import uk.nhs.prm.repo.re_registration.message_publishers.ReRegistrationAuditPublisher;
import uk.nhs.prm.repo.re_registration.model.ReRegistrationEvent;
import uk.nhs.prm.repo.re_registration.service.SsmService;

@Slf4j
@Service
public class EhrRepoService {
private final String ehrRepoUrl;
private final String ehrRepoAuthKey;
private final Tracer tracer;
private final ReRegistrationAuditPublisher auditPublisher;
private SsmService ssmService;
private HttpClient httpClient;

public EhrRepoService(@Value("${ehrRepoUrl}") String ehrRepoUrl, @Value("${ehrRepoAuthKey}") String ehrRepoAuthKey, Tracer tracer, ReRegistrationAuditPublisher auditPublisher, HttpClient httpClient) {
this.ehrRepoUrl = ehrRepoUrl;
this.ehrRepoAuthKey = ehrRepoAuthKey;
private final String ehrRepoUrl;
private final String ehrRepoAuthKeySsmParameterName;
private String ehrRepoAuthKey;

public EhrRepoService(
Tracer tracer,
ReRegistrationAuditPublisher auditPublisher,
SsmService ssmService,
HttpClient httpClient,
@Value("${ehrRepoUrl}") String ehrRepoUrl,
@Value("${ehrRepoAuthKeySsmParameterName}") String ehrRepoAuthKeySsmParameterName
) {
this.tracer = tracer;
this.auditPublisher = auditPublisher;
this.ssmService = ssmService;
this.httpClient = httpClient;
this.ehrRepoUrl = ehrRepoUrl;
this.ehrRepoAuthKeySsmParameterName = ehrRepoAuthKeySsmParameterName;
}

public EhrDeleteResponseContent deletePatientEhr(ReRegistrationEvent reRegistrationEvent) throws JsonProcessingException {
@PostConstruct
private void getEhrRepoAuthKeyFromSsm() {
ehrRepoAuthKey = ssmService.getValueForParameter(ehrRepoAuthKeySsmParameterName);
}

public EhrDeleteResponseContent deletePatientEhr(ReRegistrationEvent reRegistrationEvent) throws JsonProcessingException {
var url = getPatientDeleteEhrUrl(reRegistrationEvent.getNhsNumber());
log.info("Making a DELETE EHR Request to ehr-repo");
var ehrRepoResponse = httpClient.delete(url, ehrRepoAuthKey);
return getParsedDeleteEhrResponseBody(ehrRepoResponse.getBody());

}


private EhrDeleteResponseContent getParsedDeleteEhrResponseBody(String responseBody) throws JsonProcessingException {
log.info("Trying to parse ehr-repo response");
return new ObjectMapper().readValue(responseBody, EhrDeleteResponse.class).getEhrDeleteResponseContent();
Expand Down
Loading
Loading