From fa05c9ed966ed8af6a84928bfcfe7774593e9fa0 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Fri, 18 Jun 2010 13:02:24 +0000 Subject: [PATCH] SWS-544 - Add test framework for Spring WS client --- parent/pom.xml | 2 +- pom.xml | 19 +- test/pom.xml | 11 + .../ws/mock/client/DiffMatcher.java | 59 +++++ .../client/ExceptionResponseCallback.java | 47 ++++ .../ws/mock/client/MockSenderConnection.java | 213 ++++++++++++++++++ .../client/MockWebServiceMessageSender.java | 192 ++++++++++++++++ .../ws/mock/client/PayloadMatcher.java | 104 +++++++++ .../mock/client/PayloadResponseCallback.java | 54 +++++ .../ws/mock/client/RequestExpectations.java | 78 +++++++ .../ws/mock/client/RequestMatcher.java | 42 ++++ .../ws/mock/client/ResponseActions.java | 120 ++++++++++ .../ws/mock/client/ResponseCallback.java | 35 +++ .../client/SoapFaultResponseCallback.java | 87 +++++++ .../ws/mock/client/SoapHeaderMatcher.java | 66 ++++++ .../client/ExceptionResponseCallbackTest.java | 38 ++++ .../mock/client/MockSenderConnectionTest.java | 101 +++++++++ .../MockWebServiceMessageSenderTest.java | 136 +++++++++++ .../ws/mock/client/PayloadMatcherTest.java | 83 +++++++ .../ws/mock/client/SoapHeaderMatcherTest.java | 70 ++++++ test/src/test/resources/log4j.properties | 6 + test/template.mf | 13 +- 22 files changed, 1569 insertions(+), 7 deletions(-) create mode 100644 test/src/main/java/org/springframework/ws/mock/client/DiffMatcher.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/ExceptionResponseCallback.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/MockSenderConnection.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/MockWebServiceMessageSender.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/PayloadMatcher.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/PayloadResponseCallback.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/RequestExpectations.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/RequestMatcher.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/ResponseActions.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/ResponseCallback.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/SoapFaultResponseCallback.java create mode 100644 test/src/main/java/org/springframework/ws/mock/client/SoapHeaderMatcher.java create mode 100644 test/src/test/java/org/springframework/ws/mock/client/ExceptionResponseCallbackTest.java create mode 100644 test/src/test/java/org/springframework/ws/mock/client/MockSenderConnectionTest.java create mode 100644 test/src/test/java/org/springframework/ws/mock/client/MockWebServiceMessageSenderTest.java create mode 100644 test/src/test/java/org/springframework/ws/mock/client/PayloadMatcherTest.java create mode 100644 test/src/test/java/org/springframework/ws/mock/client/SoapHeaderMatcherTest.java create mode 100644 test/src/test/resources/log4j.properties diff --git a/parent/pom.xml b/parent/pom.xml index c884fc1c..6c7d09d6 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -677,7 +677,7 @@ xmlunit xmlunit - 1.1 + 1.3 test diff --git a/pom.xml b/pom.xml index 44aa057e..3f987907 100644 --- a/pom.xml +++ b/pom.xml @@ -23,10 +23,10 @@ 2005 - poutsma + apoutsma Arjen Poutsma - arjen.poutsma@springsource.com - SpringSource + apoutsma@vmware.com + SpringSource - a division of VMware http://www.springsource.com Project Admin @@ -34,6 +34,15 @@ +1 + + tareqa + Tareq Abed Rabbo + tareq.abedrabbo@gmail.com + + Developer + + +1 + @@ -52,7 +61,8 @@ Giovanni Cuccu - Tareq Abed Rabbo + Lukas Krecan + http://blog.krecan.net @@ -96,6 +106,7 @@ core support security + test archetype diff --git a/test/pom.xml b/test/pom.xml index 27b52d5a..93c4e1f4 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -38,5 +38,16 @@ org.springframework.ws spring-ws-core + + + junit + junit + compile + + + xmlunit + xmlunit + compile + diff --git a/test/src/main/java/org/springframework/ws/mock/client/DiffMatcher.java b/test/src/main/java/org/springframework/ws/mock/client/DiffMatcher.java new file mode 100644 index 00000000..0dc41e3f --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/DiffMatcher.java @@ -0,0 +1,59 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; + +import org.springframework.ws.WebServiceMessage; +import org.springframework.xml.transform.TransformerObjectSupport; + +import org.custommonkey.xmlunit.Diff; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; +import static org.custommonkey.xmlunit.XMLAssert.fail; + +/** + * Implementation of {@link RequestMatcher} based on XMLUnit's {@link Diff}. + * + * @author Arjen Poutsma + * @since 2.0 + */ +abstract class DiffMatcher extends TransformerObjectSupport implements RequestMatcher { + + public final void match(WebServiceMessage request) throws IOException, AssertionError { + try { + Diff diff = createDiff(request); + assertXMLEqual(diff, true); + } + catch (IOException ex) { + throw ex; + } + catch (Exception ex) { + fail("Could not create Diff: " + ex.getMessage()); + } + } + + /** + * Creates a {@link Diff} for the given request message. + * + * @param request the request message + * @return the diff + * @throws Exception in case of errors + */ + protected abstract Diff createDiff(WebServiceMessage request) throws Exception; + +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/ExceptionResponseCallback.java b/test/src/main/java/org/springframework/ws/mock/client/ExceptionResponseCallback.java new file mode 100644 index 00000000..86980950 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/ExceptionResponseCallback.java @@ -0,0 +1,47 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; + +import org.springframework.ws.WebServiceMessage; + +/** + * @author Arjen Poutsma + * @since 2.0 + */ +class ExceptionResponseCallback implements ResponseCallback { + + private final Exception exception; + + ExceptionResponseCallback(IOException exception) { + this.exception = exception; + } + + ExceptionResponseCallback(RuntimeException exception) { + this.exception = exception; + } + + public void doWithResponse(WebServiceMessage message) throws IOException { + if (exception instanceof IOException) { + throw (IOException) exception; + } + else { + throw (RuntimeException) exception; + } + } +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/MockSenderConnection.java b/test/src/main/java/org/springframework/ws/mock/client/MockSenderConnection.java new file mode 100644 index 00000000..5d3f8e93 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/MockSenderConnection.java @@ -0,0 +1,213 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; +import java.net.URI; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import javax.xml.namespace.QName; +import javax.xml.transform.Source; + +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.WebServiceMessageFactory; +import org.springframework.ws.transport.FaultAwareWebServiceConnection; +import org.springframework.ws.transport.WebServiceConnection; +import org.springframework.xml.transform.TransformerObjectSupport; + +import static org.junit.Assert.fail; + +/** + * Mock implementation of {@link WebServiceConnection}. Implements {@link RequestExpectations} and {@link + * ResponseActions} to form a fluent API. + * + * @author Arjen Poutsma + * @author Lukas Krecan + * @since 2.0 + */ +class MockSenderConnection extends TransformerObjectSupport + implements FaultAwareWebServiceConnection, RequestExpectations, ResponseActions { + + private static final URI ANY_URI = URI.create("ANY"); + + private final List requestMatchers = new LinkedList(); + + private URI uri; + + private ResponseCallback responseCallback; + + private String errorMessage; + + /** Creates a new {@code MockSenderConnection} for use with any URI. */ + MockSenderConnection() { + this.uri = ANY_URI; + } + + /** Creates a new {@code MockSenderConnection} for use with the specified URI. */ + MockSenderConnection(URI uri) { + this.uri = uri; + } + + // RequestExpectations implementation + + public ResponseActions expectPayload(String payload) { + Assert.notNull(payload, "'payload' must not be null"); + return addRequestMatcher(PayloadMatcher.createStringPayloadMatcher(payload)); + } + + public ResponseActions expectPayload(Source payload) { + Assert.notNull(payload, "'payload' must not be null"); + return addRequestMatcher(PayloadMatcher.createSourcePayloadMatcher(payload)); + } + + public ResponseActions expectPayload(Resource payload) { + Assert.notNull(payload, "'payload' must not be null"); + return addRequestMatcher(PayloadMatcher.createResourcePayloadMatcher(payload)); + } + + public ResponseActions expectSoapHeader(QName soapHeaderName) { + Assert.notNull(soapHeaderName, "'soapHeaderName' must not be null"); + return addRequestMatcher(new SoapHeaderMatcher(soapHeaderName)); + } + + public ResponseActions addRequestMatcher(RequestMatcher requestMatcher) { + requestMatchers.add(requestMatcher); + return this; + } + + // ResponseActions implementation + + public RequestExpectations and() { + return this; + } + + public void andRespondWithPayload(Resource resource) { + Assert.notNull(resource, "'resource' must not be null"); + try { + this.responseCallback = new PayloadResponseCallback(resource); + } + catch (IOException ex) { + fail("Could not open [" + resource + "]: " + ex.getMessage()); + } + } + + public void andRespondWithPayload(String payload) { + Assert.notNull(payload, "'payload' must not be null"); + this.responseCallback = new PayloadResponseCallback(payload); + } + + public void andRespondWithError(String errorMessage) { + Assert.hasLength(errorMessage, "'errorMessage' must not be empty"); + this.errorMessage = errorMessage; + } + + public void andThrowException(IOException ioException) { + Assert.notNull(ioException, "'ex' must not be null"); + this.responseCallback = new ExceptionResponseCallback(ioException); + } + + public void andThrowException(RuntimeException ex) { + Assert.notNull(ex, "'ex' must not be null"); + this.responseCallback = new ExceptionResponseCallback(ex); + } + + public void andRespondWithMustUnderstandFault(String faultStringOrReason, Locale locale) { + Assert.hasLength(faultStringOrReason, "'faultStringOrReason' must not be empty"); + this.responseCallback = SoapFaultResponseCallback.createMustUnderstandFault(faultStringOrReason, locale); + } + + public void andRespondWithClientOrSenderFault(String faultStringOrReason, Locale locale) { + Assert.hasLength(faultStringOrReason, "'faultStringOrReason' must not be empty"); + this.responseCallback = SoapFaultResponseCallback.createClientOrSenderFault(faultStringOrReason, locale); + } + + public void andRespondWithServerOrReceiverFault(String faultStringOrReason, Locale locale) { + Assert.hasLength(faultStringOrReason, "'faultStringOrReason' must not be empty"); + this.responseCallback = SoapFaultResponseCallback.createServerOrReceiverFault(faultStringOrReason, locale); + } + + public void andRespondWithVersionMismatchFault(String faultStringOrReason, Locale locale) { + Assert.hasLength(faultStringOrReason, "'faultStringOrReason' must not be empty"); + this.responseCallback = SoapFaultResponseCallback.createVersionMismatchFault(faultStringOrReason, locale); + } + + public void setResponseCallback(ResponseCallback responseCallback) { + Assert.notNull(responseCallback, "'responseCallback' must not be null"); + this.responseCallback = responseCallback; + } + + // WebServiceConnection implementation + + public void send(WebServiceMessage message) throws IOException { + if (!requestMatchers.isEmpty()) { + for (RequestMatcher requestMatcher : requestMatchers) { + requestMatcher.match(message); + } + } + else { + throw new AssertionError("Unexpected send() for [" + message + "]"); + } + + } + + public WebServiceMessage receive(WebServiceMessageFactory messageFactory) throws IOException { + if (responseCallback != null) { + WebServiceMessage response = messageFactory.createWebServiceMessage(); + responseCallback.doWithResponse(response); + return response; + } + else { + return null; + } + } + + public URI getUri() { + return uri; + } + + public boolean hasAnyUri() { + return ANY_URI.equals(uri); + } + + public boolean hasError() throws IOException { + return errorMessage != null; + } + + public String getErrorMessage() throws IOException { + return errorMessage; + } + + public boolean hasFault() throws IOException { + return responseCallback instanceof SoapFaultResponseCallback; + } + + public void setFault(boolean fault) throws IOException { + // Do nothing + } + + public void close() throws IOException { + requestMatchers.clear(); + responseCallback = null; + errorMessage = null; + uri = null; + } + + +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/MockWebServiceMessageSender.java b/test/src/main/java/org/springframework/ws/mock/client/MockWebServiceMessageSender.java new file mode 100644 index 00000000..f0738c4b --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/MockWebServiceMessageSender.java @@ -0,0 +1,192 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; +import java.net.URI; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.springframework.util.Assert; +import org.springframework.ws.transport.WebServiceMessageSender; + +/** + * Main entry point for client-side Web Service testing. Typically used in combination with a {@link + * org.springframework.ws.client.core.WebServiceTemplate WebServiceTemplate}. + *

