All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opengis.cite.ogcapiprocesses10.CommonFixture Maven / Gradle / Ivy

There is a newer version: 1.2
Show newest version
package org.opengis.cite.ogcapiprocesses10;

import static io.restassured.RestAssured.given;
import static io.restassured.http.ContentType.HTML;
import static io.restassured.http.Method.GET;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;

import org.apache.http.HttpRequest;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.openapi4j.core.validation.ValidationResults;
import org.openapi4j.core.validation.ValidationResults.ValidationItem;
import org.openapi4j.parser.model.v3.OpenApi3;
import org.openapi4j.parser.model.v3.Server;
import org.opengis.cite.ogcapiprocesses10.util.JsonUtils;
import org.opengis.cite.ogcapiprocesses10.util.TestSuiteLogger;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.SchemaValidatorsConfig;
import com.networknt.schema.SpecVersion;
import com.networknt.schema.ValidationMessage;

import io.restassured.filter.log.RequestLoggingFilter;
import io.restassured.filter.log.ResponseLoggingFilter;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;

/**
 * A supporting base class that sets up a common test fixture. These configuration methods
 * are invoked before those defined in a subclass.
 *
 * @author bpr
 */
public class CommonFixture {

	private ByteArrayOutputStream requestOutputStream = new ByteArrayOutputStream();

	private ByteArrayOutputStream responseOutputStream = new ByteArrayOutputStream();

	protected RequestLoggingFilter requestLoggingFilter;

	protected ResponseLoggingFilter responseLoggingFilter;

	protected URL specURL;

	protected URI rootUri;

	protected int limit = -1;

	protected boolean testAllProcesses = false;

	/** A String representing the request. */
	protected HttpRequest reqEntity;

	/** An Object representing the content of the response message. */
	protected Object rspEntity;

	protected final String CONTENT_TYPE = "Content-Type";

	protected final String CONTENT_MEDIA_TYPE_PROPERTY_KEY = "contentMediaType";

	protected final String CONTENT_SCHEMA_PROPERTY_KEY = "contentSchema";

	protected final String CONTENT_ENCODING_PROPERTY_KEY = "contentEncoding";

	private static final int MAX_RSP_ATTR_LENGTH = 4096;

	private static final String REQ_ATTR = "request";

	private static final String REQ_POST_ATTR = "post-request";

	private static final String RSP_ATTR = "response";

