/**
* Copyright (c) Codice Foundation
* <p/>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p/>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package org.codice.ddf.itests.common.csw.mock;
import static org.junit.Assert.fail;
import static com.xebialabs.restito.semantics.Action.bytesContent;
import static com.xebialabs.restito.semantics.Action.contentType;
import static com.xebialabs.restito.semantics.Action.ok;
import static com.xebialabs.restito.semantics.Condition.get;
import static com.xebialabs.restito.semantics.Condition.parameter;
import static com.xebialabs.restito.semantics.Condition.post;
import static com.xebialabs.restito.semantics.Condition.withPostBodyContaining;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.xebialabs.restito.builder.stub.StubHttp;
import com.xebialabs.restito.builder.verify.VerifyHttp;
import com.xebialabs.restito.server.StubServer;
/**
* Encompasses a Restito CSW Stub Server for use in integration testing. Handles handshake responses
* and federated query responses for a csw endpoint.
*/
public class FederatedCswMockServer {
protected static final Logger LOGGER = LoggerFactory.getLogger(FederatedCswMockServer.class);
private final String sourceId;
private final String httpRoot;
private final int port;
private StubServer cswStubServer;
private String defaultCapabilityResponse = getDefaultResponseResource(
"default-csw-mock-get-capabilities-response.xml");
private String defaultQueryResponseResource = getDefaultResponseResource(
"default-csw-mock-query-response.xml");
private String defaultInsertTransactionResponse = getDefaultResponseResource(
"default-csw-mock-insert-transaction-response.xml");
private String defaultUpdateTransactionResponse = getDefaultResponseResource(
"default-csw-mock-update-transaction-response.xml");
private String defaultDeleteTransactionResponse = getDefaultResponseResource(
"default-csw-mock-delete-transaction-response.xml");
/**
* Constructor for the federated CSW Restito stub server.
*
* @param sourceId DDF sourceId to give to the stub server.
* @param httpRoot httpRoot address. Typically the non-secure root "http://localhost:".
* @param port Port number on which to respond.
*/
public FederatedCswMockServer(String sourceId, String httpRoot, int port) {
if (httpRoot.endsWith(":")) {
this.httpRoot = httpRoot.substring(0, httpRoot.length() - 1);
} else {
this.httpRoot = httpRoot;
}
this.sourceId = sourceId;
this.port = port;
}
/**
* Sets the default response for the {@code GetCapabilities} request. Will be used when this
* stub server is started and must be set before {@link #start()} is called.
* </p>
* If a different response is needed after startup, the normal {@link #whenHttp()} should be
* used instead of replacing this default response.
*
* @param response response to be returned
*/
public void setupDefaultCapabilityResponseExpectation(String response) {
this.defaultCapabilityResponse = response;
}
/**
* Sets the default response for the {@code GetRecords} request. Will be used when this stub
* server is started and must be set before {@link #start()} is called.
* </p>
* If a different response is needed after startup, the normal {@link #whenHttp()} should be
* used instead of replacing this default response.
*
* @param response response to be returned
*/
public void setupDefaultQueryResponseExpectation(String response) {
defaultQueryResponseResource = response;
}
public void setupDefaultInsertTransactionResponseExpectation(String response) {
defaultInsertTransactionResponse = response;
}
public void setupDefaultUpdateTransactionResponseExpectation(String response) {
defaultUpdateTransactionResponse = response;
}
public void setupDefaultDeleteTransactionResponseExpectation(String response) {
defaultDeleteTransactionResponse = response;
}
/**
* Starts the Restito stub server.
*/
public void start() {
try {
cswStubServer = new StubServer(port).run();
setupDefaultCapabilityResponseExpectation();
setupDefaultQueryResponseExpectation();
setupDefaultTransactionResponseExpectation();
} catch (IOException | RuntimeException e) {
fail(String.format("Failed to setup %s: %s",
getClass().getSimpleName(),
e.getMessage()));
}
}
/**
* Stops the Restito stub server.
*/
public void stop() {
cswStubServer.stop();
}
/**
* Resets the Restito server by stopping and starting it.
*/
public void reset() {
// There is no way in version 0.7 of Restito to clear the calls and reset the
// StubServer so we need to stop the current one and create a new instance.
// TODO - Replace this code when the new version of Restito is used.
stop();
start();
}
/**
* Returns StubHttp's whenHttp method with the stub server as the parameter. Use is the same.
* Sets up an Action when a specific Http call is made.
*
* @return StubHttp using whenHttp method with the stub server as the parameter.
*/
public StubHttp whenHttp() {
return StubHttp.whenHttp(cswStubServer);
}
/**
* Returns VerifyHttp's verifyHttp method with the stub server as the parameter. Use is the same.
* Provides itest verification when a specific Http call is made.
*
* @return VerifyHttp using verifyHttp method with the stub server as the parameter.
*/
public VerifyHttp verifyHttp() {
return VerifyHttp.verifyHttp(cswStubServer);
}
/**
* Get the port being used by the stub server.
*
* @return the port being used by the stub server.
*/
public int getPort() {
return port;
}
/**
* Get the root url being used by the stub server.
*
* @return the root url being used by the stub server.
*/
public String getRoot() {
return httpRoot;
}
/**
* Returns the restito stub server to allow for any unsupported actions
*
* @return the stub server managed by this class
*/
public StubServer getServer() {
return cswStubServer;
}
private void setupDefaultCapabilityResponseExpectation() throws IOException {
String document = substituteTags(defaultCapabilityResponse);
LOGGER.debug("Capability response: \n{}", document);
whenHttp().match(get("/services/csw"), parameter("request", "GetCapabilities"))
.then(ok(), contentType("text/xml"), bytesContent(document.getBytes()));
}
private void setupDefaultQueryResponseExpectation() throws IOException {
String document = substituteTags(defaultQueryResponseResource);
LOGGER.debug("Query response: \n{}", defaultQueryResponseResource);
whenHttp().match(post("/services/csw"), withPostBodyContaining("GetRecords"))
.then(ok(), contentType("text/xml"), bytesContent(document.getBytes()));
}
private void setupDefaultTransactionResponseExpectation() throws IOException {
LOGGER.debug("Insert response: \n{}", defaultInsertTransactionResponse);
whenHttp().match(post("/services/csw"),
withPostBodyContaining("Transaction"),
withPostBodyContaining("Insert"))
.then(ok(),
contentType("text/xml"),
bytesContent(defaultInsertTransactionResponse.getBytes()));
LOGGER.debug("Update response: \n{}", defaultUpdateTransactionResponse);
whenHttp().match(post("/services/csw"),
withPostBodyContaining("Transaction"),
withPostBodyContaining("Update"))
.then(ok(),
contentType("text/xml"),
bytesContent(defaultUpdateTransactionResponse.getBytes()));
LOGGER.debug("Delete response: \n{}", defaultDeleteTransactionResponse);
whenHttp().match(post("/services/csw"),
withPostBodyContaining("Transaction"),
withPostBodyContaining("Delete"))
.then(ok(),
contentType("text/xml"),
bytesContent(defaultDeleteTransactionResponse.getBytes()));
}
private String substituteTags(String document) {
String resultDocument = substituteSourceId(document);
resultDocument = substitutePortNumber(resultDocument);
return substituteHttpRoot(resultDocument);
}
private String substitutePortNumber(String document) {
return document.replaceAll("\\$port\\$", Integer.toString(port));
}
private String substituteSourceId(String document) {
return document.replaceAll("\\$sourceId\\$", sourceId);
}
private String substituteHttpRoot(String document) {
return document.replaceAll("\\$httpRoot\\$", httpRoot);
}
private String getDefaultResponseResource(String resourceName) {
try {
return IOUtils.toString(FederatedCswMockServer.class.getClassLoader()
.getResourceAsStream("/" + resourceName));
} catch (IOException e) {
return null;
}
}
}