+ * The typical usage of this mock is similar to any other mocking library (such as EasyMock), that is: + *

    + *
  1. Inject this mock into the {@link org.springframework.ws.client.core.WebServiceTemplate WebServiceTemplate}. + * See {@link org.springframework.ws.client.core.WebServiceTemplate#setMessageSender(WebServiceMessageSender) WebServiceTemplate.setMessageSender()}.
  2. + *
  3. Set up expectations about the URI to connect to, and about the outgoing request message. + * See {@link #whenConnecting()}, {@link #whenConnectingTo(String)}, and {@link RequestExpectations}.
  4. + *
  5. Indicate the desired response actions. See {@link ResponseActions}.
  6. + *
  7. Call {@link #replay()}. + *
  8. Use the {@code WebServiceTemplate} as normal. + *
  9. Call {@link #verify()}. + *
+ * Note that because of the 'fluent' API used by this class, you can typically use the Code Completion features + * offered by your IDE to set up the mocks. + *

+ * For example: + *

+ * // set up
+ * MockWebServiceMessageSender mockMessageSender = new MockWebServiceMessageSender();
+ * AirlineClient client = new AirlineClient(); // AirlineClient extends WebServiceGatewaySupport
+ * client.getWebServiceTemplate().setMessageSender(mockMessageSender);
+ * // expectations
+ * String uri = "http://example.com/airline";
+ * String expectedRequest = "<getFlightsRequest xmlns=\"http://example.com/\" >";
+ * String response = "<getFlightsResponse xmlns=\"http://example.com/\">";
+ * mockMessageSender.whenConnectingTo(uri).expectPayload(request).andRespondWithPayload(response);
+ * mockMessageSender.replay();
+ * // execution
+ * StringResult result = new StringResult();
+ * template.sendSourceAndReceiveToResult(uri, new StringSource(expectedRequest), stringResult);
+ * assertXMLEqual(response, result.toString()); // from XMLUnit
+ * mockMessageSender.verify();
+ * 
+ * + * @author Arjen Poutsma + * @author Lukas Krecan + * @see org.springframework.ws.client.core.WebServiceTemplate#setMessageSender + * @see #whenConnecting() + * @see #whenConnectingTo + * @see RequestExpectations + * @see ResponseActions + * @see #replay() + * @see #verify() + * @since 2.0 + */ +public class MockWebServiceMessageSender implements WebServiceMessageSender { + + private final List expectedConnections = new LinkedList(); + + private Iterator connectionIterator; + + /** Creates a new {@code MockWebServiceMessageSender}. */ + public MockWebServiceMessageSender() { + reset(); + } + + /** + * {@inheritDoc} + *

+ * This implementation checks whether the given URI has been recorded as expected, and throws an {@code AssertionError} if not. + * + * @throws IllegalStateException if this mock is not in {@linkplain #replay() replay} state + * @throws AssertionError if the given URI is not expected + */ + public MockSenderConnection createConnection(URI uri) throws IOException { + Assert.notNull(uri, "'uri' must not be null"); + if (connectionIterator == null) { + throw new IllegalStateException("Please call replay() after recording expected connections"); + } + if (!connectionIterator.hasNext()) { + throw new AssertionError("No further connections expected"); + } + MockSenderConnection currentConnection = connectionIterator.next(); + if (!currentConnection.getUri().equals(uri) && !currentConnection.hasAnyUri()) { + throw new AssertionError("Unexpected connection to \"" + uri + "\""); + } + return currentConnection; + } + + /** Always returns {@code true}. */ + public boolean supports(URI uri) { + return true; + } + + /** + * Sets up an expected connection to the specific URI. Returns a {@link RequestExpectations} object that allows for + * further expectations on the request. + * + * @param uri the URI expected to connect to + * @return the request expectations + */ + public RequestExpectations whenConnectingTo(String uri) { + Assert.hasLength(uri, "'uri' must not be empty"); + return whenConnectingTo(URI.create(uri)); + } + + /** + * Sets up an expected connection to the specific URI. Returns a {@link RequestExpectations} object that allows for + * further expectations on the request. + * + * @param uri the URI expected to connect to + * @return the request expectations + */ + public RequestExpectations whenConnectingTo(URI uri) { + Assert.notNull(uri, "'uri' must not be null"); + MockSenderConnection connection = new MockSenderConnection(uri); + expectedConnections.add(connection); + return connection; + } + + /** + * Sets up an expected connection to any URI. Returns a {@link RequestExpectations} object that allows for + * further expectations on the request. + * + * @return the request expectations + */ + public RequestExpectations whenConnecting() { + MockSenderConnection connection = new MockSenderConnection(); + expectedConnections.add(connection); + return connection; + } + + /** Resets the mock to the state directly after creation. */ + public void reset() { + connectionIterator = null; + expectedConnections.clear(); + } + + /** + * Switches the mock from record state to replay state. + * + * @throws IllegalStateException if this mock already is in replay state. + */ + public void replay() { + Assert.state(connectionIterator == null, "Already in replay state"); + connectionIterator = expectedConnections.iterator(); + } + + /** + * Verifies that all expectations have been met. + * + * @throws IllegalStateException if this mock is in record state + * @throws AssertionError if any expectation have not been met + */ + public void verify() { + Assert.state(connectionIterator != null, "Calling verify() is only allowed after replay()"); + if (connectionIterator.hasNext()) { + StringBuilder builder = new StringBuilder("Expected connection(s) to ["); + while (connectionIterator.hasNext()) { + MockSenderConnection connection = connectionIterator.next(); + builder.append(connection.getUri()); + if (connectionIterator.hasNext()) { + builder.append(", "); + } + } + builder.append(']'); + throw new AssertionError(builder.toString()); + } + } + + +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/PayloadMatcher.java b/test/src/main/java/org/springframework/ws/mock/client/PayloadMatcher.java new file mode 100644 index 00000000..7ad3fbad --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/PayloadMatcher.java @@ -0,0 +1,104 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; + +import org.springframework.core.io.Resource; +import org.springframework.ws.WebServiceMessage; +import org.springframework.xml.sax.SaxUtils; +import org.springframework.xml.transform.StringResult; + +import org.custommonkey.xmlunit.Diff; +import org.custommonkey.xmlunit.XMLUnit; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import static org.custommonkey.xmlunit.XMLAssert.fail; + +/** + * Abstract base class that matches payloads. + * + * @author Arjen Poutsma + * @since 2.0 + */ +abstract class PayloadMatcher extends DiffMatcher { + + @Override + protected final Diff createDiff(WebServiceMessage request) throws Exception { + Source payload = request.getPayloadSource(); + if (payload == null) { + fail("Request message does not contain payload"); + } + return createDiff(payload); + } + + protected abstract Diff createDiff(Source payload) throws Exception; + + public static PayloadMatcher createStringPayloadMatcher(final String control) { + return new PayloadMatcher() { + @Override + protected Diff createDiff(Source payload) throws TransformerException, IOException, SAXException { + StringResult result = new StringResult(); + transform(payload, result); + return new Diff(control, result.toString()); + } + }; + } + + public static PayloadMatcher createResourcePayloadMatcher(final Resource control) { + return new PayloadMatcher() { + @Override + protected Diff createDiff(Source payload) throws IOException, SAXException, TransformerException { + InputSource controlInputSource = SaxUtils.createInputSource(control); + Document controlDocument = XMLUnit.buildDocument(XMLUnit.newControlParser(), controlInputSource); + DOMSource controlSource = new DOMSource(controlDocument); + + DOMResult result = new DOMResult(); + transform(payload, result); + DOMSource resultSource = new DOMSource(result.getNode()); + + return new Diff(controlSource, resultSource); + } + }; + } + + public static PayloadMatcher createSourcePayloadMatcher(final Source control) { + return new PayloadMatcher() { + @Override + protected Diff createDiff(Source payload) throws Exception { + if (control instanceof DOMSource && payload instanceof DOMSource) { + return new Diff((DOMSource) control, (DOMSource) payload); + } + DOMResult controlResult = new DOMResult(); + transform(control, controlResult); + DOMSource controlSource = new DOMSource(controlResult.getNode()); + + DOMResult payloadResult = new DOMResult(); + transform(payload, payloadResult); + DOMSource payloadSource = new DOMSource(payloadResult.getNode()); + + return new Diff(controlSource, payloadSource); + } + }; + } +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/PayloadResponseCallback.java b/test/src/main/java/org/springframework/ws/mock/client/PayloadResponseCallback.java new file mode 100644 index 00000000..c7f3929f --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/PayloadResponseCallback.java @@ -0,0 +1,54 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; + +import org.springframework.core.io.Resource; +import org.springframework.ws.WebServiceMessage; +import org.springframework.xml.transform.ResourceSource; +import org.springframework.xml.transform.StringSource; +import org.springframework.xml.transform.TransformerObjectSupport; + +/** @author Arjen Poutsma */ +class PayloadResponseCallback extends TransformerObjectSupport implements ResponseCallback { + + private final Source payload; + + PayloadResponseCallback(Source payload) { + this.payload = payload; + } + + PayloadResponseCallback(String payload) { + this.payload = new StringSource(payload); + } + + PayloadResponseCallback(Resource payload) throws IOException { + this.payload = new ResourceSource(payload); + } + + public void doWithResponse(WebServiceMessage message) throws IOException { + try { + transform(payload, message.getPayloadResult()); + } + catch (TransformerException ex) { + throw new AssertionError("Could not transform response payload to message: " + ex.getMessage()); + } + } +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/RequestExpectations.java b/test/src/main/java/org/springframework/ws/mock/client/RequestExpectations.java new file mode 100644 index 00000000..775e0f25 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/RequestExpectations.java @@ -0,0 +1,78 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import javax.xml.namespace.QName; +import javax.xml.transform.Source; + +import org.springframework.core.io.Resource; + +/** + * Allows for setting expectations on the request. Implementations of this interface are returned by {@link + * MockWebServiceMessageSender#whenConnectingTo(java.net.URI)}, and by {@link MockWebServiceMessageSender#whenConnecting()}. + * + * @author Arjen Poutsma + * @author Lukas Krecan + * @since 2.0 + */ +public interface RequestExpectations { + + /** + * Records that the mock will expect the given String XML payload. Returns a {@link ResponseActions} object that + * allows for setting up the response. + * + * @param payload the String XML payload + * @return the response actions + */ + ResponseActions expectPayload(String payload); + + /** + * Records that the mock will expect the given {@link Source} payload. Returns a {@link ResponseActions} object that + * allows for setting up the response. + * + * @param payload the payload + * @return the response actions + */ + ResponseActions expectPayload(Source payload); + + /** + * Records that the mock will expect the given {@link Resource} payload. Returns a {@link ResponseActions} object + * that allows for setting up the response. + * + * @param payload the String XML payload + * @return the response actions + */ + ResponseActions expectPayload(Resource payload); + + /** + * Records that the mock will expect the given SOAP header to exist on the outgoing message. Returns a {@link + * ResponseActions} object that allows for setting up the response. + * + * @param soapHeaderName the qualified name of the SOAP header to expect + * @return the response actions + */ + ResponseActions expectSoapHeader(QName soapHeaderName); + + /** + * Adds the {@link RequestMatcher} to the list of expectations. Returns a {@link ResponseActions} object that allows + * for setting up the response. + * + * @param requestMatcher the request matcher + * @return the response actions + */ + ResponseActions addRequestMatcher(RequestMatcher requestMatcher); +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/RequestMatcher.java b/test/src/main/java/org/springframework/ws/mock/client/RequestMatcher.java new file mode 100644 index 00000000..b5fffef2 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/RequestMatcher.java @@ -0,0 +1,42 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; + +import org.springframework.ws.WebServiceMessage; + +/** + * Defines the contract for matching request messages to expectations. + * + * @author Arjen Poutsma + * @author Lukas Krecan + * @since 2.0 + */ +public interface RequestMatcher { + + /** + * Matches the given request message against the expectations. Implementations typically make use of JUnit-based + * assertions. + * + * @param request the request message to make assertions on + * @throws IOException in case of I/O errors + * @throws AssertionError if expectations are not met + */ + void match(WebServiceMessage request) throws IOException, AssertionError; + +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/ResponseActions.java b/test/src/main/java/org/springframework/ws/mock/client/ResponseActions.java new file mode 100644 index 00000000..e65c385e --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/ResponseActions.java @@ -0,0 +1,120 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; +import java.util.Locale; + +import org.springframework.core.io.Resource; + +/** + * Allows for setting up responses. Implementations of this interface are returned by {@link RequestExpectations}. + * + * @author Arjen Poutsma + * @author Lukas Krecan + * @since 2.0 + */ +public interface ResponseActions { + + /** + * Allows for further expectations to be set on the request. + * + * @return the request expectations + */ + RequestExpectations and(); + + /** + * Records that the mock will receive the given String XML as payload response. + * + * @param payload the response payload + */ + void andRespondWithPayload(String payload); + + /** + * Records that the mock will receive the given {@link Resource} as payload response. + * + * @param resource the response payload + */ + void andRespondWithPayload(Resource resource); + + /** + * Records that the mock will respond with the given error message. + * + * @param errorMessage the error message + * @see org.springframework.ws.transport.WebServiceConnection#hasError() + * @see org.springframework.ws.transport.WebServiceConnection#getErrorMessage() + */ + void andRespondWithError(String errorMessage); + + /** + * Records that the mock will respond by throwing the given {@link IOException}. + * + * @param ex the I/O exception + */ + void andThrowException(IOException ex); + + /** + * Records that the mock will respond by throwing the given runtime exception. + * + * @param ex the runtime exception + */ + void andThrowException(RuntimeException ex); + + /** + * Records that the mock will respond with a {@code MustUnderstand} fault. + * + * @param faultStringOrReason the SOAP 1.1 fault string or SOAP 1.2 reason text + * @param locale the language of faultStringOrReason. Optional for SOAP 1.1 + * @see org.springframework.ws.soap.SoapBody#addMustUnderstandFault(String, java.util.Locale) + */ + void andRespondWithMustUnderstandFault(String faultStringOrReason, Locale locale); + + /** + * Records that the mock will respond with a {@code Client} (SOAP 1.1) or {@code Sender} (SOAP 1.2) fault. + * + * @param faultStringOrReason the SOAP 1.1 fault string or SOAP 1.2 reason text + * @param locale the language of faultStringOrReason. Optional for SOAP 1.1 + * @see org.springframework.ws.soap.SoapBody#addClientOrSenderFault(String, java.util.Locale) + */ + void andRespondWithClientOrSenderFault(String faultStringOrReason, Locale locale); + + /** + * Records that the mock will respond with a {@code Server} (SOAP 1.1) or {@code Receiver} (SOAP 1.2) fault. + * + * @param faultStringOrReason the SOAP 1.1 fault string or SOAP 1.2 reason text + * @param locale the language of faultStringOrReason. Optional for SOAP 1.1 + * @see org.springframework.ws.soap.SoapBody#addServerOrReceiverFault(String, java.util.Locale) + */ + void andRespondWithServerOrReceiverFault(String faultStringOrReason, Locale locale); + + /** + * Records that the mock will respond with a {@code VersionMismatch} fault. + * + * @param faultStringOrReason the SOAP 1.1 fault string or SOAP 1.2 reason text + * @param locale the language of faultStringOrReason. Optional for SOAP 1.1 + * @see org.springframework.ws.soap.SoapBody#addVersionMismatchFault(String, java.util.Locale) + */ + void andRespondWithVersionMismatchFault(String faultStringOrReason, Locale locale); + + /** + * Sets the {@link ResponseCallback} for this mock. + * + * @param responseCallback the response callback + */ + void setResponseCallback(ResponseCallback responseCallback); + +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/ResponseCallback.java b/test/src/main/java/org/springframework/ws/mock/client/ResponseCallback.java new file mode 100644 index 00000000..d64f5204 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/ResponseCallback.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; + +import org.springframework.ws.WebServiceMessage; + +/** + * Callback interface for code that operates on a {@link WebServiceMessage}. Defines the contract for matching request + * messages to expectations. + * + * @author Arjen Poutsma + * @author Lukas Krecan + * @since 2.0 + */ +public interface ResponseCallback { + + void doWithResponse(WebServiceMessage message) throws IOException; + +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/SoapFaultResponseCallback.java b/test/src/main/java/org/springframework/ws/mock/client/SoapFaultResponseCallback.java new file mode 100644 index 00000000..49024bf1 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/SoapFaultResponseCallback.java @@ -0,0 +1,87 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; +import java.util.Locale; + +import org.springframework.util.Assert; +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.soap.SoapBody; +import org.springframework.ws.soap.SoapMessage; + +import static org.junit.Assert.fail; + +/** + * @author Arjen Poutsma + * @since 2.0 + */ +abstract class SoapFaultResponseCallback implements ResponseCallback { + + public final void doWithResponse(WebServiceMessage message) throws IOException { + Assert.isInstanceOf(SoapMessage.class, message); + SoapMessage soapMessage = (SoapMessage) message; + SoapBody soapBody = soapMessage.getSoapBody(); + if (soapBody == null) { + fail("SOAP message [" + soapMessage + "] does not contain SOAP body"); + } + addSoapFault(soapBody); + } + + public abstract void addSoapFault(SoapBody soapBody); + + public static SoapFaultResponseCallback createMustUnderstandFault(final String faultStringOrReason, final Locale locale) { + return new SoapFaultResponseCallback() { + @Override + public void addSoapFault(SoapBody soapBody) { + soapBody.addMustUnderstandFault(faultStringOrReason, locale); + } + }; + + } + + public static SoapFaultResponseCallback createClientOrSenderFault(final String faultStringOrReason, final Locale locale) { + return new SoapFaultResponseCallback() { + @Override + public void addSoapFault(SoapBody soapBody) { + soapBody.addClientOrSenderFault(faultStringOrReason, locale); + } + }; + } + + public static SoapFaultResponseCallback createServerOrReceiverFault(final String faultStringOrReason, final Locale locale) { + return new SoapFaultResponseCallback() { + @Override + public void addSoapFault(SoapBody soapBody) { + soapBody.addServerOrReceiverFault(faultStringOrReason, locale); + } + }; + + } + + public static SoapFaultResponseCallback createVersionMismatchFault(final String faultStringOrReason, final Locale locale) { + return new SoapFaultResponseCallback() { + @Override + public void addSoapFault(SoapBody soapBody) { + soapBody.addVersionMismatchFault(faultStringOrReason, locale); + } + }; + + } + + +} diff --git a/test/src/main/java/org/springframework/ws/mock/client/SoapHeaderMatcher.java b/test/src/main/java/org/springframework/ws/mock/client/SoapHeaderMatcher.java new file mode 100644 index 00000000..2f11cb62 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/mock/client/SoapHeaderMatcher.java @@ -0,0 +1,66 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; +import java.util.Iterator; +import javax.xml.namespace.QName; + +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.soap.SoapHeader; +import org.springframework.ws.soap.SoapHeaderElement; +import org.springframework.ws.soap.SoapMessage; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Matches SOAP headers. + * + * @author Arjen Poutsma + * @since 2.0 + */ +class SoapHeaderMatcher implements RequestMatcher { + + private final QName soapHeaderName; + + SoapHeaderMatcher(QName soapHeaderName) { + this.soapHeaderName = soapHeaderName; + } + + public void match(WebServiceMessage request) throws IOException, AssertionError { + if (!(request instanceof SoapMessage)) { + fail("Request message is not a SOAP message"); + return; + } + SoapMessage soapMessage = (SoapMessage) request; + SoapHeader soapHeader = soapMessage.getSoapHeader(); + if (soapHeader == null) { + fail("SOAP message [" + soapMessage + "] does not contain SOAP header"); + } + Iterator soapHeaderElementIterator = soapHeader.examineAllHeaderElements(); + boolean found = false; + while (soapHeaderElementIterator.hasNext()) { + SoapHeaderElement soapHeaderElement = soapHeaderElementIterator.next(); + if (soapHeaderName.equals(soapHeaderElement.getName())) { + found = true; + break; + } + } + assertTrue("SOAP header [" + soapHeaderName + "] not found", found); + } +} diff --git a/test/src/test/java/org/springframework/ws/mock/client/ExceptionResponseCallbackTest.java b/test/src/test/java/org/springframework/ws/mock/client/ExceptionResponseCallbackTest.java new file mode 100644 index 00000000..09278180 --- /dev/null +++ b/test/src/test/java/org/springframework/ws/mock/client/ExceptionResponseCallbackTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; + +import org.junit.Test; + +public class ExceptionResponseCallbackTest { + + @Test(expected = IOException.class) + public void ioException() throws Exception { + ExceptionResponseCallback callback = new ExceptionResponseCallback(new IOException()); + + callback.doWithResponse(null); + } + + @Test(expected = RuntimeException.class) + public void runtimeException() throws Exception { + ExceptionResponseCallback callback = new ExceptionResponseCallback(new RuntimeException()); + + callback.doWithResponse(null); + } +} diff --git a/test/src/test/java/org/springframework/ws/mock/client/MockSenderConnectionTest.java b/test/src/test/java/org/springframework/ws/mock/client/MockSenderConnectionTest.java new file mode 100644 index 00000000..66b36920 --- /dev/null +++ b/test/src/test/java/org/springframework/ws/mock/client/MockSenderConnectionTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.net.URI; + +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.WebServiceMessageFactory; + +import org.junit.Before; +import org.junit.Test; + +import static org.easymock.EasyMock.*; +import static org.junit.Assert.*; + +/** @author Arjen Poutsma */ +public class MockSenderConnectionTest { + + private MockSenderConnection connection; + + @Before + public void setUp() throws Exception { + connection = new MockSenderConnection(); + } + + @Test + public void uri() throws Exception { + assertTrue("connection does not have any URI", connection.hasAnyUri()); + URI uri = new URI("http://example.com"); + connection = new MockSenderConnection(uri); + assertEquals("Invalid uri", uri, connection.getUri()); + } + + @Test + public void sendMatch() throws Exception { + RequestMatcher requestMatcher1 = createMock("requestMatcher1", RequestMatcher.class); + RequestMatcher requestMatcher2 = createMock("requestMatcher2", RequestMatcher.class); + connection.addRequestMatcher(requestMatcher1); + connection.addRequestMatcher(requestMatcher2); + WebServiceMessage request = createMock("request", WebServiceMessage.class); + + requestMatcher1.match(request); + requestMatcher2.match(request); + + replay(requestMatcher1, requestMatcher2, request); + + connection.send(request); + + + verify(requestMatcher1, requestMatcher2, request); + } + + @Test(expected = AssertionError.class) + public void sendNonMatch() throws Exception { + RequestMatcher requestMatcher1 = createMock("requestMatcher1", RequestMatcher.class); + RequestMatcher requestMatcher2 = createMock("requestMatcher2", RequestMatcher.class); + connection.addRequestMatcher(requestMatcher1); + connection.addRequestMatcher(requestMatcher2); + WebServiceMessage request = createMock("request", WebServiceMessage.class); + + requestMatcher1.match(request); + expectLastCall().andThrow(new AssertionError()); + + replay(requestMatcher1, requestMatcher2, request); + + connection.send(request); + } + + + @Test + public void receive() throws Exception { + ResponseCallback responseCallback = createMock(ResponseCallback.class); + WebServiceMessageFactory messageFactory = createMock(WebServiceMessageFactory.class); + WebServiceMessage response = createMock("response", WebServiceMessage.class); + connection.setResponseCallback(responseCallback); + + expect(messageFactory.createWebServiceMessage()).andReturn(response); + responseCallback.doWithResponse(response); + + replay(responseCallback, messageFactory, response); + + WebServiceMessage result = connection.receive(messageFactory); + assertSame(response, result); + + verify(responseCallback, messageFactory, response); + } +} diff --git a/test/src/test/java/org/springframework/ws/mock/client/MockWebServiceMessageSenderTest.java b/test/src/test/java/org/springframework/ws/mock/client/MockWebServiceMessageSenderTest.java new file mode 100644 index 00000000..cb96e2a5 --- /dev/null +++ b/test/src/test/java/org/springframework/ws/mock/client/MockWebServiceMessageSenderTest.java @@ -0,0 +1,136 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import java.io.IOException; + +import org.springframework.ws.client.WebServiceIOException; +import org.springframework.ws.client.WebServiceTransportException; +import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.soap.client.SoapFaultClientException; +import org.springframework.xml.transform.StringResult; +import org.springframework.xml.transform.StringSource; + +import org.junit.Before; +import org.junit.Test; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; + +public class MockWebServiceMessageSenderTest { + + private MockWebServiceMessageSender messageSender; + + private WebServiceTemplate template; + + @Before + public void setUp() throws Exception { + messageSender = new MockWebServiceMessageSender(); + template = new WebServiceTemplate(); + template.setMessageSender(messageSender); + template.setDefaultUri("http://example.com/airline"); + } + + @Test + public void normal() throws Exception { + String request = ""; + String response = ""; + + messageSender.whenConnecting().expectPayload(request).andRespondWithPayload(response); + messageSender.replay(); + + StringResult result = new StringResult(); + template.sendSourceAndReceiveToResult(new StringSource(request), result); + assertXMLEqual(result.toString(), response); + messageSender.verify(); + } + + @Test(expected = AssertionError.class) + public void invalidRequest() throws Exception { + String expectedRequest = ""; + + messageSender.whenConnecting().expectPayload(expectedRequest); + messageSender.replay(); + + String realRequest = ""; + template.sendSourceAndReceiveToResult(new StringSource(realRequest), new StringResult()); + messageSender.verify(); + } + + @Test(expected = AssertionError.class) + public void wrongUri() throws Exception { + String expectedUri = "http://example.com/1"; + + messageSender.whenConnectingTo(expectedUri); + messageSender.replay(); + + String realUri = "http://example.com/2"; + template.sendSourceAndReceiveToResult(realUri, null, null); + messageSender.verify(); + } + + @Test(expected = AssertionError.class) + public void notAllUris() throws Exception { + String expectedUri1 = "http://example.com/1"; + String expectedUri2 = "http://example.com/2"; + String request = ""; + String response = ""; + + + messageSender.whenConnectingTo(expectedUri1).expectPayload(request).andRespondWithPayload(response); + messageSender.whenConnectingTo(expectedUri2).expectPayload(request).andRespondWithPayload(response); + messageSender.replay(); + + template.sendSourceAndReceiveToResult(expectedUri1, new StringSource(request), new StringResult()); + messageSender.verify(); + } + + @Test(expected = WebServiceTransportException.class) + public void error() throws Exception { + String request = ""; + + messageSender.whenConnecting().expectPayload(request).andRespondWithError("Something went wrong"); + messageSender.replay(); + + template.sendSourceAndReceiveToResult(new StringSource(request), new StringResult()); + messageSender.verify(); + } + + @Test(expected = WebServiceIOException.class) + public void ioException() throws Exception { + String request = ""; + + IOException ex = new IOException("Something went wrong"); + messageSender.whenConnecting().expectPayload(request).andThrowException(ex); + messageSender.replay(); + + template.sendSourceAndReceiveToResult(new StringSource(request), new StringResult()); + messageSender.verify(); + } + + @Test(expected = SoapFaultClientException.class) + public void soapFault() throws Exception { + String request = ""; + + String faultString = "Foo"; + messageSender.whenConnecting().expectPayload(request).andRespondWithMustUnderstandFault(faultString, null); + messageSender.replay(); + + template.sendSourceAndReceiveToResult(new StringSource(request), new StringResult()); + messageSender.verify(); + } + +} diff --git a/test/src/test/java/org/springframework/ws/mock/client/PayloadMatcherTest.java b/test/src/test/java/org/springframework/ws/mock/client/PayloadMatcherTest.java new file mode 100644 index 00000000..7b6c82ee --- /dev/null +++ b/test/src/test/java/org/springframework/ws/mock/client/PayloadMatcherTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.ws.WebServiceMessage; +import org.springframework.xml.transform.StringSource; + +import org.junit.Test; + +import static org.easymock.EasyMock.*; + +public class PayloadMatcherTest { + + @Test + public void stringPayloadMatch() throws Exception { + String xml = ""; + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource(xml)); + replay(message); + + PayloadMatcher matcher = PayloadMatcher.createStringPayloadMatcher(xml); + matcher.match(message); + + verify(message); + } + + @Test(expected = AssertionError.class) + public void nonMatch() throws Exception { + String actual = ""; + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource(actual)); + replay(message); + + String expected = ""; + PayloadMatcher matcher = PayloadMatcher.createStringPayloadMatcher(expected); + matcher.match(message); + } + + @Test + public void resourcePayload() throws Exception { + String xml = ""; + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource(xml)); + replay(message); + + Resource resource = new ByteArrayResource(xml.getBytes()); + PayloadMatcher matcher = PayloadMatcher.createResourcePayloadMatcher(resource); + matcher.match(message); + + verify(message); + } + + + @Test + public void sourcePayloadMatcher() throws Exception { + String xml = ""; + WebServiceMessage message = createMock(WebServiceMessage.class); + expect(message.getPayloadSource()).andReturn(new StringSource(xml)); + replay(message); + + Resource resource = new ByteArrayResource(xml.getBytes()); + PayloadMatcher matcher = PayloadMatcher.createSourcePayloadMatcher(new StringSource(xml)); + matcher.match(message); + + verify(message); + } +} diff --git a/test/src/test/java/org/springframework/ws/mock/client/SoapHeaderMatcherTest.java b/test/src/test/java/org/springframework/ws/mock/client/SoapHeaderMatcherTest.java new file mode 100644 index 00000000..3f8cfd26 --- /dev/null +++ b/test/src/test/java/org/springframework/ws/mock/client/SoapHeaderMatcherTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2005-2010 the original author or authors. + * + * 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 org.springframework.ws.mock.client; + +import javax.xml.namespace.QName; +import javax.xml.soap.MessageFactory; +import javax.xml.soap.SOAPMessage; + +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.soap.SoapMessage; +import org.springframework.ws.soap.saaj.SaajSoapMessage; + +import org.junit.Before; +import org.junit.Test; + +import static org.easymock.EasyMock.createMock; + +public class SoapHeaderMatcherTest { + + private SoapHeaderMatcher matcher; + + private QName expectedHeaderName; + + @Before + public void setUp() throws Exception { + expectedHeaderName = new QName("http://example.com", "header"); + matcher = new SoapHeaderMatcher(expectedHeaderName); + } + + @Test + public void match() throws Exception { + MessageFactory messageFactory = MessageFactory.newInstance(); + SOAPMessage saajMessage = messageFactory.createMessage(); + saajMessage.getSOAPHeader().addHeaderElement(expectedHeaderName); + SoapMessage soapMessage = new SaajSoapMessage(saajMessage); + + matcher.match(soapMessage); + } + + @Test(expected = AssertionError.class) + public void nonMatch() throws Exception { + MessageFactory messageFactory = MessageFactory.newInstance(); + SOAPMessage saajMessage = messageFactory.createMessage(); + SoapMessage soapMessage = new SaajSoapMessage(saajMessage); + + matcher.match(soapMessage); + } + + @Test(expected = AssertionError.class) + public void nonSoap() throws Exception { + WebServiceMessage message = createMock(WebServiceMessage.class); + + matcher.match(message); + } + +} diff --git a/test/src/test/resources/log4j.properties b/test/src/test/resources/log4j.properties new file mode 100644 index 00000000..92e896c8 --- /dev/null +++ b/test/src/test/resources/log4j.properties @@ -0,0 +1,6 @@ +log4j.rootCategory=INFO, stdout +log4j.logger.org.springframework.ws=DEBUG + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n \ No newline at end of file diff --git a/test/template.mf b/test/template.mf index 98e57bbc..1d992fa0 100644 --- a/test/template.mf +++ b/test/template.mf @@ -4,9 +4,18 @@ Bundle-Vendor: SpringSource Bundle-Version: ${osgi.version} Bundle-ManifestVersion: 2 Import-Template: + javax.xml.namespace.*;version="0", + javax.xml.parsers.*;version="0", + javax.xml.transform.*;version="0", + org.custommonkey.xmlunit.*;version="[1.3.0, 2.0.0)", + org.junit.*;version="[4.7.0, 5.0.0)", + org.springframework.core.*;version=${spring.framework.osgi.range}, + org.springframework.util.*;version=${spring.framework.osgi.range}, org.springframework.ws.*;version=${osgi.range}, - org.springframework.xml.*;version=${osgi.range} -Ignored-Existing-Headers: + org.springframework.xml.*;version=${osgi.range}, + org.w3c.dom.*;version="0", + org.xml.sax.*;version="0" +Ignored-Existing-Headers: Bnd-LastModified, Import-Package, Export-Package,