diff --git a/test/src/main/java/org/springframework/ws/test/client/AbstractResponseCreator.java b/test/src/main/java/org/springframework/ws/test/client/AbstractResponseCreator.java index d867cf37..d5f72455 100644 --- a/test/src/main/java/org/springframework/ws/test/client/AbstractResponseCreator.java +++ b/test/src/main/java/org/springframework/ws/test/client/AbstractResponseCreator.java @@ -21,7 +21,6 @@ import java.net.URI; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.WebServiceMessageFactory; -import org.springframework.xml.transform.TransformerObjectSupport; /** * Abstract base class for the {@link ResponseCreator} interface. @@ -32,11 +31,12 @@ import org.springframework.xml.transform.TransformerObjectSupport; * @author Arjen Poutsma * @since 2.0 */ -abstract class AbstractResponseCreator extends TransformerObjectSupport - implements ResponseCreator { +abstract class AbstractResponseCreator implements ResponseCreator { - public final T createResponse(URI uri, T request, WebServiceMessageFactory messageFactory) throws IOException { - T response = messageFactory.createWebServiceMessage(); + public final WebServiceMessage createResponse(URI uri, + WebServiceMessage request, + WebServiceMessageFactory messageFactory) throws IOException { + WebServiceMessage response = messageFactory.createWebServiceMessage(); doWithResponse(uri, request, response); return response; } @@ -49,6 +49,7 @@ abstract class AbstractResponseCreator extends Tran * @param response the response message * @throws IOException in case of I/O errors */ - protected abstract void doWithResponse(URI uri, T request, T response) throws IOException; + protected abstract void doWithResponse(URI uri, WebServiceMessage request, WebServiceMessage response) + throws IOException; } diff --git a/test/src/main/java/org/springframework/ws/test/client/ErrorResponseCreator.java b/test/src/main/java/org/springframework/ws/test/client/ErrorResponseCreator.java index f69ba4ee..ccc56343 100644 --- a/test/src/main/java/org/springframework/ws/test/client/ErrorResponseCreator.java +++ b/test/src/main/java/org/springframework/ws/test/client/ErrorResponseCreator.java @@ -29,7 +29,7 @@ import org.springframework.ws.WebServiceMessageFactory; * @author Lukas Krecan * @since 2.0 */ -class ErrorResponseCreator implements ResponseCreator { +class ErrorResponseCreator implements ResponseCreator { private final String errorMessage; @@ -39,7 +39,7 @@ class ErrorResponseCreator implements ResponseCreator { public WebServiceMessage createResponse(URI uri, WebServiceMessage request, - WebServiceMessageFactory factory) throws IOException { + WebServiceMessageFactory factory) throws IOException { // Do nothing return null; } diff --git a/test/src/main/java/org/springframework/ws/test/client/ExceptionResponseCreator.java b/test/src/main/java/org/springframework/ws/test/client/ExceptionResponseCreator.java index 2925b00b..e7a0a8f3 100644 --- a/test/src/main/java/org/springframework/ws/test/client/ExceptionResponseCreator.java +++ b/test/src/main/java/org/springframework/ws/test/client/ExceptionResponseCreator.java @@ -29,7 +29,7 @@ import org.springframework.ws.WebServiceMessageFactory; * @author Arjen Poutsma * @since 2.0 */ -class ExceptionResponseCreator implements ResponseCreator { +class ExceptionResponseCreator implements ResponseCreator { private final Exception exception; @@ -43,7 +43,7 @@ class ExceptionResponseCreator implements ResponseCreator { public WebServiceMessage createResponse(URI uri, WebServiceMessage request, - WebServiceMessageFactory factory) throws IOException { + WebServiceMessageFactory factory) throws IOException { if (exception instanceof IOException) { throw (IOException) exception; } diff --git a/test/src/main/java/org/springframework/ws/test/client/MockWebServiceServer.java b/test/src/main/java/org/springframework/ws/test/client/MockWebServiceServer.java new file mode 100644 index 00000000..a7eb1ac6 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/test/client/MockWebServiceServer.java @@ -0,0 +1,68 @@ +/* + * 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.test.client; + +import org.springframework.util.Assert; +import org.springframework.ws.client.core.WebServiceTemplate; + +/** + * @author Arjen Poutsma + */ +public class MockWebServiceServer { + + private final MockWebServiceMessageSender mockMessageSender; + + private MockWebServiceServer(MockWebServiceMessageSender mockMessageSender) { + Assert.notNull(mockMessageSender, "'mockMessageSender' must not be null"); + this.mockMessageSender = mockMessageSender; + } + + public static MockWebServiceServer createServer(WebServiceTemplate webServiceTemplate) { + Assert.notNull(webServiceTemplate, "'webServiceTemplate' must not be null"); + + MockWebServiceMessageSender mockMessageSender = new MockWebServiceMessageSender(); + webServiceTemplate.setMessageSender(mockMessageSender); + + return new MockWebServiceServer(mockMessageSender); + } + + /** + * Records an expectation specified by the given {@link RequestMatcher}. Returns a {@link ResponseActions} object + * that allows for setting up the response, or more expectations. + * + * @param requestMatcher the request matcher expected + * @return the response actions + */ + public ResponseActions expect(RequestMatcher requestMatcher) { + MockSenderConnection connection = mockMessageSender.expectNewConnection(); + connection.addRequestMatcher(requestMatcher); + return connection; + } + + /** + * Verifies that all connections were used. + * + * @throws AssertionError in case of unused connections. + */ + public void verify() { + mockMessageSender.verifyConnections(); + } + + + + +} diff --git a/test/src/main/java/org/springframework/ws/test/client/PayloadResponseCreator.java b/test/src/main/java/org/springframework/ws/test/client/PayloadResponseCreator.java index 32edaeb2..944ef1d3 100644 --- a/test/src/main/java/org/springframework/ws/test/client/PayloadResponseCreator.java +++ b/test/src/main/java/org/springframework/ws/test/client/PayloadResponseCreator.java @@ -22,6 +22,7 @@ import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import org.springframework.ws.WebServiceMessage; +import org.springframework.xml.transform.TransformerHelper; /** * Implementation of {@link ResponseCreator} that writes a {@link Source} response. @@ -29,10 +30,12 @@ import org.springframework.ws.WebServiceMessage; * @author Arjen Poutsma * @since 2.0 */ -class PayloadResponseCreator extends AbstractResponseCreator { +class PayloadResponseCreator extends AbstractResponseCreator { private final Source payload; + private TransformerHelper transformerHelper = new TransformerHelper(); + PayloadResponseCreator(Source payload) { this.payload = payload; } @@ -40,7 +43,7 @@ class PayloadResponseCreator extends AbstractResponseCreator @Override protected void doWithResponse(URI uri, WebServiceMessage request, WebServiceMessage response) throws IOException { try { - transform(payload, response.getPayloadResult()); + transformerHelper.transform(payload, response.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/test/client/RequestMatcher.java b/test/src/main/java/org/springframework/ws/test/client/RequestMatcher.java index 6ad40ca5..b70f2962 100644 --- a/test/src/main/java/org/springframework/ws/test/client/RequestMatcher.java +++ b/test/src/main/java/org/springframework/ws/test/client/RequestMatcher.java @@ -28,7 +28,7 @@ import org.springframework.ws.WebServiceMessage; * @author Lukas Krecan * @since 2.0 */ -public interface RequestMatcher { +public interface RequestMatcher { /** * Matches the given request message against the expectations. Implementations typically make use of JUnit-based @@ -39,6 +39,6 @@ public interface RequestMatcher { * @throws IOException in case of I/O errors * @throws AssertionError if expectations are not met */ - void match(URI uri, T request) throws IOException, AssertionError; + void match(URI uri, WebServiceMessage request) throws IOException, AssertionError; } \ No newline at end of file diff --git a/test/src/main/java/org/springframework/ws/test/client/RequestMatchers.java b/test/src/main/java/org/springframework/ws/test/client/RequestMatchers.java new file mode 100644 index 00000000..61242de4 --- /dev/null +++ b/test/src/main/java/org/springframework/ws/test/client/RequestMatchers.java @@ -0,0 +1,154 @@ +/* + * 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.test.client; + +import java.io.IOException; +import java.net.URI; +import java.util.Map; +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.test.support.PayloadDiffMatcher; +import org.springframework.xml.transform.ResourceSource; +import org.springframework.xml.validation.XmlValidator; +import org.springframework.xml.validation.XmlValidatorFactory; + +/** + * @author Arjen Poutsma + */ +public abstract class RequestMatchers { + + private RequestMatchers() { + } + + /** + * Expects any request. + * + * @return the request matcher + */ + public static RequestMatcher anything() { + return new RequestMatcher() { + public void match(URI uri, WebServiceMessage request) throws IOException, AssertionError { + } + }; + } + + /** + * Expects the given {@link javax.xml.transform.Source} XML payload. + * + * @param payload the XML payload + * @return the request matcher + */ + public static RequestMatcher payload(Source payload) { + Assert.notNull(payload, "'payload' must not be null"); + final PayloadDiffMatcher matcher = new PayloadDiffMatcher(payload); + return new RequestMatcher() { + public void match(URI uri, WebServiceMessage request) throws IOException, AssertionError { + matcher.match(request); + } + }; + } + + /** + * Expects the given {@link org.springframework.core.io.Resource} XML payload. + * + * @param payload the XML payload + * @return the request matcher + */ + public static RequestMatcher payload(Resource payload) throws IOException { + Assert.notNull(payload, "'payload' must not be null"); + return payload(new ResourceSource(payload)); + } + + /** + * Expects the payload to validate against the given XSD schema(s). + * + * @param schema the schema + * @param furtherSchemas further schemas, if necessary + * @return the request matcher + */ + public static RequestMatcher validPayload(Resource schema, Resource... furtherSchemas) { + try { + Resource[] joinedSchemas = new Resource[furtherSchemas.length + 1]; + joinedSchemas[0] = schema; + System.arraycopy(furtherSchemas, 0, joinedSchemas, 1, furtherSchemas.length); + XmlValidator validator = + XmlValidatorFactory.createValidator(joinedSchemas, XmlValidatorFactory.SCHEMA_W3C_XML); + return new SchemaValidatingRequestMatcher(validator); + } + catch (IOException ex) { + throw new IllegalArgumentException("Schema(s) could not be opened", ex); + } + } + + /** + * Expects the given XPath expression to (not) exist or be evaluated to a value. + * + * @param xpathExpression the XPath expression + * @return the XPath expectations, to be further configured + */ + public static XPathExpectations xpath(String xpathExpression) { + return new DefaultXPathExpectations(xpathExpression, null); + } + + /** + * Expects the given XPath expression to (not) exist or be evaluated to a value. + * + * @param xpathExpression the XPath expression + * @param namespaceMapping the namespaces + * @return the XPath expectations, to be further configured + */ + public static XPathExpectations xpath(String xpathExpression, Map namespaceMapping) { + return new DefaultXPathExpectations(xpathExpression, namespaceMapping); + } + + /** + * Expects the given SOAP header in the outgoing message. + * + * @param soapHeaderName the qualified name of the SOAP header to expect + * @return the request matcher + */ + public static RequestMatcher soapHeader(QName soapHeaderName) { + Assert.notNull(soapHeaderName, "'soapHeaderName' must not be null"); + return new SoapHeaderMatcher(soapHeaderName); + } + + /** + * Expects a connection to the given URI. + * + * @param uri the String uri expected to connect to + * @return the request matcher + */ + public static RequestMatcher connectionTo(String uri) { + Assert.notNull(uri, "'uri' must not be null"); + return connectionTo(URI.create(uri)); + } + + /** + * Expects a connection to the given URI. + * + * @param uri the String uri expected to connect to + * @return the request matcher + */ + public static RequestMatcher connectionTo(URI uri) { + Assert.notNull(uri, "'uri' must not be null"); + return new UriMatcher(uri); + } +} diff --git a/test/src/main/java/org/springframework/ws/test/client/ResponseCreator.java b/test/src/main/java/org/springframework/ws/test/client/ResponseCreator.java index 2d061bba..cfdb5ffe 100644 --- a/test/src/main/java/org/springframework/ws/test/client/ResponseCreator.java +++ b/test/src/main/java/org/springframework/ws/test/client/ResponseCreator.java @@ -29,7 +29,7 @@ import org.springframework.ws.WebServiceMessageFactory; * @author Lukas Krecan * @since 2.0 */ -public interface ResponseCreator { +public interface ResponseCreator { /** * Create a response for the given the request and URI. @@ -39,6 +39,6 @@ public interface ResponseCreator { * @param messageFactory the message that can be used to create responses * @throws IOException in case of I/O errors */ - T createResponse(URI uri, T request, WebServiceMessageFactory messageFactory) throws IOException; + WebServiceMessage createResponse(URI uri, WebServiceMessage request, WebServiceMessageFactory messageFactory) throws IOException; } diff --git a/test/src/main/java/org/springframework/ws/test/client/ResponseCreators.java b/test/src/main/java/org/springframework/ws/test/client/ResponseCreators.java new file mode 100644 index 00000000..9cf2f12f --- /dev/null +++ b/test/src/main/java/org/springframework/ws/test/client/ResponseCreators.java @@ -0,0 +1,140 @@ +/* + * 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.test.client; + +import java.io.IOException; +import java.util.Locale; +import javax.xml.transform.Source; + +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.xml.transform.ResourceSource; + +/** + * @author Arjen Poutsma + */ +public abstract class ResponseCreators { + + private ResponseCreators() { + } + + /** + * Respond with the given {@link javax.xml.transform.Source} XML as payload response. + * + * @param payload the response payload + * @return the response callback + */ + public static ResponseCreator withPayload(Source payload) { + Assert.notNull(payload, "'payload' must not be null"); + return new PayloadResponseCreator(payload); + } + + /** + * Respond with the given {@link org.springframework.core.io.Resource} XML as payload response. + * + * @param payload the response payload + * @return the response callback + */ + public static ResponseCreator withPayload(Resource payload) throws IOException { + Assert.notNull(payload, "'payload' must not be null"); + return withPayload(new ResourceSource(payload)); + } + + /** + * Respond with an error. + * + * @param errorMessage the error message + * @return the response callback + * @see org.springframework.ws.transport.WebServiceConnection#hasError() + * @see org.springframework.ws.transport.WebServiceConnection#getErrorMessage() + */ + public static ResponseCreator withError(String errorMessage) { + Assert.hasLength(errorMessage, "'errorMessage' must not be empty"); + return new ErrorResponseCreator(errorMessage); + } + + /** + * Respond with an {@link java.io.IOException}. + * + * @param ioException the exception to be thrown + * @return the response callback + */ + public static ResponseCreator withException(IOException ioException) { + Assert.notNull(ioException, "'ioException' must not be null"); + return new ExceptionResponseCreator(ioException); + } + + /** + * Respond with an {@link RuntimeException}. + * + * @param ex the runtime exception to be thrown + * @return the response callback + */ + public static ResponseCreator withException(RuntimeException ex) { + Assert.notNull(ex, "'ex' must not be null"); + return new ExceptionResponseCreator(ex); + } + + /** + * 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) + */ + public static ResponseCreator withMustUnderstandFault(String faultStringOrReason, Locale locale) { + Assert.hasLength(faultStringOrReason, "'faultStringOrReason' must not be empty"); + return SoapFaultResponseCreator.createMustUnderstandFault(faultStringOrReason, locale); + } + + /** + * 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, Locale) + */ + public static ResponseCreator withClientOrSenderFault(String faultStringOrReason, Locale locale) { + Assert.hasLength(faultStringOrReason, "'faultStringOrReason' must not be empty"); + return SoapFaultResponseCreator.createClientOrSenderFault(faultStringOrReason, locale); + } + + /** + * 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, Locale) + */ + public static ResponseCreator withServerOrReceiverFault(String faultStringOrReason, Locale locale) { + Assert.hasLength(faultStringOrReason, "'faultStringOrReason' must not be empty"); + return SoapFaultResponseCreator.createServerOrReceiverFault(faultStringOrReason, locale); + } + + /** + * 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, Locale) + */ + public static ResponseCreator withVersionMismatchFault(String faultStringOrReason, Locale locale) { + Assert.hasLength(faultStringOrReason, "'faultStringOrReason' must not be empty"); + return SoapFaultResponseCreator.createVersionMismatchFault(faultStringOrReason, locale); + } + +} diff --git a/test/src/main/java/org/springframework/ws/test/client/SoapFaultResponseCreator.java b/test/src/main/java/org/springframework/ws/test/client/SoapFaultResponseCreator.java index d8f192f8..31fe2219 100644 --- a/test/src/main/java/org/springframework/ws/test/client/SoapFaultResponseCreator.java +++ b/test/src/main/java/org/springframework/ws/test/client/SoapFaultResponseCreator.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.net.URI; import java.util.Locale; +import org.springframework.ws.WebServiceMessage; import org.springframework.ws.soap.SoapBody; import org.springframework.ws.soap.SoapMessage; @@ -31,11 +32,16 @@ import static org.springframework.ws.test.support.AssertionErrors.fail; * @author Arjen Poutsma * @since 2.0 */ -abstract class SoapFaultResponseCreator extends AbstractResponseCreator { +abstract class SoapFaultResponseCreator extends AbstractResponseCreator { @Override - protected void doWithResponse(URI uri, SoapMessage request, SoapMessage response) throws IOException { - SoapBody responseBody = response.getSoapBody(); + protected void doWithResponse(URI uri, WebServiceMessage request, WebServiceMessage response) throws IOException { + if (!(response instanceof SoapMessage)) { + fail("Response is not a SOAP message"); + return; + } + SoapMessage soapResponse = (SoapMessage) response; + SoapBody responseBody = soapResponse.getSoapBody(); if (responseBody == null) { fail("SOAP message [" + response + "] does not contain SOAP body"); } diff --git a/test/src/test/java/org/springframework/ws/test/client/integration/ClientIntegrationTest.java b/test/src/test/java/org/springframework/ws/test/client/integration/ClientIntegrationTest.java index a1e209f4..d23abdcd 100644 --- a/test/src/test/java/org/springframework/ws/test/client/integration/ClientIntegrationTest.java +++ b/test/src/test/java/org/springframework/ws/test/client/integration/ClientIntegrationTest.java @@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.ws.client.core.WebServiceTemplate; +import org.springframework.ws.test.client.MockWebServiceServer; import org.springframework.ws.test.integration.CustomerCountRequest; import org.springframework.ws.test.integration.CustomerCountResponse; import org.springframework.xml.transform.StringSource; @@ -31,7 +32,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; -import static org.springframework.ws.test.client.WebServiceMock.*; +import static org.springframework.ws.test.client.RequestMatchers.payload; +import static org.springframework.ws.test.client.ResponseCreators.withPayload; /** * Integration test for client-side WebService testing. In different package so we can't use the package-protected @@ -46,9 +48,11 @@ public class ClientIntegrationTest { @Autowired private WebServiceTemplate webServiceTemplate; + private MockWebServiceServer mockServer; + @Before - public void setUpMocks() throws Exception { - mockWebServiceTemplate(webServiceTemplate); + public void createServer() throws Exception { + mockServer = MockWebServiceServer.createServer(webServiceTemplate); } @Test @@ -60,7 +64,7 @@ public class ClientIntegrationTest { "" + "10" + ""); - expect(payload(expectedRequestPayload)).andRespond(withPayload(responsePayload)); + mockServer.expect(payload(expectedRequestPayload)).andRespond(withPayload(responsePayload)); CustomerCountRequest request = new CustomerCountRequest(); request.setCustomerName("John Doe"); @@ -68,7 +72,7 @@ public class ClientIntegrationTest { CustomerCountResponse response = (CustomerCountResponse) webServiceTemplate.marshalSendAndReceive(request); assertEquals(10, response.getCustomerCount()); - verifyConnections(); + mockServer.verify(); } }