Skip to content

Commit

Permalink
PO-559: Add schema config excepton
Browse files Browse the repository at this point in the history
  • Loading branch information
RustyHMCTS committed Aug 23, 2024
1 parent 5ba14cc commit 7b6883e
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package uk.gov.hmcts.opal.exception;

public class SchemaConfigurationException extends RuntimeException {

public SchemaConfigurationException(String msg) {
super(msg);
}

public SchemaConfigurationException(Throwable t) {
super(t);
}

public SchemaConfigurationException(String message, Throwable t) {
super(message, t);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
import org.springframework.util.StreamUtils;
import uk.gov.hmcts.opal.dto.ToJsonString;
import uk.gov.hmcts.opal.exception.JsonSchemaValidationException;
import uk.gov.hmcts.opal.exception.SchemaConfigurationException;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Set;
import java.util.stream.Collectors;

import static java.lang.String.format;

Expand All @@ -26,44 +28,70 @@ public class JsonSchemaValidationService {
private static final String PATH_ROOT = "jsonSchemas";

public boolean isValid(String body, String jsonSchemaFileName) {
Set<ValidationMessage> errors = validate(body, jsonSchemaFileName);
Set<String> errors = validate(body, jsonSchemaFileName);
if (!errors.isEmpty()) {
log.error(":isValid: for JSON schema '{}', found {} validation errors.", jsonSchemaFileName, errors.size());
for (ValidationMessage msg : errors) {
log.error(":isValid: error: {}", msg.getMessage());
for (String msg : errors) {
log.error(":isValid: error: {}", msg);
}
return false;
}
return true;
}

public Set<ValidationMessage> validate(String body, String jsonSchemaFileName) {
public void validateOrError(String body, String jsonSchemaFileName) {
Set<String> errors = validate(body, jsonSchemaFileName);
if (!errors.isEmpty()) {
StringBuilder sb = new StringBuilder(errors.size() >> 7);
sb.append("Validating against JSON schema '")
.append(jsonSchemaFileName)
.append("', found ")
.append(errors.size())
.append(" validation errors:");
for (String msg : errors) {
sb.append("\n\t").append(msg);
}
throw new JsonSchemaValidationException(sb.toString());
}
}

public Set<String> validate(String body, String jsonSchemaFileName) {
String jsonSchemaContents = readJsonSchema(jsonSchemaFileName);
var jsonSchema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7).getSchema(jsonSchemaContents);
return jsonSchema.validate(getJsonNodeFromStringContent(body));
try {
Set<ValidationMessage> msgs = jsonSchema.validate(getJsonNodeFromStringContent(body));
return msgs.stream().map(ValidationMessage::getMessage).collect(Collectors.toSet());
} catch (JsonSchemaValidationException jsve) {
return Set.of(jsve.getMessage());
}
}

private JsonNode getJsonNodeFromStringContent(String content) {
try {
return ToJsonString.getObjectMapper().readTree(content);
} catch (JsonProcessingException e) {
throw new JsonSchemaValidationException(e.getMessage(), e);
StringBuilder sb = new StringBuilder(e.getMessage().length() + content.length() + 99);
sb.append(e.getOriginalMessage())
.append("\n\tContent to validate:\n\"\"\"\n")
.append(content)
.append("\n\"\"\"");
throw new JsonSchemaValidationException(sb.toString(), e);
}
}

private String readJsonSchema(String schemaFileName) {
if (schemaFileName.isBlank()) {
throw new JsonSchemaValidationException("A schema filename is required to validate a JSON document.");
throw new SchemaConfigurationException("A schema filename is required to validate a JSON document.");
}
String filePath = Path.of(PATH_ROOT, schemaFileName).toString();
ClassPathResource cpr = new ClassPathResource(filePath);
if (!cpr.exists()) {
throw new JsonSchemaValidationException(format("No JSON Schema file found at '%s'", cpr.getPath()));
throw new SchemaConfigurationException(format("No JSON Schema file found at '%s'", cpr.getPath()));
}
try {
return StreamUtils.copyToString(cpr.getInputStream(), Charset.defaultCharset());
} catch (IOException e) {
throw new JsonSchemaValidationException(format("Problem opening InputStream at '%s'", filePath), e);
throw new SchemaConfigurationException(format("Problem opening InputStream at '%s'", filePath), e);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package uk.gov.hmcts.opal.service.opal;

import com.networknt.schema.ValidationMessage;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import uk.gov.hmcts.opal.exception.JsonSchemaValidationException;
import uk.gov.hmcts.opal.exception.SchemaConfigurationException;

import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

@ExtendWith(MockitoExtension.class)
class JsonSchemaValidationServiceTest {
Expand All @@ -22,27 +23,27 @@ class JsonSchemaValidationServiceTest {
@Test
void testIsValid_failBlankSchema() {
// Act
JsonSchemaValidationException jsve = assertThrows(
JsonSchemaValidationException.class,
SchemaConfigurationException sce = assertThrows(
SchemaConfigurationException.class,
() -> jsonSchemaValidationService.isValid("", " ")
);

// Assert
assertEquals("A schema filename is required to validate a JSON document.",
jsve.getMessage());
sce.getMessage());
}

@Test
void testIsValid_failLoadSchema() {
// Act
JsonSchemaValidationException jsve = assertThrows(
JsonSchemaValidationException.class,
SchemaConfigurationException sce = assertThrows(
SchemaConfigurationException.class,
() -> jsonSchemaValidationService.isValid("", "nonExistentSchema.json")
);

// Assert
assertEquals("No JSON Schema file found at 'jsonSchemas/nonExistentSchema.json'",
jsve.getMessage());
sce.getMessage());
}

@Test
Expand All @@ -52,21 +53,52 @@ void testIsValid_failIsValid() {

@Test
void testIsValid_failValidate1() {
Set<ValidationMessage> messages = jsonSchemaValidationService
Set<String> messages = jsonSchemaValidationService
.validate("", "testSchema.json");
assertEquals(1, messages.size());
assertEquals("$: unknown found, object expected", messages
.stream()
.findFirst()
.map(ValidationMessage::getMessage)
.orElse(""));
}

@Test
void testIsValid_failValidate2() {
Set<ValidationMessage> messages = jsonSchemaValidationService
Set<String> messages = jsonSchemaValidationService
.validate("{\"data\": 7}", "testSchema.json");
assertEquals(4, messages.size());
}

@Test
void testIsValid_failValidate3() {
Set<String> messages = jsonSchemaValidationService
.validate("Not valid JSON", "testSchema.json");
assertEquals(1, messages.size());
String msg = messages.stream().findFirst().orElse("");
assertTrue(msg.startsWith("Unrecognized token 'Not': was expecting (JSON String, Number, Array, Object "));
}

@Test
void testIsValid_failValidateOrError1() {
// Act
JsonSchemaValidationException sce = assertThrows(
JsonSchemaValidationException.class,
() -> jsonSchemaValidationService.validateOrError("Not Valid JSON", "testSchema.json")
);

// Assert
assertTrue(sce.getMessage().startsWith("Validating against JSON schema 'testSchema.json', found 1 validation"));
}

@Test
void testIsValid_failValidateOrError2() {
// Act
JsonSchemaValidationException sce = assertThrows(
JsonSchemaValidationException.class,
() -> jsonSchemaValidationService.validateOrError("{\"name\": 5}", "testSchema.json")
);

// Assert
assertTrue(sce.getMessage().startsWith("Validating against JSON schema 'testSchema.json', found 4 validation"));
}
}

0 comments on commit 7b6883e

Please sign in to comment.