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
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ amqp:
mhs:
queueName: ${MHS_QUEUE_NAME:mhsQueue}
broker: ${MHS_AMQP_BROKER:amqp://localhost:5672}
username: ${MHS_AMQP_USERNAME:}
password: ${MHS_AMQP_PASSWORD:}
username: ${MHS_AMQP_USERNAME:admin}
password: ${MHS_AMQP_PASSWORD:admin}
maxRedeliveries: ${MHS_AMQP_MAX_REDELIVERIES:3}
dlqPrefix: ${MHS_DLQ_PREFIX:DLQ.}
gp2gp:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@

import lombok.Getter;
import lombok.Setter;
import org.springframework.validation.annotation.Validated;
import uk.nhs.adaptors.pss.translator.validation.ValidMhsQueueProperties;

@Component
@ConfigurationProperties(prefix = "amqp.mhs")
@Getter
@Setter
@Validated
@ValidMhsQueueProperties
public class MhsQueueProperties {
private String queueName;
private String broker;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package uk.nhs.adaptors.pss.translator.validation;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import uk.nhs.adaptors.pss.translator.config.MhsQueueProperties;

import java.util.ArrayList;
import java.util.TreeMap;

@Slf4j
public class MhsQueuePropertyValidator
implements ConstraintValidator<ValidMhsQueueProperties, MhsQueueProperties> {
private static final String MISSING_ENV_VARIABLE_MESSAGE = "Env variable not provided: %s";

@Override
public boolean isValid(MhsQueueProperties config, ConstraintValidatorContext context) {
TreeMap<String, String> environmentVariables = getEnvironmentVariables(config);

ArrayList<String> validationMessages = validateAgainstRuleset(environmentVariables);

if (!validationMessages.isEmpty()) {

Check warning on line 23 in gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/validation/MhsQueuePropertyValidator.java

View workflow job for this annotation

GitHub Actions / pitest

2 different changes can be made to line 23 without causing a test to fail

removed conditional - replaced equality check with true (no tests cover this line RemoveConditionalMutator_EQUAL_IF) removed conditional - replaced equality check with false (no tests cover this line RemoveConditionalMutator_EQUAL_ELSE)
for (var message : validationMessages) {
setConstraintViolation(context, message);

Check warning on line 25 in gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/validation/MhsQueuePropertyValidator.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 25 without causing a test to fail

removed call to setConstraintViolation (no tests cover this line VoidMethodCallMutator)
}
return false;

Check warning on line 27 in gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/validation/MhsQueuePropertyValidator.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 27 without causing a test to fail

replaced boolean return with true for isValid (no tests cover this line BooleanTrueReturnValsMutator)
}
return true;

Check warning on line 29 in gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/validation/MhsQueuePropertyValidator.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 29 without causing a test to fail

replaced boolean return with false for isValid (no tests cover this line BooleanFalseReturnValsMutator)
}

private TreeMap<String, String> getEnvironmentVariables(MhsQueueProperties configuration) {
TreeMap<String, String> environmentVariables = new TreeMap<>();

environmentVariables.put("MHS_AMQP_BROKER", configuration.getBroker());
environmentVariables.put("MHS_AMQP_USERNAME", configuration.getUsername());
environmentVariables.put("MHS_AMQP_PASSWORD", configuration.getPassword());

return environmentVariables;

Check warning on line 39 in gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/validation/MhsQueuePropertyValidator.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 39 without causing a test to fail

replaced return value with null for getEnvironmentVariables (no tests cover this line NullReturnValsMutator)
}

private ArrayList<String> validateAgainstRuleset(TreeMap<String, String> environmentVariables) {
ArrayList<String> messages = new ArrayList<>();

for (var variable : environmentVariables.entrySet()) {
if (StringUtils.isBlank(variable.getValue())) {

Check warning on line 46 in gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/validation/MhsQueuePropertyValidator.java

View workflow job for this annotation

GitHub Actions / pitest

2 different changes can be made to line 46 without causing a test to fail

removed conditional - replaced equality check with false (no tests cover this line RemoveConditionalMutator_EQUAL_ELSE) removed conditional - replaced equality check with true (no tests cover this line RemoveConditionalMutator_EQUAL_IF)
messages.add(String.format(MISSING_ENV_VARIABLE_MESSAGE, variable.getKey()));

Check warning on line 47 in gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/validation/MhsQueuePropertyValidator.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 47 without causing a test to fail

removed last varargs argument in call to format (no tests cover this line VarargsMutator)
}
}

return messages;

Check warning on line 51 in gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/validation/MhsQueuePropertyValidator.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 51 without causing a test to fail

replaced return value with null for validateAgainstRuleset (no tests cover this line NullReturnValsMutator)
}

private static void setConstraintViolation(ConstraintValidatorContext context, String message) {
LOGGER.error(message);
context.buildConstraintViolationWithTemplate(message).addConstraintViolation();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package uk.nhs.adaptors.pss.translator.validation;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Constraint(validatedBy = MhsQueuePropertyValidator.class)
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidMhsQueueProperties {
String message() default "Invalid MHS Queue Configuration";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package validation;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Configuration;
import uk.nhs.adaptors.pss.translator.config.MhsQueueProperties;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

public class MhsQueuePropertyValidatorTest {

// Valid configurations
private static final String VALID_MHS_AMQP_BROKER = "amqp://localhost:1234";
private static final String VALID_MHS_AMQP_USERNAME = "some-username";
private static final String VALID_MHS_AMQP_PASSWORD = "some-password";

// Configuration fields
private static final String MHS_AMQP_BROKER = "broker";
private static final String MHS_AMQP_USERNAME = "username";
private static final String MHS_AMQP_PASSWORD = "password";

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(TestMhsQueueProperties.class);

@Test
void When_ConfigurationContainsAllProperties_Expect_IsContextIsCreated() {
contextRunner
.withPropertyValues(
buildPropertyValue(MHS_AMQP_BROKER, VALID_MHS_AMQP_BROKER),
buildPropertyValue(MHS_AMQP_USERNAME, VALID_MHS_AMQP_USERNAME),
buildPropertyValue(MHS_AMQP_PASSWORD, VALID_MHS_AMQP_PASSWORD)
)
.run(context -> {
assertThat(context)
.hasNotFailed()
.hasSingleBean(MhsQueueProperties.class);

var storageConnectorConfiguration = context.getBean(MhsQueueProperties.class);

assertAll(
() -> assertThat(storageConnectorConfiguration.getBroker())
.isEqualTo(VALID_MHS_AMQP_BROKER),
() -> assertThat(storageConnectorConfiguration.getUsername())
.isEqualTo(VALID_MHS_AMQP_USERNAME),
() -> assertThat(storageConnectorConfiguration.getPassword())
.isEqualTo(VALID_MHS_AMQP_PASSWORD)
);
});
}

@Test
void When_ConfigurationPropertiesNotProvided_Expect_ContextNotCreated() {
contextRunner
.withPropertyValues(
buildPropertyValue(MHS_AMQP_BROKER, ""),
buildPropertyValue(MHS_AMQP_USERNAME, ""),
buildPropertyValue(MHS_AMQP_PASSWORD, "")
)
.run(context -> {
assertThat(context).hasFailed();
var startupFailure = context.getStartupFailure();

assertThat(startupFailure)
.rootCause()
.hasMessageContaining("Env variable not provided: MHS_AMQP_BROKER")
.hasMessageContaining("Env variable not provided: MHS_AMQP_USERNAME")
.hasMessageContaining("Env variable not provided: MHS_AMQP_PASSWORD");
});
}

@Test
void When_SingleConfigurationPropertyNotProvided_Expect_ContextNotCreated() {
contextRunner
.withPropertyValues(
buildPropertyValue(MHS_AMQP_BROKER, VALID_MHS_AMQP_BROKER),
buildPropertyValue(MHS_AMQP_USERNAME, VALID_MHS_AMQP_USERNAME),
buildPropertyValue(MHS_AMQP_PASSWORD, "")
)
.run(context -> {
assertThat(context).hasFailed();
var startupFailure = context.getStartupFailure();

assertThat(startupFailure)
.rootCause()
.hasMessageContaining("Env variable not provided: MHS_AMQP_PASSWORD");
});
}


@Contract(pure = true)
private static @NotNull String buildPropertyValue(String propertyName, String value) {
return String.format("amqp.mhs.%s=%s", propertyName, value);
}

@Configuration
@EnableConfigurationProperties(MhsQueueProperties.class)
static class TestMhsQueueProperties {
}
}