	/**
	 * Initializes the common test fixture with a client component for interacting with
	 * HTTP endpoints.
	 * @param testContext The test context that contains all the information for a test
	 * run, including suite attributes.
	 */
	@BeforeClass
	public void initCommonFixture(ITestContext testContext) {
		initLogging();
		rootUri = (URI) testContext.getSuite().getAttribute(SuiteAttribute.IUT.getName());
		limit = (Integer) testContext.getSuite().getAttribute(SuiteAttribute.PROCESS_TEST_LIMIT.getName());
		boolean useLocalSchema = (boolean) testContext.getSuite()
			.getAttribute(SuiteAttribute.USE_LOCAL_SCHEMA.getName());
		if (useLocalSchema) {
			specURL = getClass().getResource("/org/opengis/cite/ogcapiprocesses10/openapi/api-processes10.yaml");
		}
		else {
			try {
				specURL = new URI("https://developer.ogc.org/api/processes/openapi.yaml").toURL();
			}
			catch (MalformedURLException | URISyntaxException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 

* clearMessages. *

*/ @BeforeMethod public void clearMessages() { initLogging(); } /** *

* getRequest. *

* @return a {@link java.lang.String} object */ public String getRequest() { return requestOutputStream.toString(); } /** *

* getResponse. *

* @return a {@link java.lang.String} object */ public String getResponse() { return responseOutputStream.toString(); } /** *

* init. *

* @return a {@link io.restassured.specification.RequestSpecification} object */ protected RequestSpecification init() { return given().filters(requestLoggingFilter, responseLoggingFilter).log().all(); } /** * Obtains the (XML) response entity as a DOM Document. This convenience method wraps * a static method call to facilitate unit testing (Mockito workaround). * @param response A representation of an HTTP response message. * @param targetURI The target URI from which the entity was retrieved (may be null). * @return A Document representing the entity. * * @see ClientUtils#getResponseEntityAsDocument public Document * getResponseEntityAsDocument( ClientResponse response, String targetURI ) { return * ClientUtils.getResponseEntityAsDocument( response, targetURI ); } */ /** * Builds an HTTP request message that uses the GET method. This convenience method * wraps a static method call to facilitate unit testing (Mockito workaround). * @return A ClientRequest object. * * @see ClientUtils#buildGetRequest public ClientRequest buildGetRequest( URI * endpoint, Map String, String qryParams, MediaType... mediaTypes ) { return * ClientUtils.buildGetRequest( endpoint, qryParams, mediaTypes ); } */ /** *

* validateResponseAgainstSchema. *

* @param urlSchema a {@link java.lang.String} object * @param body a {@link java.lang.String} object * @return a boolean */ protected boolean validateResponseAgainstSchema(String urlSchema, String body) { ObjectMapper objMapper = new ObjectMapper(new YAMLFactory()); JsonSchemaFactory factory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)) .objectMapper(objMapper) .build(); SchemaValidatorsConfig config = new SchemaValidatorsConfig(); config.setTypeLoose(false); try { JsonSchema jsonSchema = factory.getSchema(new URI(urlSchema), config); ObjectMapper objectMapper = new ObjectMapper(); JsonNode json = objectMapper.readTree(body); Set validationResult = jsonSchema.validate(json); if (validationResult.isEmpty()) { System.out.println("no validation errors :-)"); return true; } else { validationResult.forEach(vm -> System.out.println(vm.getMessage())); return false; } } catch (Exception e) { e.printStackTrace(); return false; } } /** * Try to implement testing for A.5. Conformance Class HTML TODO: Abtract Test 56: * /conf/html/content Abtract Test 57: /conf/html/definition * @param uri a {@link java.lang.String} object */ protected void checkHtmlConfClass(String uri) { Response request = init().baseUri(uri).accept(HTML).when().request(GET); // TestSuiteLogger.log(Level.INFO, rootUri.toString()); request.then().statusCode(200); String headerValue = request.getHeader("Content-Type"); System.out.println("Content-type header fecthed: " + headerValue); if (headerValue.indexOf("text/html") < 0) throw new AssertionError( "The Content-type header should be text/html but '" + headerValue + "' has been found"); String bodyHTML = request.getBody().asString(); } private void initLogging() { this.requestOutputStream = new ByteArrayOutputStream(); this.responseOutputStream = new ByteArrayOutputStream(); PrintStream requestPrintStream = new PrintStream(requestOutputStream, true); PrintStream responsePrintStream = new PrintStream(responseOutputStream, true); requestLoggingFilter = new RequestLoggingFilter(requestPrintStream); responseLoggingFilter = new ResponseLoggingFilter(responsePrintStream); } /** *

* printResults. *

* @param validationResults a {@link org.openapi4j.core.validation.ValidationResults} * object * @return a {@link java.lang.String} object */ protected String printResults(ValidationResults validationResults) { List validationItems = validationResults.items(); StringBuilder printedResultsStringBuilder = new StringBuilder(); for (ValidationItem validationItem : validationItems) { printedResultsStringBuilder.append(validationItem + "\n"); } return printedResultsStringBuilder.toString(); } /** *

* addServerUnderTest. *

* @param openApi3 a {@link org.openapi4j.parser.model.v3.OpenApi3} object */ protected void addServerUnderTest(OpenApi3 openApi3) { Server serverUnderTest = new Server(); String authority = rootUri.getAuthority(); String scheme = rootUri.getScheme(); serverUnderTest.setUrl(scheme + "://" + authority); openApi3.addServer(serverUnderTest); } /** *

* createInput. *

* @param schemaNode a {@link com.fasterxml.jackson.databind.JsonNode} object * @param id a {@link java.lang.String} object * @return a {@link org.opengis.cite.ogcapiprocesses10.CommonFixture.Input} object */ protected Input createInput(JsonNode schemaNode, String id) { Input input = new Input(id); JsonNode typeNode = schemaNode.get("type"); if (typeNode != null) { String typeDefinition = typeNode.asText(); Type type = new Type(typeDefinition); if (typeDefinition.equals("object")) { JsonNode propertiesNode = schemaNode.get("properties"); if (propertiesNode != null) { Iterator propertyNames = propertiesNode.fieldNames(); while (propertyNames.hasNext()) { String propertyName = (String) propertyNames.next(); if (propertyName.equals("bbox")) { input.setBbox(true); break; } } } } else if (typeDefinition.equals("string")) { JsonNode formatNode = schemaNode.get("format"); if (formatNode != null) { String format = formatNode.asText(); input.setFormat(format); if (format.equals("byte")) { type.setBinary(true); } } JsonNode contentMediaTypeNode = schemaNode.get(CONTENT_MEDIA_TYPE_PROPERTY_KEY); if (contentMediaTypeNode != null && !contentMediaTypeNode.isMissingNode()) { type.setContentMediaType(contentMediaTypeNode.asText()); } JsonNode contentEncodingNode = schemaNode.get(CONTENT_ENCODING_PROPERTY_KEY); if (contentEncodingNode != null && !contentEncodingNode.isMissingNode()) { String contentEncodingNodeText = contentEncodingNode.asText(); if (contentEncodingNodeText.equals("binary")) { type.setBinary(true); } type.setContentEncoding(contentEncodingNodeText); } JsonNode contentSchemaNode = schemaNode.get(CONTENT_SCHEMA_PROPERTY_KEY); if (contentSchemaNode != null && !contentSchemaNode.isMissingNode()) { type.setContentSchema(contentSchemaNode.asText()); } } else if (typeDefinition.equals("array")) { JsonNode itemsNode = schemaNode.get("items"); if (itemsNode != null) { JsonNode itemsTypeNode = itemsNode.get("type"); if (itemsTypeNode != null) { Type itemsType = new Type(itemsTypeNode.asText()); input.addType(itemsType); } } } input.addType(type); } else { // oneOf, allOf, anyOf JsonNode oneOfNode = schemaNode.get("oneOf"); if (oneOfNode != null) { if (oneOfNode instanceof ArrayNode) { ArrayNode oneOfArrayNode = (ArrayNode) oneOfNode; for (int i = 0; i < oneOfArrayNode.size(); i++) { JsonNode oneOfChildNode = oneOfArrayNode.get(i); JsonNode oneOfTypeNode = oneOfChildNode.get("type"); if (oneOfTypeNode != null) { String typeDefinition = oneOfTypeNode.asText(); Type type = new Type(typeDefinition); if (typeDefinition.equals("object")) { JsonNode propertiesNode = oneOfChildNode.get("properties"); if (propertiesNode != null) { Iterator propertyNames = propertiesNode.fieldNames(); while (propertyNames.hasNext()) { String propertyName = (String) propertyNames.next(); if (propertyName.equals("bbox")) { input.setBbox(true); break; } } } } else if (typeDefinition.equals("string")) { JsonNode formatNode = oneOfChildNode.get("format"); if (formatNode != null) { String format = formatNode.asText(); if (format.equals("byte")) { type.setBinary(true); } } JsonNode contentMediaTypeNode = oneOfChildNode.get(CONTENT_MEDIA_TYPE_PROPERTY_KEY); if (contentMediaTypeNode != null && !contentMediaTypeNode.isMissingNode()) { type.setContentMediaType(contentMediaTypeNode.asText()); } JsonNode contentEncodingNode = oneOfChildNode.get(CONTENT_ENCODING_PROPERTY_KEY); if (contentEncodingNode != null && !contentEncodingNode.isMissingNode()) { String contentEncodingNodeText = contentEncodingNode.asText(); if (contentEncodingNodeText.equals("binary")) { type.setBinary(true); } type.setContentEncoding(contentEncodingNodeText); } JsonNode contentSchemaNode = oneOfChildNode.get(CONTENT_SCHEMA_PROPERTY_KEY); if (contentSchemaNode != null && !contentSchemaNode.isMissingNode()) { type.setContentSchema(contentSchemaNode.asText()); } } else if (typeDefinition.equals("array")) { JsonNode itemsNode = oneOfChildNode.get("items"); if (itemsNode != null) { JsonNode itemsTypeNode = itemsNode.get("type"); if (itemsTypeNode != null) { Type itemsType = new Type(itemsTypeNode.asText()); input.addType(itemsType); } } } input.addType(type); } } } } else { if (checkAllOfForBbox(schemaNode)) { input.setBbox(true); } } } return input; } private boolean checkAllOfForBbox(JsonNode schemaNode) { JsonNode allOfNode = schemaNode.get("allOf"); if (allOfNode != null) { if (allOfNode instanceof ArrayNode) { for (JsonNode jsonNode : allOfNode) { JsonNode formatNode = jsonNode.get("format"); String format = formatNode.asText(); if (format.equals("ogc-bbox")) { return true; } } } } return false; } /** *

* createOutput. *

* @param schemaNode a {@link com.fasterxml.jackson.databind.JsonNode} object * @param id a {@link java.lang.String} object * @return a {@link org.opengis.cite.ogcapiprocesses10.CommonFixture.Output} object */ protected Output createOutput(JsonNode schemaNode, String id) { Output output = new Output(id); JsonNode typeNode = schemaNode.get("type"); if (typeNode != null) { String typeDefinition = typeNode.asText(); if (typeDefinition.equals("array")) { Type itemsType = new Type(typeDefinition); output.addType(itemsType); } } else { if (checkAllOfForBbox(schemaNode)) { output.setBbox(true); } } return output; } public class Type { private String typeDefinition; private String contentEncoding; private String contentMediaType; private String contentSchema; private boolean isBinary; private String format; public Type(String typeDefinition) { this.typeDefinition = typeDefinition; } public boolean isBinary() { return isBinary; } public void setBinary(boolean isBinary) { this.isBinary = isBinary; } public String getContentEncoding() { return contentEncoding; } public void setContentEncoding(String contentEncoding) { this.contentEncoding = contentEncoding; } public String getContentMediaType() { return contentMediaType; } public void setContentMediaType(String contentMediaType) { this.contentMediaType = contentMediaType; } public void setContentSchema(String schema) { this.contentSchema = schema; } public String getContentSchema() { return contentSchema; } public String getTypeDefinition() { return typeDefinition; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("\tType definition: " + typeDefinition + "\n"); builder.append("\tContent Encoding: " + contentEncoding + "\n"); builder.append("\tType Content MediaType: " + contentMediaType + "\n"); builder.append("\tIs binary: " + isBinary + "\n"); return builder.toString(); } public String getFormat() { return format; } } public class Input { protected String id; protected List types; protected boolean isBbox; protected String format; public Input(String id, List types, boolean isBbox) { this.id = id; this.types = types; this.isBbox = isBbox; } public Input(String id, Type type) { this(id, Arrays.asList(new Type[] { type }), false); } public Input(String id) { this(id, new ArrayList(), false); } public boolean isBbox() { return isBbox; } public void setBbox(boolean isBbox) { this.isBbox = isBbox; } public String getId() { return id; } public List getTypes() { return types; } public boolean addType(Type type) { return types.add(type); } public String getFormat() { return format; } public void setFormat(String format) { this.format = format; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Id: " + id + "\n"); builder.append("\tType: " + types + "\n"); builder.append("\tIs bbox: " + isBbox); return builder.toString(); } } public class Output { private String id; private List types; private boolean bbox; public Output(String id) { this.id = id; this.types = new ArrayList(); } public void addType(Type itemsType) { types.add(itemsType); } public void setBbox(boolean b) { bbox = true; } public boolean isBbox() { return bbox; } public String getId() { return id; } public void setId(String id) { this.id = id; } public List getTypes() { return types; } public void setTypes(List types) { this.types = types; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Id: " + id + "\n"); builder.append("\tType: " + types + "\n"); return builder.toString(); } } /** * Augments the test result with supplementary attributes in the event that a test * method failed. The "request" attribute contains a String representing the request * entity (POST method) or query component (GET method). The "response" attribute * contains the content of the response entity. * @param result A description of the test result. */ @AfterMethod public void addAttributesOnTestFailure(ITestResult result) { if (result.getStatus() != ITestResult.FAILURE) { return; } if (null != this.reqEntity) { result.setAttribute(REQ_ATTR, this.reqEntity.toString()); } if (null != this.reqEntity) { String request = ""; if (this.reqEntity instanceof HttpGet) { request = this.reqEntity.toString(); } else { // https://github.com/opengeospatial/ets-ogcapi-processes10/issues/51 try { HttpPost postRequest = (HttpPost) this.reqEntity; result.setAttribute(REQ_POST_ATTR, postRequest.toString()); request = JsonUtils.inputStreamToString(postRequest.getEntity().getContent()); // we have to add a "<" at the start, because this is used by TEAM // Engine EarlReporter // to differentiate between GET and POST. request = "\n" + request; } catch (Exception e) { TestSuiteLogger.log(Level.WARNING, "Could not get POST endpoint URI.", e); } } result.setAttribute(REQ_ATTR, request); } if (null != this.rspEntity) { StringBuilder response = new StringBuilder(); if (this.rspEntity instanceof InputStream) { try { response = response.append(JsonUtils.inputStreamToString((InputStream) rspEntity)); } catch (IOException e) { TestSuiteLogger.log(Level.WARNING, "Could not write response to String.", e); } } else if (rspEntity instanceof String) { response = response.append((String) rspEntity); } String responseString = JsonUtils.prettifyString(response.toString()); if (response.length() > MAX_RSP_ATTR_LENGTH) { response = new StringBuilder(); response.append(responseString); response.delete(MAX_RSP_ATTR_LENGTH, response.length()); responseString = response.toString(); } result.setAttribute(RSP_ATTR, responseString); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy