/*
* Copyright (C) 2014 Stefan Niederhauser (nidin@gmx.ch)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package guru.nidi.ramltester;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import guru.nidi.ramltester.core.JsonSchemaViolationCause;
import guru.nidi.ramltester.core.RamlReport;
import guru.nidi.ramltester.core.RamlViolationMessage;
import guru.nidi.ramltester.core.XmlSchemaViolationCause;
import org.junit.Test;
import java.io.UnsupportedEncodingException;
import java.util.Locale;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
/**
*
*/
public class SchemaTest extends HighlevelTestBase {
private final RamlDefinition simple = RamlLoaders.fromClasspath(getClass()).load("simple.raml");
private final ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS);
@Test
public void matchingJsonSchema() throws UnsupportedEncodingException {
assertNoViolations(simple, get("/schema"), jsonResponse(200, "{\"s\":\"str\",\"i\":42}"));
}
@Test
public void multiNonMatchingJsonSchema() throws UnsupportedEncodingException {
assertOneResponseViolationThat(simple, get("/schema"), jsonResponse(200, "{\"s\":{},\"i\":true}"), allOf(
containsString("error: instance type (boolean) does not match any allowed primitive type (allowed: [\"integer\"])"),
containsString("error: instance type (object) does not match any allowed primitive type (allowed: [\"string\"])")));
}
@Test
public void matchingXmlSchema() throws UnsupportedEncodingException {
assertNoViolations(simple, get("/schema"), response(208, "<api-request><input>str</input></api-request>", "text/xml"));
}
@Test
public void matchingReferencedJsonSchema() throws UnsupportedEncodingException {
assertNoViolations(simple, get("/schema"), jsonResponse(204, "\"str\""));
assertNoViolations(simple, get("/schema"), jsonResponse(205, "\"str\""));
}
@Test
public void matchingReferencedXmlSchema() throws UnsupportedEncodingException {
assertNoViolations(simple, get("/schema"), response(206, "<api-request><input>str</input></api-request>", "application/xml"));
assertNoViolations(simple, get("/schema"), response(207, "<api-request><input>str</input></api-request>", "application/xml"));
}
@Test
public void notMatchingJsonSchemaInline() throws Exception {
final RamlReport report = test(simple, get("/schema"), jsonResponse(200, "{\"s\":{},\"i\":true}"));
final RamlViolationMessage message = report.getResponseViolations().iterator().next();
assertThat(message.getCause(), instanceOf(JsonSchemaViolationCause.class));
final String boolMessage = "{'message':'instance type (boolean) does not match any allowed primitive type (allowed: [\\'integer\\'])','logLevel':'ERROR'}";
final String objMessage = "{'message':'instance type (object) does not match any allowed primitive type (allowed: [\\'string\\'])','logLevel':'ERROR'}";
assertThat(mapper.writeValueAsString(message.getCause()), either(
equalTo(("{'messages':[" + boolMessage + "," + objMessage + "]}").replace("'", "\""))).or(
equalTo(("{'messages':[" + objMessage + "," + boolMessage + "]}").replace("'", "\""))
));
}
@Test
public void notMatchingJsonSchemaInclude() throws Exception {
assertOneResponseViolationThat(
simple,
get("/schema"),
jsonResponse(201, "5"),
startsWith("Body does not match schema for action(GET /schema) response(201) mime-type('application/json')\n" +
"Content: 5\n" +
"Messages:\n"),
instanceOf(JsonSchemaViolationCause.class)
);
}
@Test
public void notMatchingJsonSchemaReferenced() throws Exception {
assertOneResponseViolationThat(
simple,
get("/schema"),
jsonResponse(202, "5"),
startsWith("Body does not match schema for action(GET /schema) response(202) mime-type('application/json')\n" +
"Content: 5\n" +
"Messages:\n"),
instanceOf(JsonSchemaViolationCause.class)
);
}
@Test
public void notMatchingXmlSchemaInline() throws Exception {
Locale.setDefault(Locale.ENGLISH);
final RamlReport report = test(simple, get("/schema"), response(208, "<api-request>str</api-request>", "text/xml"));
final RamlViolationMessage message = report.getResponseViolations().iterator().next();
assertThat(message.getCause(), instanceOf(XmlSchemaViolationCause.class));
final String childMessage = "{'message':'cvc-complex-type.2.3: Element `api-request` cannot have character [children], because the type`s content type is element-only.','line':1,'column':31}";
final String completeMessage = "{'message':'cvc-complex-type.2.4.b: The content of element `api-request` is not complete. One of `{input}` is expected.','line':1,'column':31}";
assertThat(mapper.writeValueAsString(message.getCause()), either(
equalTo(("{'messages':[" + childMessage + "," + completeMessage + "]}").replace("'", "\"").replace("`", "'"))).or(
equalTo(("{'messages':[" + completeMessage + "," + childMessage + "]}").replace("'", "\"").replace("`", "'"))
));
}
@Test
public void notMatchingXmlSchemaInclude() throws Exception {
assertResponseViolationsThat(
simple,
get("/schema"),
response(206, "5", "application/xml"),
startsWith("Body does not match schema for action(GET /schema) response(206) mime-type('application/xml')\n" +
"Content: 5\n" +
"Messages:\n"),
instanceOf(XmlSchemaViolationCause.class)
);
}
@Test
public void notMatchingXmlSchemaReferenced() throws Exception {
assertResponseViolationsThat(
simple,
get("/schema"),
response(207, "5", "application/xml"),
startsWith("Body does not match schema for action(GET /schema) response(207) mime-type('application/xml')\n" +
"Content: 5\n" +
"Messages:\n"),
instanceOf(XmlSchemaViolationCause.class)
);
}
@Test
public void noSchemaValidatorForMediaType() throws Exception {
assertOneResponseViolationThat(
simple,
get("/schema"),
response(209, "5", "text/bla"),
equalTo("No SchemaValidator found for media type 'text/bla' on action(GET /schema) response(209) mime-type('text/bla')")
);
}
@Test
public void invalidSchema() throws Exception {
assertOneResponseViolationThat(
simple,
get("/schema"),
jsonResponse(210, "5"),
equalTo("Body does not match schema for action(GET /schema) response(210) mime-type('application/json')\n" +
"Content: 5\n" +
"Messages:\n- Schema invalid: Unrecognized token 'xxx': was expecting ('true', 'false' or 'null')\n" +
" at [Source: Schema 'invalid'; line: 1, column: 7]")
);
}
}