diff --git a/.gitignore b/.gitignore
index 2ddd19a..f6a7666 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
target
*.iml
.idea
+.classpath
+.project
+.settings
diff --git a/README.md b/README.md
index d6a107d..947d3f7 100644
--- a/README.md
+++ b/README.md
@@ -132,6 +132,10 @@ Endpoints are configured in `ws-mock.properties` file under `resources` folder.
SERVICE[i].WSDL
name of wsdl file, relevant only to SOAP webservices; the wsdl file should be placed in the classpath visible to the mock service application
+
+ SERVICE[i].VALIDATE_SCHEMA
+ boolean value true to validate, or false (or not present at all) to not validate namespaces of request as defined in WSDL file
+
SERVICE[i].OPERATION[j].INPUT_MESSAGE
(optional) root element of request message; relevant only to SOAP webservices; skip this if WSDL is provided, this information will be read from the WSDL file
diff --git a/src/main/java/fi/mystes/http/api/PATCH.java b/src/main/java/fi/mystes/http/api/PATCH.java
new file mode 100644
index 0000000..8da0f08
--- /dev/null
+++ b/src/main/java/fi/mystes/http/api/PATCH.java
@@ -0,0 +1,15 @@
+package fi.mystes.http.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.ws.rs.HttpMethod;
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@HttpMethod("PATCH")
+public @interface PATCH {
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/sf/jaceko/mock/resource/RestEndpointResource.java b/src/main/java/net/sf/jaceko/mock/resource/RestEndpointResource.java
index 10979eb..bfa8235 100755
--- a/src/main/java/net/sf/jaceko/mock/resource/RestEndpointResource.java
+++ b/src/main/java/net/sf/jaceko/mock/resource/RestEndpointResource.java
@@ -26,6 +26,8 @@
import net.sf.jaceko.mock.service.RequestExecutor;
import org.apache.log4j.Logger;
+import fi.mystes.http.api.PATCH;
+
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
@@ -113,6 +115,23 @@ public Response performPutRequest(@PathParam("serviceName") String serviceName,
LOG.debug("serviceName: " + serviceName + ", response:" + mockResponse);
return buildWebserviceResponse(mockResponse);
}
+
+ @PATCH
+ @Consumes({"text/*", "application/*"})
+ public Response performPatchRequest(@PathParam("serviceName") String serviceName, @Context HttpHeaders headers, String request) {
+ return performPatchRequest(serviceName, null, headers, request);
+ }
+
+ @PATCH
+ @Path("/{postfix: (([^/]+?(/)?)+?)}")
+ @Consumes({"text/*", "application/*"})
+ public Response performPatchRequest(@PathParam("serviceName") String serviceName, @PathParam("postfix") String resourcePath,
+ @Context HttpHeaders headers, String request) {
+ validateResourcePath(serviceName, resourcePath);
+ MockResponse mockResponse = svcLayer.performRequest(serviceName, "PATCH", request, null, resourcePath, headers.getRequestHeaders());
+ LOG.debug("serviceName: " + serviceName + ", response:" + mockResponse);
+ return buildWebserviceResponse(mockResponse);
+ }
@DELETE
public Response performDeleteRequest(@PathParam("serviceName") String serviceName, @Context HttpHeaders headers) {
diff --git a/src/main/java/net/sf/jaceko/mock/service/PropertyProcessor.java b/src/main/java/net/sf/jaceko/mock/service/PropertyProcessor.java
index 215218e..0c321ee 100755
--- a/src/main/java/net/sf/jaceko/mock/service/PropertyProcessor.java
+++ b/src/main/java/net/sf/jaceko/mock/service/PropertyProcessor.java
@@ -81,6 +81,8 @@ public class PropertyProcessor {
private static final String BINARY = "BINARY";
private static final String NAMESPACE = "NAMESPACE";
+
+ private static final String VALIDATE_SCHEMA = "VALIDATE_SCHEMA";
private static final Pattern SERVICE_PATTERN = Pattern.compile("^SERVICE\\[([0-9]+)\\]$");
private static final Pattern OPERATION_PATTERN = Pattern.compile("^OPERATION\\[([0-9]+)\\]$");
@@ -158,9 +160,30 @@ private void setServiceProperties(final WebService service, final String service
service.setIgnoreXmlDeclaration(Boolean.valueOf(propertyValue));
} else if (serviceProperty.equals(ENABLE_RESOURCE_PATHS)) {
service.setEnableResourcePaths(Boolean.valueOf(propertyValue));
+ } else if (serviceProperty.equals(VALIDATE_SCHEMA) && propertyValue.equals("true")) {
+ StringBuilder operationsNamespaces = getCommaSeparatedWsdlNamespaces();
+
+ Collection operations = service.getOperations();
+ for(WebserviceOperation operation : operations) {
+ operation.setNameSpaces(operationsNamespaces.toString());
+ }
}
}
+ private StringBuilder getCommaSeparatedWsdlNamespaces() {
+ StringBuilder operationsNamespaces = new StringBuilder();
+ Map namespaces = wsdlProcessor.getWsdlNamespaces();
+ boolean first = true;
+ for (String ns : namespaces.values()) {
+ if (!first) {
+ operationsNamespaces.append(",");
+ }
+ operationsNamespaces.append(ns);
+ first = false;
+ }
+ return operationsNamespaces;
+ }
+
private WebService getService(final Map services, final int serviceIndex) {
WebService service = services.get(serviceIndex);
if (service == null) {
@@ -207,10 +230,12 @@ private void setDefaultResponseText(final WebserviceOperation operation) {
if( operation.isBinary() ) {
operation.setDefaultResponseBinaryContent(fileReader.readBinaryFileContents(operation.getDefaultResponseFile()));
} else {
- final String fileText = fileReader.readFileContents(operation.getDefaultResponseFile());
- if (fileText != null) {
- operation.setDefaultResponseText(fileText);
- }
+ if (operation.getDefaultResponseFile() != null) {
+ final String fileText = fileReader.readFileContents(operation.getDefaultResponseFile());
+ if (fileText != null) {
+ operation.setDefaultResponseText(fileText);
+ }
+ }
}
}
diff --git a/src/main/java/net/sf/jaceko/mock/service/WsdlProcessor.java b/src/main/java/net/sf/jaceko/mock/service/WsdlProcessor.java
index 4eb99ce..56c09d9 100755
--- a/src/main/java/net/sf/jaceko/mock/service/WsdlProcessor.java
+++ b/src/main/java/net/sf/jaceko/mock/service/WsdlProcessor.java
@@ -43,6 +43,7 @@ public class WsdlProcessor {
private static final Logger LOG = Logger.getLogger(WsdlProcessor.class);
private WSDLFactory factory;
+ private Map namespaces;
public WsdlProcessor() {
try {
@@ -59,6 +60,7 @@ public List getOperationsFromWsdl(final String wsdlFileName
WSDLReader wsdlReader = factory.newWSDLReader();
try {
Definition def = wsdlReader.readWSDL(null, new InputSource(new StringReader(fileText)));
+ namespaces = def.getNamespaces();
SoapMessageBuilder soapMessageBuilder = new SoapMessageBuilder(def, fileText);
Map bindingsMap = def.getBindings();
Collection bindings = bindingsMap.values();
@@ -101,5 +103,15 @@ public List getOperationsFromWsdl(final String wsdlFileName
return mockOperations;
}
+
+ /**
+ * Gets namespaces parsed from given WSDL in getOperationsFromWsdl method.
+ * getOperationsFromWsdl must first be invoked.
+ *
+ * @return Map containing prefixes as keys and namespaces as values
+ */
+ public Map getWsdlNamespaces() {
+ return namespaces;
+ }
}
diff --git a/src/test/java/net/sf/jaceko/mock/it/WsdlProcessingIntegrationTest.java b/src/test/java/net/sf/jaceko/mock/it/WsdlProcessingIntegrationTest.java
index 9155a64..ac30252 100755
--- a/src/test/java/net/sf/jaceko/mock/it/WsdlProcessingIntegrationTest.java
+++ b/src/test/java/net/sf/jaceko/mock/it/WsdlProcessingIntegrationTest.java
@@ -33,6 +33,9 @@ public class WsdlProcessingIntegrationTest {
private static final String SERVICES = "http://localhost:8080/mock/services";
private static final String HELLO_MOCK_ENDPOINT = "http://localhost:8080/mock/services/SOAP/hello-soap-withwsdl/endpoint";
+
+ private static final String HELLO_MOCK_ENDPOINT_SCHEMA_CHECK = "http://localhost:8080/mock/services/SOAP/hello-soap-withwsdl-and-schema-check/endpoint";
+
private static final String HELLO_REQUEST = "\r\n"
+ " \r\n"
@@ -41,6 +44,14 @@ public class WsdlProcessingIntegrationTest {
+ " {0} \r\n"
+ " \r\n"
+ " \r\n" + " ";
+
+ private static final String HELLO_REQUEST_INVALID_NS = "\r\n"
+ + " \r\n"
+ + " \r\n"
+ + " \r\n"
+ + " {0} \r\n"
+ + " \r\n"
+ + " \r\n" + " ";
private static final String CONVERSION_RATE_ENDPOINT = "http://localhost:8080/mock/services/SOAP/webservicex-rate-convertor/endpoint";
private static final String CONVERSION_RATE_REQUEST = "\r\n"
@@ -104,5 +115,14 @@ public void shouldReturnDefaultHelloResponseGeneratedFromWsdlFile() throws Clien
Document serviceResponseDoc = new DocumentImpl(response.getBody());
assertThat(serviceResponseDoc, hasXPath("//Envelope/Body/sayHelloResponse/greeting"));
}
+
+ @Test
+ public void shouldResponseWithUndefinedWebserviceOperationDueToInvalidNamespaceUsingWsdlFile() throws ClientProtocolException, IOException,
+ ParserConfigurationException, SAXException {
+
+ MockResponse response = requestSender.sendPostRequest(HELLO_MOCK_ENDPOINT_SCHEMA_CHECK, HELLO_REQUEST_INVALID_NS, MediaType.TEXT_XML);
+ assertThat(response.getCode(), is(HttpStatus.SC_NOT_FOUND));
+
+ }
}
diff --git a/src/test/java/net/sf/jaceko/mock/resource/RestEndpointResourceTest.java b/src/test/java/net/sf/jaceko/mock/resource/RestEndpointResourceTest.java
index 785318a..6f68850 100755
--- a/src/test/java/net/sf/jaceko/mock/resource/RestEndpointResourceTest.java
+++ b/src/test/java/net/sf/jaceko/mock/resource/RestEndpointResourceTest.java
@@ -243,6 +243,42 @@ public void shouldReturnPUT_CONFLICTResponse() {
assertThat((String) response.getEntity(), is(responseReturnedByServiceLayer));
}
+
+ @Test
+ public void shouldPerformPatchRequest() {
+ String request = "def ";
+ resource.performPatchRequest(SERVICE_NAME, mockHttpHeaders, request);
+ verify(requestExecutor).performRequest(SERVICE_NAME, "PATCH", request, null, null, headers);
+ }
+
+ @Test
+ public void shouldPerformPatchRequestWithHeaders() {
+ String request = "def ";
+
+ headers.putSingle("someheader", "headervalue");
+ headers.putSingle("someotherheader", "anotherheadervalue");
+
+ resource.performPatchRequest(SERVICE_NAME, mockHttpHeaders, request);
+
+ verify(requestExecutor).performRequest(SERVICE_NAME, "PATCH", request, null, null, headers);
+ }
+
+ @Test
+ public void shouldPerformPatchRequestPassingResourceId() {
+ String resourceId = "resId12";
+ String request = "abc ";
+ resource.performPatchRequest(SERVICE_NAME, resourceId, mockHttpHeaders, request);
+ verify(requestExecutor).performRequest(SERVICE_NAME, "PATCH", request, null, resourceId, headers);
+ }
+
+ @Test
+ public void shouldReturnPATCH_CONFLICTResponse() {
+ String responseReturnedByServiceLayer = "someResponse123";
+ when(requestExecutor.performRequest(anyString(), anyString(), anyString(), anyString(), anyString(), any(MultivaluedMap.class))).thenReturn(
+ new MockResponse(responseReturnedByServiceLayer, 409));
+ Response response = resource.performPatchRequest(SERVICE_NAME, mockHttpHeaders, null);
+ assertThat((String) response.getEntity(), is(responseReturnedByServiceLayer));
+ }
@Test
public void shouldPerformDeleteRequest() {
diff --git a/src/test/java/net/sf/jaceko/mock/service/PropertyProcessorFileReadingTest.java b/src/test/java/net/sf/jaceko/mock/service/PropertyProcessorFileReadingTest.java
index 2824c52..8a90654 100755
--- a/src/test/java/net/sf/jaceko/mock/service/PropertyProcessorFileReadingTest.java
+++ b/src/test/java/net/sf/jaceko/mock/service/PropertyProcessorFileReadingTest.java
@@ -7,7 +7,10 @@
import net.sf.jaceko.mock.model.webservice.WebService;
import net.sf.jaceko.mock.model.webservice.WebserviceOperation;
import net.sf.jaceko.mock.util.FileReader;
+
+import org.hamcrest.core.IsNull;
import org.junit.Test;
+import org.mockito.internal.matchers.*;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
@@ -22,7 +25,7 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.core.IsEqual.equalTo;
-import static org.hamcrest.core.IsNull.notNullValue;
+import static org.hamcrest.core.IsNull.*;
import static org.hamcrest.xml.HasXPath.hasXPath;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
@@ -38,7 +41,8 @@ public PropertyProcessorFileReadingTest() {
@Test
public void shouldReadWsdlContentsFromFile() throws IOException, ParserConfigurationException, SAXException {
String propertyString = "SERVICE[0].NAME=ticketing\r\n" + "SERVICE[0].WSDL=hello-for-unit-tests.wsdl\r\n"
- + "SERVICE[0].TYPE=SOAP\r\n" + "SERVICE[0].OPERATION[0].INPUT_MESSAGE=someRequest\r\n";
+ + "SERVICE[0].TYPE=SOAP\r\n" + "SERVICE[0].OPERATION[0].INPUT_MESSAGE=someRequest\r\n"
+ + "SERVICE[0].VALIDATE_SCHEMA=true";
Reader reader = new StringReader(propertyString);
MockConfigurationHolder configuration = propertyProcessor.process(reader);
@@ -47,7 +51,7 @@ public void shouldReadWsdlContentsFromFile() throws IOException, ParserConfigura
String wsdlText = soapService.getWsdlText();
Document wsdlDoc = new DocumentImpl(wsdlText);
assertThat(wsdlDoc, hasXPath("/definitions/message/@name", equalTo("SayHelloRequest")));
-
+ assertThat(soapService.getOperations().iterator().next().getNameSpaces(), is(notNullValue()));
}
@Test
@@ -67,7 +71,6 @@ public void shouldReadDefaultResponseContentsFromFile() throws IOException, Pars
assertThat(responseDoc, hasXPath("/dummyResponse/reqId", equalTo("789789")));
assertThat(responseDoc, hasXPath("/dummyResponse/status", equalTo("OK")));
-
}
@Test
@@ -82,6 +85,7 @@ public void shouldContinueIfResponseFileNotFound() throws IOException, ParserCon
WebService soapService = services.iterator().next();
WebserviceOperation operation = soapService.getOperation(0);
assertThat(operation, notNullValue());
+ assertThat(operation.getNameSpaces(), nullValue());
}
diff --git a/src/test/java/net/sf/jaceko/mock/service/WsdlProcessorTest.java b/src/test/java/net/sf/jaceko/mock/service/WsdlProcessorTest.java
index b6c55d5..fc288ee 100755
--- a/src/test/java/net/sf/jaceko/mock/service/WsdlProcessorTest.java
+++ b/src/test/java/net/sf/jaceko/mock/service/WsdlProcessorTest.java
@@ -4,6 +4,9 @@
import net.sf.jaceko.mock.matcher.OperationHavingNameEqualTo;
import net.sf.jaceko.mock.model.webservice.WebserviceOperation;
import net.sf.jaceko.mock.util.FileReader;
+
+import org.hamcrest.core.IsNot;
+import org.hamcrest.core.IsNull;
import org.junit.Test;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
@@ -32,7 +35,8 @@ public void shouldFetchOperationsFromWsdlFile_DocumetStyle() {
assertThat(operationsFromWsdl, hasItem(new OperationHavingNameEqualTo("lockRequestElement")));
assertThat(operationsFromWsdl, hasItem(new OperationHavingNameEqualTo("unlockRequestElement")));
assertThat(operationsFromWsdl, hasItem(new OperationHavingNameEqualTo("purgeRequestElement")));
-
+ assertThat(wsdlProcessor.getWsdlNamespaces().size(), is(4));
+
}
@Test
@@ -41,7 +45,6 @@ public void shouldFetchOperationsFromWsdlFile_RPCStyle() {
fileReader.readFileContents("hello-for-unit-tests.wsdl"));
assertThat(operationsFromWsdl.size(), is(1));
assertThat(operationsFromWsdl, hasItem(new OperationHavingNameEqualTo("sayHello")));
-
}
@Test
diff --git a/src/test/resources/it/hello-and-schema-check.wsdl b/src/test/resources/it/hello-and-schema-check.wsdl
new file mode 100755
index 0000000..23dc4cf
--- /dev/null
+++ b/src/test/resources/it/hello-and-schema-check.wsdl
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Service that says hello
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/it/ws-mock.properties b/src/test/resources/it/ws-mock.properties
index 1d9ade4..b689aaa 100755
--- a/src/test/resources/it/ws-mock.properties
+++ b/src/test/resources/it/ws-mock.properties
@@ -88,3 +88,8 @@ SERVICE[9].OPERATION[0].BINARY=true
SERVICE[9].OPERATION[0].INPUT_MESSAGE=dummySoapRequest
SERVICE[9].OPERATION[0].DEFAULT_RESPONSE=default_soap_multipart_response.dat
SERVICE[9].OPERATION[0].DEFAULT_RESPONSE_CONTENT_TYPE=multipart/related;type="application/xop+xml";start="http://tempuri.org/0";boundary="boundary123123";start-info="application/soap+xml"
+
+SERVICE[10].NAME=hello-soap-withwsdl-and-schema-check
+SERVICE[10].WSDL=hello-schema-check.wsdl
+SERVICE[10].TYPE=SOAP
+SERVICE[10].VALIDATE_SCHEMA=true
\ No newline at end of file