Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make JsonSchemaAssertions check for JSON content-type #65

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
24 changes: 24 additions & 0 deletions src/main/java/rocks/bastion/core/json/JsonSchemaAssertions.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import com.github.fge.jsonschema.core.report.ProcessingMessage;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import org.apache.http.entity.ContentType;
import org.junit.Assert;
import rocks.bastion.core.Assertions;
import rocks.bastion.core.ModelResponse;
import rocks.bastion.core.Response;
import rocks.bastion.core.resource.ResourceLoader;

import java.io.IOException;
Expand All @@ -33,17 +35,20 @@ public static JsonSchemaAssertions fromResource(String expectedSchemaSource) {
}

private String expectedSchema;
private ContentType contentType;

private JsonSchemaAssertions(String expectedSchema) {
Objects.requireNonNull(expectedSchema);
this.expectedSchema = expectedSchema;
contentType = ContentType.APPLICATION_JSON;
}

@Override
public void execute(int statusCode,
ModelResponse<?> response,
Object model) throws AssertionError {
try {
assertContentTypeHeader(response);
JsonNode jsonNodeOfResponse = convertResponseToJsonNode(response);
assertResponseConformsToSchema(jsonNodeOfResponse);
} catch (IOException e) {
Expand All @@ -54,6 +59,20 @@ public void execute(int statusCode,
throw new RuntimeException("An unknown error occurred while processing the JSON schema and API response", e);
}
}

/**
* The assertions object will initially check that the content-type header returned by the actual response is
* "application/json". This can be overriden to check for a different content-type header using this method. Despite
* this, this assertions object will still try to interpret the body as if it were JSON text.
*
* @param contentType The expected content-type header
* @return This object (for method chaining)
*/
public JsonSchemaAssertions overrideContentType(ContentType contentType) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add JavaDocs to this public method, please? I think you can add the same JavaDocs as JsonResponseAsserions.

Objects.requireNonNull(contentType);
this.contentType = contentType;
return this;
}

private JsonNode convertResponseToJsonNode(ModelResponse<?> response) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Expand All @@ -77,4 +96,9 @@ private JsonNode getExpectedSchema() throws IOException {
return mapper.readTree(expectedSchema);
}

private void assertContentTypeHeader(Response response) {
Assert.assertTrue("Content-type exists in response", response.getContentType().isPresent());
Assert.assertEquals("Content-type MIME type", contentType.getMimeType(), response.getContentType().get().getMimeType());
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package rocks.bastion.core.assertions;

import org.apache.http.entity.ContentType;
import org.junit.Assert;
import org.junit.Test;
import rocks.bastion.core.ModelResponse;
Expand Down Expand Up @@ -35,6 +36,33 @@ public void execute_fromStringSchemaMismatch_assertionErrorShouldBeThrown() {
Assert.fail("An assertion error should have been thrown by the JSON Schema Assertions");
}

@Test
public void execute_fromStringContentTypeMismatch_assertionErrorShouldBeThrown() {
try {
final JsonSchemaAssertions assertions = JsonSchemaAssertions.fromString("{\n" +
" \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n" +
" \"type\": \"object\",\n" +
" \"properties\": {\n" +
" \"id\": {\n" +
" \"type\": \"integer\"\n" +
" }\n" +
" },\n" +
" \"required\": [\n" +
" \"id\"\n" +
" ]\n" +
"}\n");
ModelResponse<String> response = TestModelResponse.prepare("{ \"id\": 21 }", "text/plain");
assertions.execute(201, response, response.getModel());
} catch (AssertionError assertionError) {
Assert.assertEquals("Assertion Failed Message",
"Content-type MIME type expected:<[application/jso]n> but was:<[text/plai]n>",
assertionError.getMessage());
return;
}

Assert.fail("An assertion error should have been thrown by the JSON Schema Assertions");
}

@Test
public void execute_fromStringSchemaMatches_shouldAssertSuccessfully() {
final JsonSchemaAssertions assertions = JsonSchemaAssertions.fromString("{\n" +
Expand All @@ -53,6 +81,25 @@ public void execute_fromStringSchemaMatches_shouldAssertSuccessfully() {
assertions.execute(201, response, response.getModel());
}

@Test
public void execute_fromStringSchemaAndContentTypeMatches_shouldAssertSuccessfully() {
final JsonSchemaAssertions assertions = JsonSchemaAssertions.fromString("{\n" +
" \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n" +
" \"type\": \"object\",\n" +
" \"properties\": {\n" +
" \"id\": {\n" +
" \"type\": \"integer\"\n" +
" }\n" +
" },\n" +
" \"required\": [\n" +
" \"id\"\n" +
" ]\n" +
"}\n");
assertions.overrideContentType(ContentType.TEXT_PLAIN);
ModelResponse<String> response = TestModelResponse.prepare("{ \"id\": 22 }", "text/plain");
assertions.execute(201, response, response.getModel());
}

@Test(expected = InvalidJsonException.class)
public void execute_fromStringSchemaIsInvalid_shouldThrowException() {
final JsonSchemaAssertions assertions = JsonSchemaAssertions.fromString("{\n" +
Expand Down
19 changes: 17 additions & 2 deletions src/test/java/rocks/bastion/core/assertions/TestModelResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,28 @@ class TestModelResponse {

/**
* Prepare a model response object with a status code of HTTP 200 and the given JSON body for testing purposes.
* The content type of the response will be set to "application/json".
*
* @param jsonContent
* @return A model response object.
*/
static ModelResponse<String> prepare(String jsonContent) {
return new ModelResponse<>(new RawResponse(200, "OK", Collections.singletonList(new ApiHeader("Content-type", "application/json")), new ByteArrayInputStream(jsonContent.getBytes())),
jsonContent);
return prepare(jsonContent, "application/json");
}

/**
* Prepare a model response object with a status code of HTTP 200, as well as the given JSON body and content type,
* for testing purposes.
*
* @param jsonContent
* @param contentType
* @return A model response object.
*/
static ModelResponse<String> prepare(String jsonContent, String contentType) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method appears to be a generalisation of the method above it. I would rewrite (and rename) the method above this one to use the new method you wrote.

return new ModelResponse<>(new RawResponse(200,
"OK",
Collections.singletonList(new ApiHeader("Content-type", contentType)), new ByteArrayInputStream(jsonContent.getBytes())),
jsonContent);
}

}