From e52e860c457bd8ad5e0aa205130b9bd2cccb23bf Mon Sep 17 00:00:00 2001 From: sajithaliyanage Date: Wed, 11 Sep 2019 20:34:01 +0530 Subject: [PATCH] Add synapse unit testing framework --- modules/core/pom.xml | 4 + .../synapse/ServerContextInformation.java | 10 + .../core/axis2/Axis2SynapseEnvironment.java | 43 +- .../org/apache/synapse/unittest/Assertor.java | 437 ++++++++++++++++++ .../apache/synapse/unittest/CommonUtils.java | 68 +++ .../unittest/ConfigurationDeployer.java | 202 ++++++++ .../apache/synapse/unittest/Constants.java | 105 +++++ .../synapse/unittest/RequestHandler.java | 298 ++++++++++++ .../synapse/unittest/RequestProcessor.java | 138 ++++++ .../unittest/SynapseTestcaseDataReader.java | 376 +++++++++++++++ .../apache/synapse/unittest/TCPServer.java | 93 ++++ .../synapse/unittest/TestCasesMediator.java | 412 +++++++++++++++++ .../apache/synapse/unittest/TestingAgent.java | 425 +++++++++++++++++ .../synapse/unittest/UnitTestingExecutor.java | 72 +++ .../apache/synapse/unittest/docs/README.md | 247 ++++++++++ .../unittest/docs/SynapseUnitTestDoc.md | 375 +++++++++++++++ .../testcase/data/classes/Artifact.java | 105 +++++ .../testcase/data/classes/AssertEqual.java | 84 ++++ .../testcase/data/classes/AssertNotNull.java | 66 +++ .../data/classes/SynapseTestCase.java | 70 +++ .../testcase/data/classes/TestCase.java | 160 +++++++ .../data/classes/TestCaseSummary.java | 119 +++++ .../data/classes/TestSuiteSummary.java | 188 ++++++++ .../testcase/data/holders/ArtifactData.java | 107 +++++ .../testcase/data/holders/TestCaseData.java | 69 +++ modules/distribution/src/main/bin/synapse.sh | 20 +- pom.xml | 12 + 27 files changed, 4303 insertions(+), 2 deletions(-) create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/Assertor.java create mode 100644 modules/core/src/main/java/org/apache/synapse/unittest/CommonUtils.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/ConfigurationDeployer.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/Constants.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/RequestHandler.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/RequestProcessor.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/SynapseTestcaseDataReader.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/TCPServer.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/TestCasesMediator.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/TestingAgent.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/UnitTestingExecutor.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/docs/README.md create mode 100644 modules/core/src/main/java/org/apache/synapse/unittest/docs/SynapseUnitTestDoc.md create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/Artifact.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/AssertEqual.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/AssertNotNull.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/SynapseTestCase.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestCase.java create mode 100644 modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestCaseSummary.java create mode 100644 modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestSuiteSummary.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/holders/ArtifactData.java create mode 100755 modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/holders/TestCaseData.java diff --git a/modules/core/pom.xml b/modules/core/pom.xml index 2eab891f2..85339d980 100644 --- a/modules/core/pom.xml +++ b/modules/core/pom.xml @@ -318,5 +318,9 @@ xercesImpl test + + com.google.code.gson + gson + diff --git a/modules/core/src/main/java/org/apache/synapse/ServerContextInformation.java b/modules/core/src/main/java/org/apache/synapse/ServerContextInformation.java index 02b154eaf..5f911e302 100644 --- a/modules/core/src/main/java/org/apache/synapse/ServerContextInformation.java +++ b/modules/core/src/main/java/org/apache/synapse/ServerContextInformation.java @@ -42,6 +42,8 @@ public class ServerContextInformation { private ServerState serverState = ServerState.UNDETERMINED; /** Reference to the server configuration */ private ServerConfigurationInformation serverConfigurationInformation; + /** whether unit test mode is enabled or not */ + private boolean isUnitTestModeEnabled=false; public ServerContextInformation(ServerConfigurationInformation serverConfigurationInformation) { this.serverConfigurationInformation = serverConfigurationInformation; @@ -96,4 +98,12 @@ public void setSynapseEnvironment(SynapseEnvironment synapseEnvironment) { public ServerConfigurationInformation getServerConfigurationInformation() { return serverConfigurationInformation; } + + public boolean isServerUnitTestModeEnabled(){ + return isUnitTestModeEnabled; + } + + public void setServerUnitTestModeEnabled(boolean isUnitTestModeEnabled){ + this.isUnitTestModeEnabled=isUnitTestModeEnabled; + } } diff --git a/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2SynapseEnvironment.java b/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2SynapseEnvironment.java index a63a8bccd..e2467a40c 100644 --- a/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2SynapseEnvironment.java +++ b/modules/core/src/main/java/org/apache/synapse/core/axis2/Axis2SynapseEnvironment.java @@ -44,6 +44,7 @@ import org.apache.synapse.rest.RESTRequestHandler; import org.apache.synapse.task.SynapseTaskManager; import org.apache.synapse.transport.passthru.util.RelayUtils; +import org.apache.synapse.unittest.UnitTestingExecutor; import org.apache.synapse.util.concurrent.SynapseThreadPool; import org.apache.synapse.util.xpath.ext.SynapseXpathFunctionContextProvider; import org.apache.synapse.util.xpath.ext.SynapseXpathVariableResolver; @@ -83,6 +84,9 @@ public class Axis2SynapseEnvironment implements SynapseEnvironment { private boolean synapseDebugMode; + /** Unit test mode is enabled/disabled*/ + private boolean isUnitTestEnabled = false; + public Axis2SynapseEnvironment(SynapseConfiguration synCfg) { int coreThreads = SynapseThreadPool.SYNAPSE_CORE_THREADS; @@ -126,7 +130,25 @@ public Axis2SynapseEnvironment(ConfigurationContext cfgCtx, public Axis2SynapseEnvironment(ConfigurationContext cfgCtx, SynapseConfiguration synapseConfig, ServerContextInformation contextInformation) { this(cfgCtx, synapseConfig); - this.contextInformation = contextInformation; + this.contextInformation = contextInformation; + setSeverUnitTestMode(contextInformation); + } + + /** + * This method is to set the unit test mode is enabled. + * unit test message context and environment initializes + */ + private void setSeverUnitTestMode(ServerContextInformation contextInformation) { + if (Boolean.parseBoolean(System.getProperty("synapseTest"))) { + setUnitTestEnabled(true); + contextInformation.setServerUnitTestModeEnabled(true); + log.info("Synapse unit testing server enabled"); + + //starting UnitTestingExecutor + UnitTestingExecutor testExecutor = UnitTestingExecutor.getExecuteInstance(); + testExecutor.setSynapseConfiguration(this.synapseConfig); + testExecutor.start(); + } } public boolean injectMessage(final MessageContext synCtx) { @@ -551,7 +573,26 @@ private Mediator getProxyOutSequence(MessageContext synCtx, ProxyService proxySe return null; } + public void setSynapseDebugMode(boolean synapseDebugMode) { this.synapseDebugMode = synapseDebugMode; } + + /** + * Whether unit test is enabled in the environment. + * + * @return whether debugging is enabled in the environment + */ + public boolean isUnitTestEnabled() { + return isUnitTestEnabled; + } + + /** + * set unit test mode enabled in the environment. + * + * @param isUnitTestEnabled boolean value of unit test mode + */ + public void setUnitTestEnabled(boolean isUnitTestEnabled) { + this.isUnitTestEnabled = isUnitTestEnabled; + } } diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/Assertor.java b/modules/core/src/main/java/org/apache/synapse/unittest/Assertor.java new file mode 100755 index 000000000..2dc63bc0e --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/Assertor.java @@ -0,0 +1,437 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; +import org.apache.log4j.Logger; +import org.apache.synapse.MessageContext; +import org.apache.synapse.core.axis2.Axis2MessageContext; +import org.apache.synapse.unittest.testcase.data.classes.AssertEqual; +import org.apache.synapse.unittest.testcase.data.classes.AssertNotNull; +import org.apache.synapse.unittest.testcase.data.classes.TestCase; +import org.apache.synapse.unittest.testcase.data.classes.TestCaseSummary; + +import java.io.IOException; +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; + +import static org.apache.synapse.unittest.Constants.INPUT_PROPERTY_AXIS2; +import static org.apache.synapse.unittest.Constants.INPUT_PROPERTY_BODY; +import static org.apache.synapse.unittest.Constants.INPUT_PROPERTY_CONTEXT; +import static org.apache.synapse.unittest.Constants.INPUT_PROPERTY_TRANSPORT; + + +/** + * Class responsible for the validation of testing with expected results. + */ +class Assertor { + + private static Logger log = Logger.getLogger(Assertor.class.getName()); + + private Assertor() { + } + + /** + * Assertion of results of sequence mediation and expected payload and properties. + * + * @param currentTestCase current test case + * @param mediateMsgCtxt message context used for the mediation + * @return true if assertion is success otherwise false + */ + static Map.Entry doAssertionSequence(TestCase currentTestCase, MessageContext mediateMsgCtxt, + int testCaseNumber, TestCaseSummary testSummary) { + + boolean isSequenceAssertComplete = false; + boolean isAssertEqualComplete = false; + boolean isAssertNotNullComplete = false; + String assertMessage = null; + + List assertEquals = currentTestCase.getAssertEquals(); + List assertNotNulls = currentTestCase.getAssertNotNull(); + + if (!assertEquals.isEmpty()) { + Map.Entry assertSequence = startAssertEqualsForSequence(assertEquals, mediateMsgCtxt); + isAssertEqualComplete = assertSequence.getKey(); + assertMessage = assertSequence.getValue(); + testSummary.setTestException(assertMessage); + } + + if (!assertNotNulls.isEmpty() && assertMessage == null) { + Map.Entry assertSequence = startAssertNotNullsForSequence(assertNotNulls, mediateMsgCtxt); + isAssertNotNullComplete = assertSequence.getKey(); + assertMessage = assertSequence.getValue(); + testSummary.setTestException(assertMessage); + } + + if ((isAssertEqualComplete && isAssertNotNullComplete) || (isAssertEqualComplete && assertNotNulls.isEmpty()) || + (isAssertNotNullComplete && assertEquals.isEmpty())) { + isSequenceAssertComplete = true; + testSummary.setAssertionStatus(Constants.PASSED_KEY); + log.info("Unit testing passed for test case - " + testCaseNumber); + } else { + testSummary.setAssertionStatus(Constants.FAILED_KEY); + log.error("Unit testing failed for test case - " + testCaseNumber); + } + + return new AbstractMap.SimpleEntry(isSequenceAssertComplete, testSummary); + } + + /** + * Assertion of results of proxy/API invoke and expected payload. + * + * @param currentTestCase current testcase + * @param response response from the service + * @param testCaseNumber asserting test case number + * @return true if assertion is success otherwise false + */ + static Map.Entry doAssertionService(TestCase currentTestCase, HttpResponse response, + int testCaseNumber, TestCaseSummary testSummary) { + + boolean isServiceAssertComplete = false; + boolean isAssertEqualComplete = false; + boolean isAssertNotNullComplete = false; + String assertMessage = null; + + List assertEquals = currentTestCase.getAssertEquals(); + List assertNotNulls = currentTestCase.getAssertNotNull(); + + try { + String responseAsString = EntityUtils.toString(response.getEntity(), "UTF-8"); + Header[] responseHeaders = response.getAllHeaders(); + + if (!assertEquals.isEmpty()) { + Map.Entry assertService + = startAssertEqualsForServices(assertEquals, responseAsString, responseHeaders); + isAssertEqualComplete = assertService.getKey(); + assertMessage = assertService.getValue(); + testSummary.setTestException(assertMessage); + } + + if (!assertNotNulls.isEmpty() && assertMessage == null) { + Map.Entry assertService + = startAssertNotNullsForServices(assertNotNulls, responseAsString, responseHeaders); + isAssertNotNullComplete = assertService.getKey(); + assertMessage = assertService.getValue(); + testSummary.setTestException(assertMessage); + } + } catch (IOException e) { + log.error("Error while reading response from the service HttpResponse", e); + } + + if ((isAssertEqualComplete && isAssertNotNullComplete) || (isAssertEqualComplete && assertNotNulls.isEmpty()) || + (isAssertNotNullComplete && assertEquals.isEmpty())) { + isServiceAssertComplete = true; + testSummary.setAssertionStatus(Constants.PASSED_KEY); + log.info("Unit testing passed for test case - " + testCaseNumber); + } else { + testSummary.setAssertionStatus(Constants.FAILED_KEY); + log.error("Unit testing failed for test case - " + testCaseNumber); + } + + return new AbstractMap.SimpleEntry(isServiceAssertComplete, testSummary); + } + + + /** + * Method of assertionEquals for Sequence test cases. + * + * @param assertEquals array of assertEquals + * @param messageContext message context + * @return Map.Entry which has status of assertEquals and message if any error occurred + */ + private static Map.Entry startAssertEqualsForSequence(List assertEquals, + MessageContext messageContext) { + + log.info("AssertEquals - assert property for sequences started"); + boolean isAssertEqualFailed = false; + String messageOfAssertEqual = null; + + for (AssertEqual assertItem : assertEquals) { + + if (!isAssertEqualFailed) { + + String actual = assertItem.getActual(); + String expected = RequestProcessor.trimStrings(assertItem.getExpected()); + String message = assertItem.getMessage(); + boolean isAssert; + String[] actualType = actual.split(":"); + String actualProperty = actualType[0]; + String mediatedResult; + + Axis2MessageContext axis2MessageContext = (Axis2MessageContext) messageContext; + org.apache.axis2.context.MessageContext axis2MessageCtx = + axis2MessageContext.getAxis2MessageContext(); + + if (actualProperty.equals(INPUT_PROPERTY_BODY)) { + mediatedResult = + RequestProcessor.trimStrings(messageContext.getEnvelope().getBody().getFirstElement() + .toString()); + isAssert = expected.equals(mediatedResult); + + } else if (actualProperty.equals(INPUT_PROPERTY_CONTEXT)) { + mediatedResult = + RequestProcessor.trimStrings(messageContext.getProperty(actualType[1]).toString()); + isAssert = expected.equals(mediatedResult); + + } else if (actualProperty.equals(INPUT_PROPERTY_AXIS2)) { + mediatedResult = + RequestProcessor.trimStrings(axis2MessageCtx.getProperty(actualType[1]).toString()); + isAssert = expected.equals(mediatedResult); + + } else if (actualProperty.equals(INPUT_PROPERTY_TRANSPORT)) { + Object headers = axis2MessageContext.getProperty( + org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS); + + @SuppressWarnings("unchecked") + Map headersMap = (Map) headers; + mediatedResult = RequestProcessor.trimStrings(headersMap.get(actualType[1]).toString()); + isAssert = expected.equals(mediatedResult); + + } else { + isAssert = false; + mediatedResult = message; + message = "Received assert actual value for sequences not defined"; + } + + log.info("Sequence Assert Actual - " + actual); + log.info("Sequence Assert Expected - " + expected); + log.info("Sequence mediated result for actual - " + mediatedResult); + if (isAssert) { + log.info("Sequence assertEqual for " + actualProperty + " type passed successfully"); + } else { + isAssertEqualFailed = true; + messageOfAssertEqual = message; + log.error("Sequence assertEqual for " + actualProperty + " type failed - " + message + "\n"); + } + } + } + + log.info("AssertEquals assertion success - " + !isAssertEqualFailed); + return new AbstractMap.SimpleEntry(!isAssertEqualFailed, messageOfAssertEqual); + } + + /** + * Method of assertionNotNull for Sequence test cases. + * + * @param assertNotNull array of assertNotNull + * @param messageContext message context + * @return Map.Entry which has status of assertNotNull and message if any error occurred + */ + private static Map.Entry startAssertNotNullsForSequence(List assertNotNull, + MessageContext messageContext) { + + log.info("Assert Not Null - assert property for sequences started"); + boolean isAssertNotNullFailed = false; + String messageOfAssertNotNull = null; + + for (AssertNotNull assertItem : assertNotNull) { + + if (!isAssertNotNullFailed) { + + String actual = assertItem.getActual(); + String message = assertItem.getMessage(); + boolean isAssertNull; + String[] actualType = actual.split(":"); + String actualProperty = actualType[0]; + String mediatedResult; + + Axis2MessageContext axis2MessageContext = (Axis2MessageContext) messageContext; + org.apache.axis2.context.MessageContext axis2MessageCtx = + axis2MessageContext.getAxis2MessageContext(); + + if (actualProperty.equals(INPUT_PROPERTY_BODY)) { + mediatedResult = RequestProcessor.trimStrings( + messageContext.getEnvelope().getBody().getFirstElement().toString()); + isAssertNull = mediatedResult.isEmpty(); + break; + + } else if (actualProperty.equals(INPUT_PROPERTY_CONTEXT)) { + mediatedResult = + RequestProcessor.trimStrings(messageContext.getProperty(actualType[1]).toString()); + isAssertNull = mediatedResult.isEmpty(); + + } else if (actualProperty.equals(INPUT_PROPERTY_AXIS2)) { + mediatedResult = + RequestProcessor.trimStrings(axis2MessageCtx.getProperty(actualType[1]).toString()); + isAssertNull = mediatedResult.isEmpty(); + + } else if (actualProperty.equals(INPUT_PROPERTY_TRANSPORT)) { + Object headers = axis2MessageCtx.getProperty( + org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS); + + @SuppressWarnings("unchecked") + Map headersMap = (Map) headers; + mediatedResult = RequestProcessor.trimStrings(headersMap.get(actualType[1]).toString()); + isAssertNull = mediatedResult.isEmpty(); + + } else { + isAssertNull = true; + mediatedResult = message; + message = "Received assert actual value for sequences not defined"; + } + + log.info("Sequence Assert Actual - " + actual); + log.info("Sequence mediated result for actual is not null - " + !mediatedResult.isEmpty()); + + if (!isAssertNull) { + log.info("Sequence assertNotNull for " + actualProperty + " type passed successfully"); + } else { + isAssertNotNullFailed = true; + messageOfAssertNotNull = message; + log.error("Sequence assertNotNull for " + actualProperty + " type failed - " + message + "/n"); + } + } + + } + + log.info("AssertNotNull assertion success - " + !isAssertNotNullFailed); + return new AbstractMap.SimpleEntry(!isAssertNotNullFailed, messageOfAssertNotNull); + } + + /** + * Method of assertionEquals for Service test cases. + * + * @param assertEquals array of assertEquals + * @param response service response body + * @param headers service response headers + * @return Map.Entry which has status of assertEquals and message if any error occurred + */ + private static Map.Entry startAssertEqualsForServices( + List assertEquals, String response, Header[] headers) { + + log.info("Assert Equals - assert property for services started"); + boolean isAssertEqualFailed = false; + String messageOfAssertEqual = null; + + for (AssertEqual assertItem : assertEquals) { + + if (isAssertEqualFailed) { + break; + } + + String actual = assertItem.getActual(); + String expected = RequestProcessor.trimStrings(assertItem.getExpected()); + String message = assertItem.getMessage(); + boolean isAssert = false; + String[] actualType = actual.split(":"); + String actualProperty = actualType[0]; + String mediatedResult = "null"; + + if (actualProperty.equals(INPUT_PROPERTY_BODY)) { + mediatedResult = RequestProcessor.trimStrings(response); + isAssert = expected.equals(mediatedResult); + + } else if (actualProperty.equals(INPUT_PROPERTY_TRANSPORT)) { + + for (Header header : headers) { + if (header.getName().equals(actualType[1])) { + mediatedResult = RequestProcessor.trimStrings(header.getValue()); + isAssert = expected.equals(mediatedResult); + break; + } + } + + } else { + message = "Received assert actual value not defined"; + mediatedResult = message; + } + + log.info("Service Assert Actual - " + actual); + log.info("Service Assert Expected - " + expected); + log.info("Service mediated result for actual - " + mediatedResult); + + if (isAssert) { + log.info("Service assertEqual for " + actualProperty + " passed successfully"); + } else { + isAssertEqualFailed = true; + messageOfAssertEqual = message; + log.error("Service assertEqual for " + actualProperty + " failed - " + message + "\n"); + } + } + + log.info("AssertEquals assertion success - " + !isAssertEqualFailed); + return new AbstractMap.SimpleEntry(!isAssertEqualFailed, messageOfAssertEqual); + } + + /** + * Method of assertNotNull for Service test cases. + * + * @param assertNotNull array of assertNotNull + * @param response service response body + * @param headers service response headers + * @return Map.Entry which has status of assertNotNull and message if any error occurred + */ + private static Map.Entry startAssertNotNullsForServices( + List assertNotNull, String response, Header[] headers) { + + log.info("Assert Not Null - assert property for services started"); + boolean isAssertNotNullFailed = false; + String messageOfAssertNotNull = null; + + for (AssertNotNull assertItem : assertNotNull) { + + if (isAssertNotNullFailed) { + break; + } + + String actual = assertItem.getActual(); + String message = assertItem.getMessage(); + boolean isAssertNull = false; + String[] actualType = actual.split(":"); + String actualProperty = actualType[0]; + String mediatedResult = "null"; + + if (actualProperty.equals(INPUT_PROPERTY_BODY)) { + mediatedResult = response; + isAssertNull = mediatedResult.isEmpty(); + + } else if (actualProperty.equals(INPUT_PROPERTY_TRANSPORT)) { + for (Header header : headers) { + if (header.getName().equals(actualType[1])) { + mediatedResult = RequestProcessor.trimStrings(header.getValue()); + isAssertNull = mediatedResult.isEmpty(); + break; + } + } + + } else { + message = "Received assert actual value for service not defined"; + mediatedResult = message; + } + + log.info("Service Assert Actual - " + actual); + log.info("Service mediated result for actual is not null- " + !mediatedResult.isEmpty()); + + if (!isAssertNull) { + log.info("Service assertNotNull for " + actualProperty + " passed successfully"); + } else { + isAssertNotNullFailed = true; + messageOfAssertNotNull = message; + log.error("Service assertNotNull for " + actualProperty + " failed - " + message + "\n"); + } + } + + log.info("AssertNotNull assertion success - " + !isAssertNotNullFailed); + return new AbstractMap.SimpleEntry(!isAssertNotNullFailed, messageOfAssertNotNull); + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/CommonUtils.java b/modules/core/src/main/java/org/apache/synapse/unittest/CommonUtils.java new file mode 100644 index 000000000..f87f18abb --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/CommonUtils.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +/** + * Class responsible for the common utilities in unit test. + */ +class CommonUtils { + + private CommonUtils() { + } + + /** + * Get stack trace from the exception. + * + * @param exception exception + * @return exception stack trace as a string + */ + static String stackTraceToString(Throwable exception) { + StringBuilder sb = new StringBuilder(); + sb.append(exception.getMessage()); + sb.append(Constants.NEW_LINE); + + for (StackTraceElement element : exception.getStackTrace()) { + sb.append(element.toString()); + sb.append(Constants.NEW_LINE); + } + return sb.toString(); + } + + /** + * Get stack trace from the exception with custom error message. + * + * @param exception exception + * @param customErrorMessage custom error message + * @return exception stack trace as a string + */ + static String stackTraceToString(Throwable exception, String customErrorMessage) { + StringBuilder sb = new StringBuilder(); + sb.append(customErrorMessage); + sb.append(Constants.NEW_LINE); + sb.append(exception.getMessage()); + sb.append(Constants.NEW_LINE); + + for (StackTraceElement element : exception.getStackTrace()) { + sb.append(element.toString()); + sb.append(Constants.NEW_LINE); + } + return sb.toString(); + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/ConfigurationDeployer.java b/modules/core/src/main/java/org/apache/synapse/unittest/ConfigurationDeployer.java new file mode 100755 index 000000000..225eed049 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/ConfigurationDeployer.java @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +import org.apache.axiom.om.OMElement; +import org.apache.axis2.AxisFault; +import org.apache.axis2.context.ConfigurationContext; +import org.apache.axis2.description.Parameter; +import org.apache.axis2.engine.AxisConfiguration; +import org.apache.synapse.SynapseConstants; +import org.apache.synapse.config.SynapseConfiguration; +import org.apache.synapse.core.SynapseEnvironment; +import org.apache.synapse.core.axis2.Axis2SynapseEnvironment; +import org.apache.synapse.deployers.APIDeployer; +import org.apache.synapse.deployers.EndpointDeployer; +import org.apache.synapse.deployers.LocalEntryDeployer; +import org.apache.synapse.deployers.ProxyServiceDeployer; +import org.apache.synapse.deployers.SequenceDeployer; + +import java.util.AbstractMap; +import java.util.Map; + +/** + * Util class for deploying synapse artifacts to the synapse engine. + */ +class ConfigurationDeployer { + + /** + * Method of deploying sequence artifact in synapse. + * + * @param inputElement synapse configuration artifact as OMElement type + * @param fileName name of the file + * @return response of the artifact deployment and the synapse configuration as a Map.Entry + */ + Map.Entry deploySequenceArtifact(OMElement inputElement, String fileName) + throws AxisFault { + + //create new sequence deployer object + SequenceDeployer sequenceDeployer = new SequenceDeployer(); + + //create a synapse configuration and set all axis2 configuration to it + SynapseConfiguration synapseConfiguration = UnitTestingExecutor.getExecuteInstance().getSynapseConfiguration(); + AxisConfiguration axisConfiguration = synapseConfiguration.getAxisConfiguration(); + ConfigurationContext configurationContext = new ConfigurationContext(axisConfiguration); + SynapseEnvironment synapseEnvironment = new Axis2SynapseEnvironment(configurationContext, synapseConfiguration); + + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_ENV, synapseEnvironment)); + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_CONFIG, synapseConfiguration)); + configurationContext.setAxisConfiguration(axisConfiguration); + + //initialize sequence deployer using created configuration context + sequenceDeployer.init(configurationContext); + + //deploy synapse artifact + String deployedArtifact = sequenceDeployer.deploySynapseArtifact(inputElement, fileName, null); + + return new AbstractMap.SimpleEntry(synapseConfiguration, deployedArtifact); + } + + /** + * Method of deploying proxy artifact in synapse. + * + * @param inputElement synapse configuration artifact as OMElement type + * @param fileName name of the file + * @return response of the artifact deployment and the synapse configuration as a Map.Entry + */ + Map.Entry deployProxyArtifact(OMElement inputElement, String fileName) + throws AxisFault { + + //create new proxy service deployer object + ProxyServiceDeployer proxyServiceDeployer = new ProxyServiceDeployer(); + + //create a synapse configuration and set all axis2 configuration to it + SynapseConfiguration synapseConfiguration = UnitTestingExecutor.getExecuteInstance().getSynapseConfiguration(); + AxisConfiguration axisConfiguration = synapseConfiguration.getAxisConfiguration(); + ConfigurationContext configurationContext = new ConfigurationContext(axisConfiguration); + SynapseEnvironment synapseEnvironment = new Axis2SynapseEnvironment(configurationContext, synapseConfiguration); + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_ENV, synapseEnvironment)); + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_CONFIG, synapseConfiguration)); + configurationContext.setAxisConfiguration(axisConfiguration); + + //initialize proxy service deployer using created configuration context + proxyServiceDeployer.init(configurationContext); + + //deploy synapse artifact + String deployedArtifact = proxyServiceDeployer.deploySynapseArtifact(inputElement, fileName, null); + + return new AbstractMap.SimpleEntry(synapseConfiguration, deployedArtifact); + } + + /** + * Method of deploying API artifact in synapse. + * + * @param inputElement synapse configuration artifact as OMElement type + * @param fileName name of the file + * @return response of the artifact deployment and the synapse configuration as a Map.Entry + */ + Map.Entry deployApiArtifact(OMElement inputElement, String fileName) + throws AxisFault { + + //create new API deployer object + APIDeployer apiResourceDeployer = new APIDeployer(); + + //create a synapse configuration and set all axis2 configuration to it + SynapseConfiguration synapseConfiguration = UnitTestingExecutor.getExecuteInstance().getSynapseConfiguration(); + AxisConfiguration axisConfiguration = synapseConfiguration.getAxisConfiguration(); + ConfigurationContext configurationContext = new ConfigurationContext(axisConfiguration); + + SynapseEnvironment synapseEnvironment = new Axis2SynapseEnvironment(configurationContext, synapseConfiguration); + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_ENV, synapseEnvironment)); + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_CONFIG, synapseConfiguration)); + configurationContext.setAxisConfiguration(axisConfiguration); + + //initialize API deployer using created configuration context + apiResourceDeployer.init(configurationContext); + + //deploy synapse artifact + String deployedArtifact = apiResourceDeployer.deploySynapseArtifact(inputElement, fileName, null); + + return new AbstractMap.SimpleEntry(synapseConfiguration, deployedArtifact); + } + + /** + * Method of deploying endpoint artifact in synapse. + * + * @param inputElement synapse configuration artifact as OMElement type + * @param fileName name of the file + * @return response of the artifact deployment and the synapse configuration as a Map.Entry + */ + Map.Entry deployEndpointArtifact(OMElement inputElement, String fileName) + throws AxisFault { + + //create new sequence deployer object + EndpointDeployer endpointDeployer = new EndpointDeployer(); + + //create a synapse configuration and set all axis2 configuration to it + SynapseConfiguration synapseConfiguration = UnitTestingExecutor.getExecuteInstance().getSynapseConfiguration(); + AxisConfiguration axisConfiguration = synapseConfiguration.getAxisConfiguration(); + ConfigurationContext configurationContext = new ConfigurationContext(axisConfiguration); + SynapseEnvironment synapseEnvironment = new Axis2SynapseEnvironment(configurationContext, synapseConfiguration); + + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_ENV, synapseEnvironment)); + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_CONFIG, synapseConfiguration)); + configurationContext.setAxisConfiguration(axisConfiguration); + + //initialize sequence deployer using created configuration context + endpointDeployer.init(configurationContext); + + //deploy synapse artifact + String deployedArtifact = endpointDeployer.deploySynapseArtifact(inputElement, fileName, null); + + return new AbstractMap.SimpleEntry(synapseConfiguration, deployedArtifact); + } + + /** + * Method of deploying endpoint artifact in synapse. + * + * @param inputElement synapse configuration artifact as OMElement type + * @param fileName name of the file + * @return response of the artifact deployment and the synapse configuration as a Map.Entry + */ + Map.Entry deployLocalEntryArtifact(OMElement inputElement, String fileName) + throws AxisFault { + + //create new sequence deployer object + LocalEntryDeployer localEntryDeployer = new LocalEntryDeployer(); + + //create a synapse configuration and set all axis2 configuration to it + SynapseConfiguration synapseConfiguration = UnitTestingExecutor.getExecuteInstance().getSynapseConfiguration(); + AxisConfiguration axisConfiguration = synapseConfiguration.getAxisConfiguration(); + ConfigurationContext configurationContext = new ConfigurationContext(axisConfiguration); + SynapseEnvironment synapseEnvironment = new Axis2SynapseEnvironment(configurationContext, synapseConfiguration); + + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_ENV, synapseEnvironment)); + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_CONFIG, synapseConfiguration)); + configurationContext.setAxisConfiguration(axisConfiguration); + + //initialize sequence deployer using created configuration context + localEntryDeployer.init(configurationContext); + + //deploy synapse artifact + String deployedArtifact = localEntryDeployer.deploySynapseArtifact(inputElement, fileName, null); + + return new AbstractMap.SimpleEntry(synapseConfiguration, deployedArtifact); + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/Constants.java b/modules/core/src/main/java/org/apache/synapse/unittest/Constants.java new file mode 100755 index 000000000..62e6270de --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/Constants.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +/** + * Constants for unit testing framework for synapse. + */ +public class Constants { + + private Constants() { + } + + //deployer constants + static final String TYPE_SEQUENCE = "sequence"; + static final String TYPE_PROXY = "proxy"; + static final String TYPE_API = "api"; + static final String TYPE_ENDPOINT = "endpoint"; + static final String TYPE_LOCAL_ENTRY = "localEntry"; + + //artifact key word constants + static final String API_CONTEXT = "context"; + static final String NAME_ATTRIBUTE = "name"; + static final String ARTIFACT_TRANSPORTS_ATTRIBUTE = "transports"; + static final String ARTIFACT_KEY_ATTRIBUTE = "key"; + static final String ARTIFACT = "artifact"; + static final String TEST_ARTIFACT = "test-artifact"; + static final String SUPPORTIVE_ARTIFACTS = "supportive-artifacts"; + static final String ARTIFACTS = "artifacts"; + + //test case key word constants + static final String TEST_CASES = "test-cases"; + static final String TEST_CASE_REQUEST_PATH = "request-path"; + static final String TEST_CASE_REQUEST_METHOD = "request-method"; + static final String TEST_CASE_INPUT = "input"; + static final String TEST_CASE_INPUT_PAYLOAD = "payload"; + static final String TEST_CASE_INPUT_PROPERTIES = "properties"; + static final String TEST_CASE_INPUT_PROPERTY_NAME = "name"; + static final String TEST_CASE_INPUT_PROPERTY_VALUE = "value"; + static final String TEST_CASE_INPUT_PROPERTY_SCOPE = "scope"; + static final String TEST_CASE_ASSERTIONS = "assertions"; + static final String TEST_CASE_ASSERTION_EQUALS = "assertEquals"; + static final String TEST_CASE_ASSERTION_NOTNULL = "assertNotNull"; + static final String ASSERTION_ACTUAL = "actual"; + static final String ASSERTION_EXPECTED = "expected"; + static final String ASSERTION_MESSAGE = "message"; + static final String INPUT_PROPERTY_SCOPE_DEFAULT = "default"; + static final String INPUT_PROPERTY_SCOPE_AXIS2 = "axis2"; + static final String INPUT_PROPERTY_SCOPE_TRANSPORT = "transport"; + static final String INPUT_PROPERTY_BODY = "$body"; + static final String INPUT_PROPERTY_CONTEXT = "$ctx"; + static final String INPUT_PROPERTY_AXIS2 = "$axis2"; + static final String INPUT_PROPERTY_TRANSPORT = "$trp"; + + //mock service key word constants + public static final String URI = "uri"; + public static final String HTTP = "http://"; + static final String GET_METHOD = "GET"; + static final String POST_METHOD = "POST"; + static final String PUT_METHOD = "PUT"; + static final String DELETE_METHOD = "DELETE"; + + //api/proxy invoke constants + static final String HTTP_LOCALHOST_URL = "http://localhost:"; + static final String HTTP_KEY = "http"; + static final String HTTPS_KEY = "https"; + static final String HTTPS_LOCALHOST_URL = "https://localhost:"; + static final String PROXY_INVOKE_PREFIX_URL = "/services/"; + + //test summary report constants + static final String PASSED_KEY = "PASSED"; + static final String FAILED_KEY = "FAILED"; + static final String SKIPPED_KEY = "SKIPPED"; + static final String DEPLOYMENT_STATUS = "deploymentStatus"; + static final String DEPLOYMENT_EXCEPTION = "deploymentException"; + static final String DEPLOYMENT_DESCRIPTION = "deploymentDescription"; + static final String TEST_CASE_NAME = "testCaseName"; + static final String MEDIATION_STATUS = "mediationStatus"; + static final String MEDIATION_EXCEPTION = "mediationException"; + static final String CURRENT_TESTCASE = "currentTestCase"; + static final String ASSERTION_EXCEPTION = "exception"; + static final String ASSERTION_STATUS = "assertionStatus"; + + //parameter constants + static final String PRAM_TEMP_DIR = "java.io.tmpdir"; + + //common constants + static final String NEW_LINE = "\n"; +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/RequestHandler.java b/modules/core/src/main/java/org/apache/synapse/unittest/RequestHandler.java new file mode 100755 index 000000000..12fa1e0a4 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/RequestHandler.java @@ -0,0 +1,298 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import org.apache.log4j.Logger; +import org.apache.synapse.unittest.testcase.data.classes.SynapseTestCase; +import org.apache.synapse.unittest.testcase.data.classes.TestCaseSummary; +import org.apache.synapse.unittest.testcase.data.classes.TestSuiteSummary; +import org.apache.synapse.unittest.testcase.data.holders.ArtifactData; +import org.apache.synapse.unittest.testcase.data.holders.TestCaseData; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.AbstractMap; +import java.util.Map; + +/** + * Class is implements with Runnable. + * Handle multiple requests from the client + * Process receive message and response to the particular client + */ +public class RequestHandler implements Runnable { + + private static Logger log = Logger.getLogger(UnitTestingExecutor.class.getName()); + + private Socket socket; + private boolean isTransportPassThroughPortChecked = false; + private String exception; + private TestSuiteSummary testSuiteSummary = new TestSuiteSummary(); + + /** + * Initializing RequestHandler withe the client socket connection. + */ + RequestHandler(Socket socket) { + this.socket = socket; + } + + @Override + public void run() { + try { + log.info("Start processing test-case handler\n"); + checkTransportPassThroughPortAvailability(); + + String receivedData = readData(); + SynapseTestCase synapseTestCases = preProcessingData(receivedData); + + if (synapseTestCases != null) { + runTestingAgent(synapseTestCases); + } else { + log.error("Reading Synapse testcase data failed"); + testSuiteSummary.setDescription("Failed while reading synapseTestCase data"); + testSuiteSummary.setDeploymentStatus(Constants.SKIPPED_KEY); + testSuiteSummary.setDeploymentException(exception); + } + + writeData(testSuiteSummary); + log.info("End processing test-case handler\n"); + } catch (Exception e) { + log.error("Error while running client request in test agent", e); + } finally { + closeSocket(); + } + } + + /** + * Read input data from the unit testing client. + * + * @return read data from the client + */ + private String readData() { + String inputFromClient = null; + + try { + InputStream inputStream = socket.getInputStream(); + ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); + inputFromClient = (String) objectInputStream.readObject(); + + } catch (Exception e) { + log.error("Failed to get input stream from TCP connection", e); + } + + //receiving message from the client + return inputFromClient; + + } + + /** + * Processed received message data and stores those data in relevant data holders. + * Uses configModifier if there are some mock services to start + * + * @param receivedMessage received synapseTestcase data message as String + * @return SynapaseTestCase object contains artifact, test cases and mock services data + */ + private SynapseTestCase preProcessingData(String receivedMessage) { + + try { + //Read relevant data from the received message and add to the relevant data holders + SynapseTestcaseDataReader synapseTestcaseDataReader = new SynapseTestcaseDataReader(receivedMessage); + + ArtifactData readArtifactData = synapseTestcaseDataReader.readAndStoreArtifactData(); + TestCaseData readTestCaseData = synapseTestcaseDataReader.readAndStoreTestCaseData(); + + //wrap the artifact data, testcase data and mock service data as one + SynapseTestCase synapseTestCases = new SynapseTestCase(); + synapseTestCases.setArtifacts(readArtifactData); + synapseTestCases.setTestCases(readTestCaseData); + + return synapseTestCases; + + } catch (Exception e) { + log.error("Error while reading data from received message", e); + exception = CommonUtils.stackTraceToString(e); + return null; + } + + } + + /** + * Execute test agent for artifact deployment and mediation using receiving JSON message. + * + * @param synapseTestCase test cases data received from client + */ + private void runTestingAgent(SynapseTestCase synapseTestCase) { + + TestingAgent agent = new TestingAgent(); + Map.Entry supportiveArtifactDeployment = + new AbstractMap.SimpleEntry(false, null); + Map.Entry testArtifactDeployment = + new AbstractMap.SimpleEntry(false, null); + + //get results of supportive-artifact deployment if exists + if (synapseTestCase.getArtifacts().getSupportiveArtifactCount() > 0) { + log.info("Supportive artifacts deployment started"); + supportiveArtifactDeployment = agent.processSupportiveArtifacts(synapseTestCase, testSuiteSummary); + } + + //check supportive-artifact deployment is success or not + if (supportiveArtifactDeployment.getKey() || synapseTestCase.getArtifacts().getSupportiveArtifactCount() == 0) { + log.info("Test artifact deployment started"); + testSuiteSummary.setDeploymentStatus(Constants.PASSED_KEY); + testArtifactDeployment = agent.processTestArtifact(synapseTestCase, testSuiteSummary); + + } else if (!supportiveArtifactDeployment.getKey() && + supportiveArtifactDeployment.getValue().getDeploymentException() != null) { + testSuiteSummary.setDeploymentStatus(Constants.FAILED_KEY); + + } else { + testSuiteSummary.setDeploymentStatus(Constants.FAILED_KEY); + testSuiteSummary.setDescription("supportive artifact deployment failed"); + } + + //check test-artifact deployment is success or not + if (testArtifactDeployment.getKey()) { + + log.info("Synapse testing agent ready to mediate test cases through deployments"); + //performs test cases through the deployed synapse configuration + agent.processTestCases(synapseTestCase, testSuiteSummary); + + } else if (!testArtifactDeployment.getKey() && testArtifactDeployment.getValue() != null) { + testSuiteSummary.setDeploymentStatus(Constants.FAILED_KEY); + } else { + testSuiteSummary.setDeploymentStatus(Constants.FAILED_KEY); + testSuiteSummary.setDescription("test artifact deployment failed"); + } + + //undeploy all the deployed artifacts + agent.artifactUndeployer(); + } + + /** + * Write output data to the unit testing client. + */ + private void writeData(TestSuiteSummary testSummary) throws IOException { + JsonObject jsonObject = createResponseJSON(testSummary); + OutputStream out = socket.getOutputStream(); + ObjectOutputStream o = new ObjectOutputStream(out); + o.writeObject(jsonObject.toString()); + out.flush(); + } + + /** + * Create a json response message including all the details of the test suite. + * + * @return json message + */ + private JsonObject createResponseJSON(TestSuiteSummary testSummary) { + JsonObject jsonResponse = new JsonObject(); + jsonResponse.addProperty(Constants.DEPLOYMENT_STATUS, testSummary.getDeploymentStatus()); + jsonResponse.addProperty(Constants.DEPLOYMENT_EXCEPTION, testSummary.getDeploymentException()); + jsonResponse.addProperty(Constants.DEPLOYMENT_DESCRIPTION, testSummary.getDescription()); + jsonResponse.addProperty(Constants.MEDIATION_STATUS, testSummary.getMediationStatus()); + jsonResponse.addProperty(Constants.CURRENT_TESTCASE, testSummary.getRecentTestCaseName()); + jsonResponse.addProperty(Constants.MEDIATION_EXCEPTION, testSummary.getMediationException()); + + JsonArray jsonArray = new JsonArray(); + for (TestCaseSummary summary : testSummary.getTestCaseSumamryList()) { + JsonObject testObject = new JsonObject(); + testObject.addProperty(Constants.TEST_CASE_NAME, summary.getTestCaseName()); + testObject.addProperty(Constants.MEDIATION_STATUS, summary.getMediationStatus()); + testObject.addProperty(Constants.ASSERTION_STATUS, summary.getAssertionStatus()); + testObject.addProperty(Constants.ASSERTION_EXCEPTION, summary.getTestException()); + + jsonArray.add(testObject); + } + + jsonResponse.add("testCases", jsonArray); + return jsonResponse; + } + + /** + * Check transport pass through port is started or not. + * Waits until port started to receive the request from client + */ + private void checkTransportPassThroughPortAvailability() throws IOException { + + if (!isTransportPassThroughPortChecked) { + log.info("Unit testing agent checks transport Pass-through HTTP Listener port"); + + boolean isPassThroughPortNotOccupied = true; + int transportPassThroughPort = 8280; + long timeoutExpiredMs = System.currentTimeMillis() + 10000; + + while (isPassThroughPortNotOccupied) { + long waitMillis = timeoutExpiredMs - System.currentTimeMillis(); + isPassThroughPortNotOccupied = checkPortAvailability(transportPassThroughPort); + + if (waitMillis <= 0) { + // timeout expired + throw new IOException("Connection refused for http Pass-through HTTP Listener port - " + + transportPassThroughPort); + } + } + + isTransportPassThroughPortChecked = true; + } + } + + /** + * Check port availability. + * + * @param port port which want to check availability + * @return if available true else false + */ + private boolean checkPortAvailability(int port) { + boolean isPortAvailable; + Socket socketTester = new Socket(); + try { + socketTester.connect(new InetSocketAddress("127.0.0.1", port)); + isPortAvailable = false; + } catch (IOException e) { + isPortAvailable = true; + } finally { + try { + socketTester.close(); + } catch (IOException e) { + log.error("Error when closing socket testing connection", e); + } + } + + return isPortAvailable; + } + + /** + * close the TCP connection with client. + */ + private void closeSocket() { + try { + socket.close(); + } catch (IOException e) { + log.error("Error when closing socket connection", e); + } + } + +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/RequestProcessor.java b/modules/core/src/main/java/org/apache/synapse/unittest/RequestProcessor.java new file mode 100755 index 000000000..13e07835c --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/RequestProcessor.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.StringReader; +import java.io.StringWriter; + +/** + * Class responsible for removing the unwanted whitespaces in any type of inputs. + */ +public class RequestProcessor { + + RequestProcessor() { + } + + private static Logger log = Logger.getLogger(RequestProcessor.class.getName()); + + /** + * Remove irrelevant whitespaces from the input string. + * If string is a XML or JSON reordered the structure of the string to normalize + * + * @param inputString string which needs to remove whitespaces + * @return trim string not include irrelevant whitespaces + */ + public static String trimStrings(String inputString) { + + //trim the string + String trimedString = inputString.trim(); + + //remove CDATA tag from the string if exists + if (trimedString.startsWith(""); + if (i == -1) + throw new IllegalStateException("argument starts with "); + trimedString = trimedString.substring(0, i); + } + + trimedString = convertStringToRelatedDocumentType(trimedString); + return trimedString.replaceAll("\\s", ""); + } + + /** + * Check the input string is a XML type and generate a XML object and convert it to string. + * Check the input string is a JSON type and generate a JSON object and convert it to string. + * + * @param domString inputString which about to convert + * @return reordered trim string not include irrelevant whitespaces + */ + private static String convertStringToRelatedDocumentType(String domString) { + //Parser that produces DOM object trees from XML content + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + //API to obtain DOM Document instance + DocumentBuilder builder; + + String processedString; + try { + //Create DocumentBuilder with default configuration + builder = factory.newDocumentBuilder(); + + //Parse the content to Document object + Document xmlDOM = builder.parse(new InputSource(new StringReader(domString))); + processedString = nodeToString(xmlDOM); + processedString = processedString.replaceAll("xmlns=\"\"", ""); + } catch (Exception e) { + processedString = convertAsJSONString(domString); + } + + return processedString; + } + + /** + * Convert XML document to string. + * + * @param node document node which represent XML + * @return converted document element as a string + */ + private static String nodeToString(Node node) { + StringWriter sw = new StringWriter(); + try { + Transformer t = TransformerFactory.newInstance().newTransformer(); + t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + t.setOutputProperty(OutputKeys.INDENT, "yes"); + t.transform(new DOMSource(node), new StreamResult(sw)); + } catch (Exception e) { + log.error("nodeToString Transformer Exception", e); + } + return sw.toString(); + } + + /** + * Create JSON object using input string. + * If failed return as it is. + * + * @param inputString input string which is not an XML + * @return reordered string + */ + private static String convertAsJSONString(String inputString) { + try { + JsonObject inputJSON = new JsonParser().parse(inputString).getAsJsonObject(); + return inputJSON.toString(); + } catch (Exception e) { + return inputString; + } + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/SynapseTestcaseDataReader.java b/modules/core/src/main/java/org/apache/synapse/unittest/SynapseTestcaseDataReader.java new file mode 100755 index 000000000..f5c017369 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/SynapseTestcaseDataReader.java @@ -0,0 +1,376 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +import org.apache.axiom.om.OMElement; +import org.apache.axiom.om.util.AXIOMUtil; +import org.apache.log4j.Logger; +import org.apache.synapse.unittest.testcase.data.classes.Artifact; +import org.apache.synapse.unittest.testcase.data.classes.AssertEqual; +import org.apache.synapse.unittest.testcase.data.classes.AssertNotNull; +import org.apache.synapse.unittest.testcase.data.classes.TestCase; +import org.apache.synapse.unittest.testcase.data.holders.ArtifactData; +import org.apache.synapse.unittest.testcase.data.holders.TestCaseData; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import static org.apache.synapse.unittest.Constants.ARTIFACT; +import static org.apache.synapse.unittest.Constants.ARTIFACTS; +import static org.apache.synapse.unittest.Constants.ARTIFACT_KEY_ATTRIBUTE; +import static org.apache.synapse.unittest.Constants.ARTIFACT_TRANSPORTS_ATTRIBUTE; +import static org.apache.synapse.unittest.Constants.ASSERTION_ACTUAL; +import static org.apache.synapse.unittest.Constants.ASSERTION_EXPECTED; +import static org.apache.synapse.unittest.Constants.ASSERTION_MESSAGE; +import static org.apache.synapse.unittest.Constants.HTTPS_KEY; +import static org.apache.synapse.unittest.Constants.HTTP_KEY; +import static org.apache.synapse.unittest.Constants.NAME_ATTRIBUTE; +import static org.apache.synapse.unittest.Constants.SUPPORTIVE_ARTIFACTS; +import static org.apache.synapse.unittest.Constants.TEST_ARTIFACT; +import static org.apache.synapse.unittest.Constants.TEST_CASES; +import static org.apache.synapse.unittest.Constants.TEST_CASE_ASSERTIONS; +import static org.apache.synapse.unittest.Constants.TEST_CASE_ASSERTION_EQUALS; +import static org.apache.synapse.unittest.Constants.TEST_CASE_ASSERTION_NOTNULL; +import static org.apache.synapse.unittest.Constants.TEST_CASE_INPUT; +import static org.apache.synapse.unittest.Constants.TEST_CASE_INPUT_PAYLOAD; +import static org.apache.synapse.unittest.Constants.TEST_CASE_INPUT_PROPERTIES; +import static org.apache.synapse.unittest.Constants.TEST_CASE_INPUT_PROPERTY_NAME; +import static org.apache.synapse.unittest.Constants.TEST_CASE_INPUT_PROPERTY_SCOPE; +import static org.apache.synapse.unittest.Constants.TEST_CASE_INPUT_PROPERTY_VALUE; +import static org.apache.synapse.unittest.Constants.TEST_CASE_REQUEST_METHOD; +import static org.apache.synapse.unittest.Constants.TEST_CASE_REQUEST_PATH; +import static org.apache.synapse.unittest.Constants.TYPE_LOCAL_ENTRY; +import static org.apache.synapse.unittest.Constants.TYPE_PROXY; + + +/** + * descriptor data read class in unit test framework. + */ +class SynapseTestcaseDataReader { + + private static Logger log = Logger.getLogger(SynapseTestcaseDataReader.class.getName()); + private OMElement importXMLFile = null; + + /** + * Constructor of the SynapseTestcaseDataReader class. + * + * @param descriptorData defines the descriptor data of the received message + */ + SynapseTestcaseDataReader(String descriptorData) { + try { + this.importXMLFile = AXIOMUtil.stringToOM(descriptorData); + + } catch (Exception e) { + log.error(e); + } + + } + + /** + * Read artifact data from the descriptor data. + * Append artifact data into the data holder object + * + * @return dataHolder object with artifact data + */ + ArtifactData readAndStoreArtifactData() throws XMLStreamException, IOException { + ArtifactData artifactDataHolder = new ArtifactData(); + Artifact testArtifact = new Artifact(); + + //Read artifact from descriptor data + QName qualifiedArtifacts = new QName("", ARTIFACTS, ""); + OMElement artifactsNode = importXMLFile.getFirstChildWithName(qualifiedArtifacts); + + QName qualifiedTestArtifact = new QName("", TEST_ARTIFACT, ""); + OMElement testArtifactNode = artifactsNode.getFirstChildWithName(qualifiedTestArtifact); + + QName qualifiedArtifact = new QName("", ARTIFACT, ""); + OMElement testArtifactDataNode = testArtifactNode.getFirstChildWithName(qualifiedArtifact); + String testArtifactData = testArtifactDataNode.getFirstElement().toString(); + testArtifact.setArtifact(testArtifactData); + + //Read test artifact type from synapse test data + String testArtifactType = testArtifactDataNode.getFirstElement().getLocalName(); + testArtifact.setArtifactType(testArtifactType); + + //Read artifact name from descriptor data + String testArtifactNameOrKey; + if (testArtifactType.equals(TYPE_LOCAL_ENTRY)) { + testArtifactNameOrKey + = testArtifactDataNode.getFirstElement().getAttributeValue(new QName(ARTIFACT_KEY_ATTRIBUTE)); + } else { + testArtifactNameOrKey + = testArtifactDataNode.getFirstElement().getAttributeValue(new QName(NAME_ATTRIBUTE)); + } + testArtifact.setArtifactNameOrKey(testArtifactNameOrKey); + + //Read artifact transport from descriptor data if artifact is a proxy + if (testArtifact.getArtifactType().equals(TYPE_PROXY)) { + String transport = testArtifactDataNode.getFirstElement() + .getAttributeValue(new QName(ARTIFACT_TRANSPORTS_ATTRIBUTE)); + if (transport == null) { + throw new IOException("Local transport method for proxy currently not supported"); + } + + String[] transportMethods = transport.split(" "); + if (Arrays.asList(transportMethods).contains(HTTP_KEY)) { + testArtifact.setTransportMethod(HTTP_KEY); + } else if (Arrays.asList(transportMethods).contains(HTTPS_KEY)) { + testArtifact.setTransportMethod(HTTPS_KEY); + } else { + throw new IOException("Defined transport method for proxy currently not supported"); + } + } + + artifactDataHolder.setTestArtifact(testArtifact); + + //Read supportive test cases data + QName qualifiedSupportiveTestArtifact = new QName("", SUPPORTIVE_ARTIFACTS, ""); + OMElement supportiveArtifactsNode = artifactsNode.getFirstChildWithName(qualifiedSupportiveTestArtifact); + + Iterator artifactIterator = Collections.emptyIterator(); + int supportiveArtifactCount = 0; + + if (supportiveArtifactsNode != null) { + artifactIterator = supportiveArtifactsNode.getChildElements(); + } + + while (artifactIterator.hasNext()) { + OMElement artifact = (OMElement) artifactIterator.next(); + Artifact supportiveArtifact = new Artifact(); + + //Read supportive artifact from synapse test data + String supportiveArtifactData = artifact.getFirstElement().toString(); + supportiveArtifact.setArtifact(supportiveArtifactData); + + //Read supportive artifact type from synapse test data + String supportiveArtifactType = artifact.getFirstElement().getLocalName(); + supportiveArtifact.setArtifactType(supportiveArtifactType); + + //Read artifact name from descriptor data + String supportiveArtifactNameOrKey; + if (testArtifactType.equals(TYPE_LOCAL_ENTRY)) { + supportiveArtifactNameOrKey + = artifact.getFirstElement().getAttributeValue(new QName(ARTIFACT_KEY_ATTRIBUTE)); + } else { + supportiveArtifactNameOrKey + = artifact.getFirstElement().getAttributeValue(new QName(NAME_ATTRIBUTE)); + } + supportiveArtifact.setArtifactNameOrKey(supportiveArtifactNameOrKey); + + artifactDataHolder.addSupportiveArtifact(supportiveArtifact); + supportiveArtifactCount++; + } + + //set supportive artifact count + artifactDataHolder.setSupportiveArtifactCount(supportiveArtifactCount); + + log.info("Artifact data from descriptor data read successfully"); + return artifactDataHolder; + } + + /** + * Read test-case data from the descriptor data. + * Append test-case data into the test data holder object + * + * @return testCaseDataHolder object with test case data + */ + TestCaseData readAndStoreTestCaseData() { + + TestCaseData testCaseDataHolder = new TestCaseData(); + + //Set test case count as zero + int testCasesCount = 0; + + //Read test cases from descriptor data + QName qualifiedTestCases = new QName("", TEST_CASES, ""); + OMElement testCasesNode = importXMLFile.getFirstChildWithName(qualifiedTestCases); + + //Iterate through test-cases in descriptor data + Iterator testCaseIterator = Collections.emptyIterator(); + if (testCasesNode != null) { + testCaseIterator = testCasesNode.getChildElements(); + } + + while (testCaseIterator.hasNext()) { + TestCase testCase = new TestCase(); + OMElement testCaseNode = (OMElement) (testCaseIterator.next()); + String testCaseName = testCaseNode.getAttributeValue(new QName(NAME_ATTRIBUTE)); + testCase.setTestCaseName(testCaseName); + + //Read input child from test-case node + QName qualifiedInput = new QName("", TEST_CASE_INPUT, ""); + OMElement testCaseInputNode = testCaseNode.getFirstChildWithName(qualifiedInput); + + //Read input node data of payload and properties if not null + if (testCaseInputNode != null) { + readTestCaseInputData(testCaseInputNode, testCase); + } + + //Read assertions of test-case node + QName qualifiedAssertions = new QName("", TEST_CASE_ASSERTIONS, ""); + OMElement testCaseAssertionNode = testCaseNode.getFirstChildWithName(qualifiedAssertions); + ArrayList assertEquals = new ArrayList(); + ArrayList assertNotNulls = new ArrayList(); + readTestCaseAssertions(testCaseAssertionNode, assertEquals, assertNotNulls); + + //set assertion values in testCase object + testCase.setAssertEquals(assertEquals); + testCase.setAssertNotNull(assertNotNulls); + + //set testCase object in testCase data holder + testCaseDataHolder.setTestCases(testCase); + testCasesCount++; + } + + //Set test case count in test data holder + testCaseDataHolder.setTestCaseCount(testCasesCount); + + log.info("Test case data from descriptor data read successfully"); + return testCaseDataHolder; + } + + /** + * Read test case input data from the descriptor data. + * Read payload and properties if exists + * + * @param testCaseInputNode node of test cases + * @param testCase test case object + */ + private void readTestCaseInputData(OMElement testCaseInputNode, TestCase testCase) { + QName qualifiedInputPayload = new QName("", TEST_CASE_INPUT_PAYLOAD, ""); + OMElement testCaseInputPayloadNode = testCaseInputNode.getFirstChildWithName(qualifiedInputPayload); + + if (testCaseInputPayloadNode != null) { + String inputPayload = testCaseInputPayloadNode.getText(); + testCase.setInputPayload(inputPayload); + } + + QName qualifiedInputRequestPath = new QName("", TEST_CASE_REQUEST_PATH, ""); + OMElement testCaseRequestPathNode = testCaseInputNode.getFirstChildWithName(qualifiedInputRequestPath); + + if (testCaseRequestPathNode != null) { + String requestPath = testCaseRequestPathNode.getText(); + testCase.setRequestPath(requestPath); + } + + QName qualifiedInputRequestMethod = new QName("", TEST_CASE_REQUEST_METHOD, ""); + OMElement testCaseRequestMethodNode = testCaseInputNode.getFirstChildWithName(qualifiedInputRequestMethod); + + if (testCaseRequestMethodNode != null) { + String requestMethod = testCaseRequestMethodNode.getText(); + testCase.setRequestMethod(requestMethod); + } + + + QName qualifiedInputProperties = new QName("", TEST_CASE_INPUT_PROPERTIES, ""); + OMElement testCaseInputPropertyNode = testCaseInputNode.getFirstChildWithName(qualifiedInputProperties); + + if (testCaseInputPropertyNode != null) { + Iterator propertyIterator = testCaseInputPropertyNode.getChildElements(); + + ArrayList> properties = new ArrayList>(); + while (propertyIterator.hasNext()) { + OMElement propertyNode = (OMElement) (propertyIterator.next()); + + String propName = propertyNode.getAttributeValue(new QName(TEST_CASE_INPUT_PROPERTY_NAME)); + String propValue = propertyNode.getAttributeValue(new QName(TEST_CASE_INPUT_PROPERTY_VALUE)); + String propScope = "default"; + + if (propertyNode.getAttributeValue(new QName(TEST_CASE_INPUT_PROPERTY_SCOPE)) != null) { + propScope = propertyNode.getAttributeValue(new QName(TEST_CASE_INPUT_PROPERTY_SCOPE)); + } + + Map propertyMap = new HashMap(); + propertyMap.put(TEST_CASE_INPUT_PROPERTY_NAME, propName); + propertyMap.put(TEST_CASE_INPUT_PROPERTY_VALUE, propValue); + propertyMap.put(TEST_CASE_INPUT_PROPERTY_SCOPE, propScope); + properties.add(propertyMap); + } + + testCase.setPropertyMap(properties); + } + } + + + /** + * Read test case assertion data from the descriptor data. + * Read assertEquals and assertNotNull data if exists + * + * @param testCaseAssertionNode node of test case assertions + * @param assertEquals array of assertEquals + * @param assertNotNulls array of assertNotNulls + */ + private void readTestCaseAssertions(OMElement testCaseAssertionNode, ArrayList assertEquals, + ArrayList assertNotNulls) { + + //Read assertions - AssertEquals of test-case node + Iterator assertEqualsIterator = + testCaseAssertionNode.getChildrenWithName(new QName(TEST_CASE_ASSERTION_EQUALS)); + + while (assertEqualsIterator.hasNext()) { + AssertEqual assertion = new AssertEqual(); + + OMElement assertEqualNode = (OMElement) (assertEqualsIterator.next()); + QName qualifiedAssertActual = new QName("", ASSERTION_ACTUAL, ""); + OMElement assertActualNode = assertEqualNode.getFirstChildWithName(qualifiedAssertActual); + String actual = assertActualNode.getText(); + assertion.setActual(actual); + + QName qualifiedAssertMessage = new QName("", ASSERTION_MESSAGE, ""); + OMElement assertMessageNode = assertEqualNode.getFirstChildWithName(qualifiedAssertMessage); + String message = assertMessageNode.getText(); + assertion.setMessage(message); + + QName qualifiedExpectedMessage = new QName("", ASSERTION_EXPECTED, ""); + OMElement assertExpectedNode = assertEqualNode.getFirstChildWithName(qualifiedExpectedMessage); + String expected = assertExpectedNode.getText(); + assertion.setExpected(expected); + + assertEquals.add(assertion); + } + + //Read assertions - AssertNotNull of test-case node + Iterator assertNotNullIterator = testCaseAssertionNode.getChildrenWithName( + new QName(TEST_CASE_ASSERTION_NOTNULL)); + while (assertNotNullIterator.hasNext()) { + AssertNotNull assertion = new AssertNotNull(); + + OMElement assertEqualNode = (OMElement) (assertNotNullIterator.next()); + QName qualifiedAssertActual = new QName("", ASSERTION_ACTUAL, ""); + OMElement assertActualNode = assertEqualNode.getFirstChildWithName(qualifiedAssertActual); + String actual = assertActualNode.getText(); + assertion.setActual(actual); + + QName qualifiedAssertMessage = new QName("", ASSERTION_MESSAGE, ""); + OMElement assertMessageNode = assertEqualNode.getFirstChildWithName(qualifiedAssertMessage); + String message = assertMessageNode.getText(); + assertion.setMessage(message); + + assertNotNulls.add(assertion); + } + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/TCPServer.java b/modules/core/src/main/java/org/apache/synapse/unittest/TCPServer.java new file mode 100755 index 000000000..eba0b74d9 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/TCPServer.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +import org.apache.log4j.Logger; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * Class is responsible for configurations of TCP connection. + */ +public class TCPServer { + + private static Logger log = Logger.getLogger(UnitTestingExecutor.class.getName()); + + private ServerSocket serverSocket; + private boolean isUnitTestingOver = false; + + /** + * Initializing TCP server for main unit testing server. + */ + public void initialize() { + //check unit test received port, if its null then set default port as 9008 + String requestPort = System.getProperty("synapseTestPort"); + if (requestPort == null || requestPort.isEmpty()) { + requestPort = "9008"; + } + + //check port for TCP server connection and initialized socket + try { + int unitTestingAgentPort = Integer.parseInt(requestPort); + serverSocket = new ServerSocket(unitTestingAgentPort); + log.info("Synapse unit testing agent has been established on port " + unitTestingAgentPort); + if (log.isDebugEnabled()) { + log.debug("Waiting for client request"); + } + + //allow for the client requests + acceptConnection(); + } catch (NumberFormatException e) { + log.error("Given TCP port \"" + requestPort + "\" is not in valid format, " + + "failed to start unit testing framework", e); + } catch (IOException e) { + log.error("Error in initializing TCP connection in given port " + requestPort, e); + } + } + + /** + * Create RequestHandler threads for load balancing. + */ + private void acceptConnection() throws IOException { + //start thread for shutdown hook + shutDown(); + + while (!isUnitTestingOver) { + Socket socket = serverSocket.accept(); + RequestHandler requestHandler = new RequestHandler(socket); + Thread threadForClient = new Thread(requestHandler); + threadForClient.start(); + } + } + + /** + * Shut down unit testing framework + */ + private void shutDown() { + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + log.info("Shutting down unit testing framework"); + isUnitTestingOver = true; + } + }); + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/TestCasesMediator.java b/modules/core/src/main/java/org/apache/synapse/unittest/TestCasesMediator.java new file mode 100755 index 000000000..152b6112d --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/TestCasesMediator.java @@ -0,0 +1,412 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +import org.apache.axiom.om.OMAbstractFactory; +import org.apache.axiom.om.OMDocument; +import org.apache.axiom.om.OMElement; +import org.apache.axiom.soap.SOAPEnvelope; +import org.apache.axis2.context.ConfigurationContext; +import org.apache.axis2.engine.AxisConfiguration; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.log4j.Logger; +import org.apache.synapse.Mediator; +import org.apache.synapse.MessageContext; +import org.apache.synapse.config.SynapseConfigUtils; +import org.apache.synapse.config.SynapseConfiguration; +import org.apache.synapse.core.SynapseEnvironment; +import org.apache.synapse.core.axis2.Axis2MessageContext; +import org.apache.synapse.core.axis2.Axis2SynapseEnvironment; +import org.apache.synapse.unittest.testcase.data.classes.TestCase; + +import java.io.IOException; +import java.util.AbstractMap; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + +import static org.apache.synapse.unittest.Constants.DELETE_METHOD; +import static org.apache.synapse.unittest.Constants.GET_METHOD; +import static org.apache.synapse.unittest.Constants.HTTPS_KEY; +import static org.apache.synapse.unittest.Constants.HTTPS_LOCALHOST_URL; +import static org.apache.synapse.unittest.Constants.HTTP_KEY; +import static org.apache.synapse.unittest.Constants.HTTP_LOCALHOST_URL; +import static org.apache.synapse.unittest.Constants.INPUT_PROPERTY_SCOPE_AXIS2; +import static org.apache.synapse.unittest.Constants.INPUT_PROPERTY_SCOPE_DEFAULT; +import static org.apache.synapse.unittest.Constants.INPUT_PROPERTY_SCOPE_TRANSPORT; +import static org.apache.synapse.unittest.Constants.POST_METHOD; +import static org.apache.synapse.unittest.Constants.PROXY_INVOKE_PREFIX_URL; +import static org.apache.synapse.unittest.Constants.PUT_METHOD; +import static org.apache.synapse.unittest.Constants.TEST_CASE_INPUT_PROPERTY_NAME; +import static org.apache.synapse.unittest.Constants.TEST_CASE_INPUT_PROPERTY_SCOPE; +import static org.apache.synapse.unittest.Constants.TEST_CASE_INPUT_PROPERTY_VALUE; + + +/** + * Class is responsible for mediating incoming payload with relevant configuration. + */ +public class TestCasesMediator { + + private TestCasesMediator() { + } + + private static Logger log = Logger.getLogger(UnitTestingExecutor.class.getName()); + private static int httpPassThruOperatingPort = 8280; + private static int httpsPassThruOperatingPort = 8243; + + /** + * Sequence mediation of receiving test cases using deployed sequence deployer. + * set input properties for the Message Context + * + * @param currentTestCase current test case + * @param synConfig synapse configuration used to deploy sequenceDeployer + * @param key key of the sequence deployer + * @return result of mediation and message context as a Map.Entry + */ + static Map.Entry sequenceMediate(TestCase currentTestCase, SynapseConfiguration synConfig, + String key) { + Mediator sequenceMediator = synConfig.getSequence(key); + MessageContext msgCtxt = createSynapseMessageContext(currentTestCase.getInputPayload(), synConfig); + + boolean mediationResult = false; + + if (msgCtxt != null) { + mediationResult = sequenceMediator + .mediate(setInputMessageProperties(msgCtxt, currentTestCase.getPropertyMap())); + } + + return new AbstractMap.SimpleEntry(mediationResult, msgCtxt); + } + + /** + * Proxy service invoke using http client for receiving test cases. + * + * @param currentTestCase current test case + * @param key key of the proxy service + * @return response received from the proxy service + */ + static HttpResponse proxyServiceExecutor(TestCase currentTestCase, String proxyTransportMethod, String key) + throws IOException { + + String url; + + //check transport port whether http or https + if (proxyTransportMethod.equals(HTTP_KEY)) { + url = HTTP_LOCALHOST_URL + httpPassThruOperatingPort + PROXY_INVOKE_PREFIX_URL + key; + } else if (proxyTransportMethod.equals(HTTPS_KEY)) { + url = HTTPS_LOCALHOST_URL + httpsPassThruOperatingPort + PROXY_INVOKE_PREFIX_URL + key; + } else { + return null; + } + + log.info("Invoking URI - " + url); + + HttpClient clientConnector = HttpClientBuilder.create().build(); + HttpPost httpPost = new HttpPost(url); + + //set headers + for (Map property : currentTestCase.getPropertyMap()) { + String scope = property.get(TEST_CASE_INPUT_PROPERTY_SCOPE); + //Setting Synapse properties + if (scope.equals(INPUT_PROPERTY_SCOPE_TRANSPORT)) { + httpPost.setHeader(property.get(TEST_CASE_INPUT_PROPERTY_NAME), + property.get(TEST_CASE_INPUT_PROPERTY_VALUE)); + } + } + + if (currentTestCase.getInputPayload() != null) { + StringEntity postEntity = new StringEntity(currentTestCase.getInputPayload().trim()); + httpPost.setEntity(postEntity); + } + + HttpResponse response = clientConnector.execute(httpPost); + + int responseCode = response.getStatusLine().getStatusCode(); + if (responseCode / 100 == 2) { + return response; + } else { + return null; + } + } + + /** + * API resource invoke using http client for receiving test cases. + * + * @param currentTestCase current test case + * @param resourceMethod resource method + * @param context context of the resource + * @return response received from the API resource + */ + static HttpResponse apiResourceExecutor(TestCase currentTestCase, String context, String resourceMethod) + throws IOException { + + String url; + if (currentTestCase.getRequestPath() != null) { + if (currentTestCase.getRequestPath().startsWith("/")) { + url = HTTP_LOCALHOST_URL + httpPassThruOperatingPort + + context + currentTestCase.getRequestPath(); + } else { + url = HTTP_LOCALHOST_URL + httpPassThruOperatingPort + + context + "/" + currentTestCase.getRequestPath(); + } + + } else { + url = HTTP_LOCALHOST_URL + httpPassThruOperatingPort + context; + } + + + log.info("Invoking URI - " + url); + + HttpClient clientConnector = HttpClientBuilder.create().build(); + HttpResponse response; + + + if (resourceMethod.toUpperCase(Locale.ENGLISH).equals(GET_METHOD)) { + //set headers and execute + response = clientConnector.execute(setGetHeaders(currentTestCase, url)); + + } else if (resourceMethod.toUpperCase(Locale.ENGLISH).equals(POST_METHOD)) { + //set headers + HttpPost httpPost = setPostHeaders(currentTestCase, url); + String postPayload = currentTestCase.getInputPayload(); + + if (postPayload == null) { + postPayload = ""; + } + + StringEntity postEntity = new StringEntity(postPayload); + httpPost.setEntity(postEntity); + response = clientConnector.execute(httpPost); + + } else if (resourceMethod.toUpperCase(Locale.ENGLISH).equals(PUT_METHOD)) { + //set headers + HttpPut httpPut = setPutHeaders(currentTestCase, url); + + StringEntity putEntity = new StringEntity(currentTestCase.getInputPayload()); + httpPut.setEntity(putEntity); + response = clientConnector.execute(httpPut); + + } else if (resourceMethod.toUpperCase(Locale.ENGLISH).equals(DELETE_METHOD)) { + HttpDelete httpDelete = new HttpDelete(url); + response = clientConnector.execute(httpDelete); + + } else { + throw new ClientProtocolException("HTTP client can't find proper request method"); + } + + int responseCode = response.getStatusLine().getStatusCode(); + if (responseCode / 100 == 2) { + return response; + } else { + return null; + } + } + + + /** + * Set headers for get client. + * + * @param currentTestCase testcase data + * @param url Url of the service + * @return get client with headers + */ + private static HttpGet setGetHeaders(TestCase currentTestCase, String url) { + HttpGet httpGet = new HttpGet(url); + + for (Map property : currentTestCase.getPropertyMap()) { + String scope = property.get(TEST_CASE_INPUT_PROPERTY_SCOPE); + + //Setting Synapse properties + if (scope.equals(INPUT_PROPERTY_SCOPE_TRANSPORT)) { + httpGet.setHeader(property.get(TEST_CASE_INPUT_PROPERTY_NAME), + property.get(TEST_CASE_INPUT_PROPERTY_VALUE)); + } + } + + return httpGet; + } + + /** + * Set headers for post client. + * + * @param currentTestCase testcase data + * @param url Url of the service + * @return post client with headers + */ + private static HttpPost setPostHeaders(TestCase currentTestCase, String url) { + HttpPost httpPost = new HttpPost(url); + //set headers + for (Map property : currentTestCase.getPropertyMap()) { + String scope = property.get(TEST_CASE_INPUT_PROPERTY_SCOPE); + + //Setting Synapse properties + if (scope.equals(INPUT_PROPERTY_SCOPE_TRANSPORT)) { + httpPost.setHeader(property.get(TEST_CASE_INPUT_PROPERTY_NAME), + property.get(TEST_CASE_INPUT_PROPERTY_VALUE)); + } + } + + return httpPost; + } + + /** + * Set headers for put client. + * + * @param currentTestCase testcase data + * @param url Url of the service + * @return put client with headers + */ + private static HttpPut setPutHeaders(TestCase currentTestCase, String url) { + HttpPut httpPut = new HttpPut(url); + //set headers + for (Map property : currentTestCase.getPropertyMap()) { + String scope = property.get(TEST_CASE_INPUT_PROPERTY_SCOPE); + + //Setting Synapse properties + if (scope.equals(INPUT_PROPERTY_SCOPE_TRANSPORT)) { + httpPut.setHeader(property.get(TEST_CASE_INPUT_PROPERTY_NAME), + property.get(TEST_CASE_INPUT_PROPERTY_VALUE)); + } + } + + return httpPut; + } + + /** + * Creating message context using input payload and the synapse configuration. + * + * @param payload received input payload for particular test case + * @param synapseConfig synapse configuration used for deploy the sequence deployer + * @return message context + */ + private static MessageContext createSynapseMessageContext(String payload, SynapseConfiguration synapseConfig) { + + MessageContext synapseMessageContext = null; + try { + org.apache.axis2.context.MessageContext messageContext = + new org.apache.axis2.context.MessageContext(); + AxisConfiguration axisConfig = synapseConfig.getAxisConfiguration(); + if (axisConfig == null) { + axisConfig = new AxisConfiguration(); + synapseConfig.setAxisConfiguration(axisConfig); + } + ConfigurationContext configurationContext = new ConfigurationContext(axisConfig); + SynapseEnvironment env = new Axis2SynapseEnvironment(configurationContext, synapseConfig); + + synapseMessageContext = new Axis2MessageContext(messageContext, synapseConfig, env); + SOAPEnvelope envelope = + OMAbstractFactory.getSOAP11Factory().getDefaultEnvelope(); + OMDocument omDocument = + OMAbstractFactory.getSOAP11Factory().createOMDocument(); + omDocument.addChild(envelope); + + envelope.getBody().addChild(createOMElement(payload)); + + synapseMessageContext.setEnvelope(envelope); + } catch (Exception e) { + log.error("Exception while creating synapse message context", e); + } + + return synapseMessageContext; + } + + /** + * Creating OMElement for payload. + * + * @param xml input payload + * @return payload in OMElement type + */ + public static OMElement createOMElement(String xml) { + return SynapseConfigUtils.stringToOM(xml); + } + + /** + * Set input property values in MessageContext + * + * @param messageContext message context + * @param properties input property values + * @return message context with input properties + */ + private static MessageContext setInputMessageProperties(MessageContext messageContext, + List> properties) { + + try { + for (Map property : properties) { + String scope = property.get(TEST_CASE_INPUT_PROPERTY_SCOPE); + + Axis2MessageContext axis2MessageContext = (Axis2MessageContext) messageContext; + org.apache.axis2.context.MessageContext axis2MessageCtx = + axis2MessageContext.getAxis2MessageContext(); + + //Setting Synapse properties + + if (scope.equals(INPUT_PROPERTY_SCOPE_DEFAULT)) { + messageContext.setProperty(property.get(TEST_CASE_INPUT_PROPERTY_NAME), + property.get(TEST_CASE_INPUT_PROPERTY_VALUE)); + + } else if (scope.equals(INPUT_PROPERTY_SCOPE_AXIS2)) { + //Setting Axis2 properties + axis2MessageCtx.setProperty(property.get(TEST_CASE_INPUT_PROPERTY_NAME), + property.get(TEST_CASE_INPUT_PROPERTY_VALUE)); + + } else if (scope.equals(INPUT_PROPERTY_SCOPE_TRANSPORT)) { + //Setting Transport Headers + Object headers = axis2MessageContext.getProperty( + org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS); + + if (headers != null) { + @SuppressWarnings("unchecked") + Map headersMap = (Map) headers; + headersMap.put(property.get(TEST_CASE_INPUT_PROPERTY_NAME), + property.get(TEST_CASE_INPUT_PROPERTY_VALUE)); + } + if (headers == null) { + Map headersMap = new TreeMap(new Comparator() { + public int compare(String o1, String o2) { + return o1.compareToIgnoreCase(o2); + } + }); + headersMap.put(property.get(TEST_CASE_INPUT_PROPERTY_NAME), + property.get(TEST_CASE_INPUT_PROPERTY_VALUE)); + axis2MessageContext.setProperty( + org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS, + headersMap); + } + } else { + throw new IOException("Property scope not defined for sequences"); + } + } + } catch (Exception e) { + log.error("Error while setting properties to the Message Context", e); + } + + return messageContext; + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/TestingAgent.java b/modules/core/src/main/java/org/apache/synapse/unittest/TestingAgent.java new file mode 100755 index 000000000..9a5f83a14 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/TestingAgent.java @@ -0,0 +1,425 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +import org.apache.axiom.om.OMElement; +import org.apache.axis2.AxisFault; +import org.apache.axis2.context.ConfigurationContext; +import org.apache.axis2.description.Parameter; +import org.apache.axis2.engine.AxisConfiguration; +import org.apache.http.HttpResponse; +import org.apache.log4j.Logger; +import org.apache.synapse.MessageContext; +import org.apache.synapse.SynapseConstants; +import org.apache.synapse.config.SynapseConfiguration; +import org.apache.synapse.core.SynapseEnvironment; +import org.apache.synapse.core.axis2.Axis2SynapseEnvironment; +import org.apache.synapse.deployers.APIDeployer; +import org.apache.synapse.deployers.EndpointDeployer; +import org.apache.synapse.deployers.LocalEntryDeployer; +import org.apache.synapse.deployers.ProxyServiceDeployer; +import org.apache.synapse.deployers.SequenceDeployer; +import org.apache.synapse.unittest.testcase.data.classes.SynapseTestCase; +import org.apache.synapse.unittest.testcase.data.classes.TestCase; +import org.apache.synapse.unittest.testcase.data.classes.TestCaseSummary; +import org.apache.synapse.unittest.testcase.data.classes.TestSuiteSummary; + +import javax.xml.namespace.QName; +import java.io.IOException; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.Map; + +import static org.apache.synapse.unittest.Constants.API_CONTEXT; +import static org.apache.synapse.unittest.Constants.TYPE_API; +import static org.apache.synapse.unittest.Constants.TYPE_ENDPOINT; +import static org.apache.synapse.unittest.Constants.TYPE_LOCAL_ENTRY; +import static org.apache.synapse.unittest.Constants.TYPE_PROXY; +import static org.apache.synapse.unittest.Constants.TYPE_SEQUENCE; + + +/** + * Testing agent deploy receiving artifact data in relevant deployer and mediate test cases on it. + * Returns the results of artifact deployment and test case mediation to the RequestHandler + */ +class TestingAgent { + + private Logger log = Logger.getLogger(TestingAgent.class.getName()); + private SynapseConfiguration synapseConfiguration = new SynapseConfiguration(); + private String artifactType = null; + private String proxyTransportMethod = null; + private String key = null; + private OMElement artifactNode = null; + private String exception = null; + private Map deploymentStats = new HashMap(); + + /** + * Check artifact type and pass the test-artifact data to the relevant deployment mechanism. + * + * @param synapseTestCase test cases data received from client + * @return Result of the deployment and exception status + */ + Map.Entry processTestArtifact(SynapseTestCase synapseTestCase, TestSuiteSummary testSuiteSummary) { + artifactType = synapseTestCase.getArtifacts().getTestArtifact().getArtifactType(); + proxyTransportMethod = synapseTestCase.getArtifacts().getTestArtifact().getTransportMethod(); + String artifactNameOrKey = synapseTestCase.getArtifacts().getTestArtifact().getArtifactNameOrKey(); + OMElement artifact = synapseTestCase.getArtifacts().getTestArtifact().getArtifact(); + boolean isArtifactDeployed = false; + ConfigurationDeployer config = new ConfigurationDeployer(); + + try { + //check artifact type and pass the artifact to the relevant deployment + + if (artifactType.equals(TYPE_SEQUENCE)) { + Map.Entry pairOfSequenceDeployment = + config.deploySequenceArtifact(artifact, artifactNameOrKey); + synapseConfiguration = pairOfSequenceDeployment.getKey(); + key = pairOfSequenceDeployment.getValue(); + + if (key.equals(artifactNameOrKey)) { + isArtifactDeployed = true; + deploymentStats.put(artifactNameOrKey, TYPE_SEQUENCE); + testSuiteSummary.setDeploymentStatus(Constants.PASSED_KEY); + log.info("Sequence artifact deployed successfully"); + } else { + String errorMessage = "Sequence " + artifactNameOrKey + " deployment failed"; + log.error(errorMessage); + testSuiteSummary.setDeploymentStatus(Constants.FAILED_KEY); + testSuiteSummary.setDeploymentException(errorMessage); + } + + } else if (artifactType.equals(TYPE_PROXY)) { + Map.Entry pairOfProxyDeployment = + config.deployProxyArtifact(artifact, artifactNameOrKey); + synapseConfiguration = pairOfProxyDeployment.getKey(); + key = pairOfProxyDeployment.getValue(); + + if (key.equals(artifactNameOrKey)) { + isArtifactDeployed = true; + deploymentStats.put(artifactNameOrKey, TYPE_PROXY); + testSuiteSummary.setDeploymentStatus(Constants.PASSED_KEY); + log.info("Proxy artifact deployed successfully"); + } else { + String errorMessage = "Proxy " + artifactNameOrKey + " deployment failed"; + log.error(errorMessage); + testSuiteSummary.setDeploymentStatus(Constants.FAILED_KEY); + testSuiteSummary.setDeploymentException(errorMessage); + } + + } else if (artifactType.equals(TYPE_API)) { + Map.Entry pairofApiDeployment = + config.deployApiArtifact(artifact, artifactNameOrKey); + synapseConfiguration = pairofApiDeployment.getKey(); + key = pairofApiDeployment.getValue(); + artifactNode = artifact; + + if (key.equals(artifactNameOrKey)) { + isArtifactDeployed = true; + deploymentStats.put(artifactNameOrKey, TYPE_API); + testSuiteSummary.setDeploymentStatus(Constants.PASSED_KEY); + log.info("API artifact deployed successfully"); + } else { + String errorMessage = "API " + artifactNameOrKey + " deployment failed"; + log.error(errorMessage); + testSuiteSummary.setDeploymentStatus(Constants.FAILED_KEY); + testSuiteSummary.setDeploymentException(errorMessage); + } + + } else { + throw new IOException("Undefined operation type for given in unit testing agent"); + } + } catch (Exception e) { + log.error("Artifact deployment failed", e); + exception = CommonUtils.stackTraceToString(e); + testSuiteSummary.setDeploymentStatus(Constants.FAILED_KEY); + testSuiteSummary.setDeploymentException(exception); + } + + return new AbstractMap.SimpleEntry(isArtifactDeployed, testSuiteSummary); + } + + /** + * Check artifact type and pass the supportive-artifact data to the relevant deployment mechanism. + * + * @param synapseTestCase test cases data received from client + * @return Result of the deployment and exception status + */ + Map.Entry processSupportiveArtifacts(SynapseTestCase synapseTestCase, + TestSuiteSummary testSuiteSummary) { + boolean isArtifactDeployed = true; + + for (int x = 0; x < synapseTestCase.getArtifacts().getSupportiveArtifactCount(); x++) { + if (isArtifactDeployed) { + try { + //check artifact type and pass the artifact to the relevant deployment + isArtifactDeployed = processForArtifactTypes(synapseTestCase, x); + + } catch (Exception e) { + log.error("Artifact deployment failed", e); + exception = CommonUtils.stackTraceToString(e); + testSuiteSummary.setDeploymentStatus(Constants.FAILED_KEY); + testSuiteSummary.setDeploymentException(exception); + } + } else { + log.error(synapseTestCase.getArtifacts().getSupportiveArtifact(x).getArtifactType() + + " artifact deployment failed"); + break; + } + } + + return new AbstractMap.SimpleEntry(isArtifactDeployed, testSuiteSummary); + } + + /** + * Check artifact type and pass the supportive-artifact data to the relevant deployment mechanism. + * + * @param synapseTestCase test cases data received from client + * @param index index of supportive artifact + * @return true if supportive artifact deployed else return false + */ + private boolean processForArtifactTypes(SynapseTestCase synapseTestCase, int index) throws IOException { + + String supportiveArtifactType = synapseTestCase.getArtifacts().getSupportiveArtifact(index).getArtifactType(); + String artifactNameOrKey = synapseTestCase.getArtifacts().getSupportiveArtifact(index).getArtifactNameOrKey(); + OMElement artifact = synapseTestCase.getArtifacts().getSupportiveArtifact(index).getArtifact(); + ConfigurationDeployer config = new ConfigurationDeployer(); + + if (supportiveArtifactType.equals(TYPE_SEQUENCE)) { + Map.Entry pairOfSequenceDeployment = + config.deploySequenceArtifact(artifact, artifactNameOrKey); + synapseConfiguration = pairOfSequenceDeployment.getKey(); + key = pairOfSequenceDeployment.getValue(); + + } else if (supportiveArtifactType.equals(TYPE_PROXY)) { + Map.Entry pairofProxyDeployment = + config.deployProxyArtifact(artifact, artifactNameOrKey); + synapseConfiguration = pairofProxyDeployment.getKey(); + key = pairofProxyDeployment.getValue(); + + } else if (supportiveArtifactType.equals(TYPE_API)) { + Map.Entry pairofApiDeployment = + config.deployApiArtifact(artifact, artifactNameOrKey); + synapseConfiguration = pairofApiDeployment.getKey(); + key = pairofApiDeployment.getValue(); + + } else if (supportiveArtifactType.equals(TYPE_ENDPOINT)) { + Map.Entry pairOfEndpointDeployment = + config.deployEndpointArtifact(artifact, artifactNameOrKey); + synapseConfiguration = pairOfEndpointDeployment.getKey(); + key = pairOfEndpointDeployment.getValue(); + + } else if (supportiveArtifactType.equals(TYPE_LOCAL_ENTRY)) { + Map.Entry pairOfLocalEntryDeployment = + config.deployLocalEntryArtifact(artifact, artifactNameOrKey); + synapseConfiguration = pairOfLocalEntryDeployment.getKey(); + key = pairOfLocalEntryDeployment.getValue(); + + } else { + throw new IOException("Undefined operation type for given in unit testing agent"); + } + + if (key.equals(artifactNameOrKey)) { + log.info(artifactNameOrKey + " - " + supportiveArtifactType + " artifact deployed successfully"); + deploymentStats.put(artifactNameOrKey, supportiveArtifactType); + return true; + + } else { + return false; + } + } + + /** + * Check artifact type and pass the test case data to the relevant mediation. + * + * @param synapseTestCase test cases data received from client + */ + void processTestCases(SynapseTestCase synapseTestCase, TestSuiteSummary testSuiteSummary) { + int testCaseCount = synapseTestCase.getTestCases().getTestCaseCount(); + log.info(testCaseCount + " Test case(s) ready to execute"); + String currentTestCaseName = null; + + try { + //execute test cases with synapse configurations and test data + for (int i = 0; i < testCaseCount; i++) { + TestCaseSummary testSummary = new TestCaseSummary(); + TestCase currentTestCase = synapseTestCase.getTestCases().getTestCase(i); + testSummary.setTestCaseName(currentTestCase.getTestCaseName()); + testSuiteSummary.setRecentTestCaseName(currentTestCaseName); + currentTestCaseName = currentTestCase.getTestCaseName(); + + if (artifactType.equals(TYPE_SEQUENCE)) { + Map.Entry mediateResult = + TestCasesMediator.sequenceMediate(currentTestCase, synapseConfiguration, key); + + testSuiteSummary.setMediationStatus(Constants.PASSED_KEY); + Boolean mediationResult = mediateResult.getKey(); + MessageContext resultedMessageContext = mediateResult.getValue(); + + //check whether mediation is success or not + checkAssertionWithSequenceMediation + (mediationResult, resultedMessageContext, currentTestCase, i, testSummary); + + } else if (artifactType.equals(TYPE_PROXY)) { + HttpResponse invokedProxyResult = TestCasesMediator + .proxyServiceExecutor(currentTestCase, proxyTransportMethod, key); + + testSuiteSummary.setMediationStatus(Constants.PASSED_KEY); + checkAssertionWithProxyMediation(invokedProxyResult, currentTestCase, i, testSummary); + + } else if (artifactType.equals(TYPE_API)) { + String context = artifactNode.getAttributeValue(new QName(API_CONTEXT)); + String resourceMethod = currentTestCase.getRequestMethod(); + HttpResponse invokedApiResult = TestCasesMediator.apiResourceExecutor + (currentTestCase, context, resourceMethod); + + testSuiteSummary.setMediationStatus(Constants.PASSED_KEY); + checkAssertionWithAPIMediation(invokedApiResult, currentTestCase, i, testSummary); + } + + testSuiteSummary.addTestCaseSumamry(testSummary); + } + } catch (Exception e) { + log.error("Error occurred while running test cases", e); + exception = CommonUtils.stackTraceToString(e); + testSuiteSummary.setRecentTestCaseName(currentTestCaseName); + testSuiteSummary.setMediationStatus(Constants.FAILED_KEY); + testSuiteSummary.setMediationException(exception); + } + } + + /** + * Check assertion results with results of sequence mediation. + * + * @param mediationResult result of mediation of sequence + * @param resultedMessageContext message context of mediation of sequence + * @param currentTestCase current running test case data + */ + private void checkAssertionWithSequenceMediation( + boolean mediationResult, MessageContext resultedMessageContext, TestCase currentTestCase, + int index, TestCaseSummary testSummary) { + String assertMessage; + if (mediationResult) { + testSummary.setMediationStatus(Constants.PASSED_KEY); + Assertor.doAssertionSequence(currentTestCase, resultedMessageContext, index + 1, testSummary); + } else { + assertMessage = "Sequence mediation failed"; + log.error(assertMessage); + testSummary.setMediationStatus(Constants.FAILED_KEY); + testSummary.setTestException(assertMessage); + } + } + + /** + * Check assertion results with results of sequence mediation. + * + * @param invokedProxyResult result of proxy invoke + * @param currentTestCase current running test case data + */ + private void checkAssertionWithProxyMediation(HttpResponse invokedProxyResult, + TestCase currentTestCase, int index, + TestCaseSummary testSummary) { + + String assertMessage; + if (invokedProxyResult != null) { + testSummary.setMediationStatus(Constants.PASSED_KEY); + Assertor.doAssertionService + (currentTestCase, invokedProxyResult, index + 1, testSummary); + } else { + assertMessage = "Proxy service invoke failed"; + log.error(assertMessage); + testSummary.setMediationStatus(Constants.FAILED_KEY); + testSummary.setTestException(assertMessage); + } + } + + /** + * Check assertion results with results of sequence mediation. + * + * @param invokedApiResult result of API invoke + * @param currentTestCase current running test case data + */ + private void checkAssertionWithAPIMediation(HttpResponse invokedApiResult, + TestCase currentTestCase, int index, + TestCaseSummary testSummary) { + String assertMessage; + if (invokedApiResult != null) { + testSummary.setMediationStatus(Constants.PASSED_KEY); + Assertor.doAssertionService + (currentTestCase, invokedApiResult, index + 1, testSummary); + } else { + assertMessage = "API resource invoke failed"; + log.error(assertMessage); + testSummary.setMediationStatus(Constants.FAILED_KEY); + testSummary.setTestException(assertMessage); + } + } + + /** + * Undeploy all the artifacts used in the recent unit test. + */ + void artifactUndeployer() { + try { + //create a synapse configuration and set all axis2 configuration to it + SynapseConfiguration synapseConfig = UnitTestingExecutor.getExecuteInstance().getSynapseConfiguration(); + AxisConfiguration axisConfiguration = synapseConfig.getAxisConfiguration(); + ConfigurationContext configurationContext = new ConfigurationContext(axisConfiguration); + SynapseEnvironment synapseEnvironment = new Axis2SynapseEnvironment(configurationContext, synapseConfig); + + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_ENV, synapseEnvironment)); + axisConfiguration.addParameter(new Parameter(SynapseConstants.SYNAPSE_CONFIG, synapseConfig)); + configurationContext.setAxisConfiguration(axisConfiguration); + + for (Map.Entry unDeployEntry : deploymentStats.entrySet()) { + String artifactName = unDeployEntry.getKey(); + String unDeployableArtifactType = unDeployEntry.getValue(); + + if (unDeployableArtifactType.equals(TYPE_SEQUENCE)) { + SequenceDeployer sequenceDeployer = new SequenceDeployer(); + sequenceDeployer.init(configurationContext); + sequenceDeployer.undeploySynapseArtifact(artifactName); + + } else if (unDeployableArtifactType.equals(TYPE_PROXY)) { + ProxyServiceDeployer proxyDeployer = new ProxyServiceDeployer(); + proxyDeployer.init(configurationContext); + proxyDeployer.undeploySynapseArtifact(artifactName); + + } else if (unDeployableArtifactType.equals(TYPE_API)) { + APIDeployer apiDeployer = new APIDeployer(); + apiDeployer.init(configurationContext); + apiDeployer.undeploySynapseArtifact(artifactName); + + } else if (unDeployableArtifactType.equals(TYPE_ENDPOINT)) { + EndpointDeployer endpointDeployer = new EndpointDeployer(); + endpointDeployer.init(configurationContext); + endpointDeployer.undeploySynapseArtifact(artifactName); + + } else if (unDeployableArtifactType.equals(TYPE_LOCAL_ENTRY)) { + LocalEntryDeployer localEntryDeployer = new LocalEntryDeployer(); + localEntryDeployer.init(configurationContext); + localEntryDeployer.undeploySynapseArtifact(artifactName); + } + } + log.info("Undeployed all the deployed test and supportive artifacts"); + + } catch (AxisFault e) { + log.error("Error while undeploying the artifacts", e); + } + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/UnitTestingExecutor.java b/modules/core/src/main/java/org/apache/synapse/unittest/UnitTestingExecutor.java new file mode 100755 index 000000000..e576e582a --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/UnitTestingExecutor.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest; + +import org.apache.log4j.Logger; +import org.apache.synapse.config.SynapseConfiguration; + +/** + * Class of executing unit test agent parallel to the Synapse engine. + * Class extends with Thread class + */ +public class UnitTestingExecutor extends Thread { + + private static Logger log = Logger.getLogger(UnitTestingExecutor.class.getName()); + private SynapseConfiguration synapseConfiguration; + private static UnitTestingExecutor initializeThread = new UnitTestingExecutor(); + + /** + * Return initialized UnitTestingExecutor initializeThread object. + */ + public static synchronized UnitTestingExecutor getExecuteInstance() { + return initializeThread; + } + + /** + * Method of executing thread of agent. + */ + @Override + public void run() { + log.info("Unit testing agent started"); + TCPServer tcpConnection = new TCPServer(); + tcpConnection.initialize(); + } + + /** + * get the current SynapseConfiguration. + * + * @return SynapseConfiguration + */ + public SynapseConfiguration getSynapseConfiguration() { + + return this.synapseConfiguration; + } + + /** + * set the current SynapseConfiguration. + * + * @param synapseConfiguration synapse configuration + */ + public void setSynapseConfiguration(SynapseConfiguration synapseConfiguration) { + + this.synapseConfiguration = synapseConfiguration; + + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/docs/README.md b/modules/core/src/main/java/org/apache/synapse/unittest/docs/README.md new file mode 100755 index 000000000..8f6b5b0e4 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/docs/README.md @@ -0,0 +1,247 @@ +## Sample Test Cases +Each request needs to be send to the unit testing server via a TCP transport (user defined port or default 9008 port). + +### Sample test case for sequence artifact + +Client request via TCP: +``` + + + + + + + + + + + SUN + + + + + + + + + + + + + + + + + + + WSO2 + + + + + ]]> + + + + + + + + + + + + $body + + + + + + + WSO2 + SUN + + + + + ]]> + + Expected payload not found + + + + $body + Payload is not available + + + + + $ctx:prop1 + prop1 not found + + + + $ctx:prop1 + val1 + Expected property value not found + + + + $axis2:prop2 + val2 + Expected property value not found + + + + $trp:prop3 + val3 + Expected property value not found + + + + + +``` + +Response from unit testing server: +``` +{'test-cases':'SUCCESS'} +``` + +### Sample test case for proxy artifact + +Client request via TCP: +``` + + + + + + + + + + + {"Hello":"World"} + + + + + + + + + + + + + + + + + + $body + {"Hello":"World"} + Failed the body assertion + + + + $body + Failed the body assertion (not null) + + + + + +``` +Response from unit testing server: +``` +{'test-cases':'SUCCESS'} +``` +### Sample test case for API artifact + +Client request via TCP: +``` + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + / + GET + + + + $body + + {"fname":"Peter","lname":"Stallone", "age":22,"address":{"line":"20 Palm Grove","city":"Colombo 03","country":"Sri Lanka"}} + + Failed the body assertion + + + + $body + Failed the body assertion (not null) + + + + + + + + + Hospital + 9190 + /hello/sayHello + + + / + GET + + + {"fname":"Peter", "lname":"Stallone", "age":22, "address":{"line":"20 Palm Grove", "city":"Colombo 03", "country":"Sri Lanka"}} + + + + + + + +``` + +Response from unit testing server: +``` +{'test-cases':'SUCCESS'} +``` diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/docs/SynapseUnitTestDoc.md b/modules/core/src/main/java/org/apache/synapse/unittest/docs/SynapseUnitTestDoc.md new file mode 100644 index 000000000..fa1d6bd37 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/docs/SynapseUnitTestDoc.md @@ -0,0 +1,375 @@ +# Synapse Unit Testing Framework +Unit testing framework for synapse provides an in-built way to execute a unit test against a given synapse configuration artifacts such as sequence, proxy, api, local entry, endpoint. Mainly it required a test artifact which is your main configuration, supportive artifacts which needs to execute the test artifact if exists and test cases with assertions. + +### Features +- Support deploy sequence, proxy, API, endpoint and local-entry artifacts +- Able to run multiple test cases against a test artifact and supportive artifacts +- Able to create, start and stop mock-services with multiple resources +- Assertion with `AssertEquals` and `AssertNotNull` properties +- Assertion for response body(`$body`), message context property(`$ctx`), axis2 property(`$axis2`) and transport property(`$trp`) values + +### Running Unit Testing Framework + +You can use the following command depending on the platform to start the unit testing framework in the Apache Synapse. +- MacOS/Linux/CentOS - `sh /bin/synapse.sh -DsynapseTest` +- Windows - `/bin/synapse.bat -DsynapseTest` + +By default the unit testing framework starts on port 9008 and you can change the starting port by passing the ```-DsynapseTestPort=``` property with above command. + +### Stopping Unit Testing Framework +To stop the Unit Testing Framework runtime, press Ctrl+C in the command window and it will stop the server along with the Apache Synapse runtime. + +### How To Send a TCP Request + +You can use following code segment to send a sample test case to the unit testing framework and get the server response. +```java +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class TCPClient { + + private static Socket clientSocket; + + public static void main(String args[]) { + try (Stream lines = Files.lines(Paths.get("configuration.xml"))) { + //Read data from test-case xml file + String messageToBeSent = lines.collect(Collectors.joining(System.lineSeparator()));; + clientSocket = new Socket("", ); + OutputStream outputStream; + + //Send the message to the server + outputStream = clientSocket.getOutputStream(); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); + objectOutputStream.writeObject(messageToBeSent); + outputStream.flush(); + + //Get the return message from the server + InputStream inputStream = clientSocket.getInputStream(); + ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); + String response = (String) objectInputStream.readObject(); + System.out.println("Message received from the server : " + response); + + } catch (Exception exception) { + exception.printStackTrace(); + } finally { + //Closing the socket + try { + clientSocket.close(); + } catch(Exception e) { + e.printStackTrace(); + } + } + } +} +``` + +## Sample Test Cases +Each request needs to be sent to the unit testing server via a TCP transport (user defined port or default 9008 port). + +### Sample Test Case for Sequence Artifact + +Client request via TCP: +```xml + + + + + + + + + + + SUN + + + + + + + + + + + + + + + + + + + WSO2 + + + + + ]]> + + + + + + + + + + + + $body + + + + + + + WSO2 + SUN + + + + + ]]> + + Expected payload not found + + + + $body + Payload is not available + + + + + $ctx:prop1 + prop1 not found + + + + $ctx:prop1 + val1 + Expected property value not found + + + + $axis2:prop2 + val2 + Expected property value not found + + + + $trp:prop3 + val3 + Expected property value not found + + + + + +``` + +Response from unit testing server: +``` +{"deploymentStatus":"PASSED","deploymentException":null,"deploymentDescription":null,"mediationStatus":"PASSED","currentTestCase":null,"mediationException":null,"testCases":[{"testCaseName":"test","mediationStatus":"PASSED","assertionStatus":"PASSED","exception":null}]} +``` + +### Sample Test Case for Proxy Artifact + +Client request via TCP: +```xml + + + + + + + + + + + {"Hello":"World"} + + + + + + + + + + + + + + + + + + $body + {"Hello":"World"} + Failed the body assertion + + + + $body + Failed the body assertion (not null) + + + + + +``` +Response from unit testing server: +``` +{"deploymentStatus":"PASSED","deploymentException":null,"deploymentDescription":null,"mediationStatus":"PASSED","currentTestCase":null,"mediationException":null,"testCases":[{"testCaseName":"test","mediationStatus":"PASSED","assertionStatus":"PASSED","exception":null}]} +``` +### Sample Test Case for API Artifact + +Client request via TCP: +```xml + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + / + GET + + + + $body + + {"fname":"Peter","lname":"Stallone", "age":22,"address":{"line":"20 Palm Grove","city":"Colombo 03","country":"Sri Lanka"}} + + Failed the body assertion + + + + $body + Failed the body assertion (not null) + + + + + + + + + Hospital + 9190 + /hello/sayHello + + + / + GET + + + {"fname":"Peter", "lname":"Stallone", "age":22, "address":{"line":"20 Palm Grove", "city":"Colombo 03", "country":"Sri Lanka"}} + + + + + + + +``` + +Response from unit testing server: +``` +{"deploymentStatus":"PASSED","deploymentException":null,"deploymentDescription":null,"mediationStatus":"PASSED","currentTestCase":null,"mediationException":null,"testCases":[{"testCaseName":"test","mediationStatus":"PASSED","assertionStatus":"PASSED","exception":null}]} +``` + +## Sample Failing Test Cases + +If a unit test failed while reading input data, artifact deployment, mock-service creation, test case mediation or assertion, framework responses the error message to the client as follows. + +``` +{"":"failed","exception":""} +``` + +Following is an example of a custom error message sent by the unit testing framework due to un-matching actual payload and expected payload. + +Client request via TCP: +```xml + + + + + + + + + + + {"Hello":"World"} + + + + + + + + + + + + + + + + + + $body + {"Hello":"Worlds"} + Failed the Hello World body assertion + + + + + +``` + +Response from unit testing server: +``` +{"deploymentStatus":"PASSED","deploymentException":null,"deploymentDescription":null,"mediationStatus":"PASSED","currentTestCase":null,"mediationException":null,"testCases":[{"testCaseName":"test","mediationStatus":"PASSED","assertionStatus":"FAILED","exception":"Failed the Hello World body assertion"}]} +``` \ No newline at end of file diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/Artifact.java b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/Artifact.java new file mode 100755 index 000000000..5462af71a --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/Artifact.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest.testcase.data.classes; + +import org.apache.axiom.om.OMElement; +import org.apache.axiom.om.util.AXIOMUtil; + +import javax.xml.stream.XMLStreamException; + +public class Artifact { + + private String artifactType; + private OMElement artifactData; + private String artifactNameOrKey; + private String transportMethod; + + /** + * Get artifact type. + * + * @return artifact type in descriptor data + */ + public String getArtifactType() { + return artifactType; + } + + /** + * Get artifact. + * + * @return artifact in descriptor data + */ + public OMElement getArtifact() { + return artifactData; + } + + /** + * Get artifact name or key. + * + * @return artifact name in descriptor data + */ + public String getArtifactNameOrKey() { + return artifactNameOrKey; + } + + /** + * Get artifact transport method. + * + * @return artifact transport method in descriptor data + */ + public String getTransportMethod() { + return transportMethod; + } + + /** + * Set test-artifact type. + * + * @param artifactType type of the artifact in descriptor data + */ + public void setArtifactType(String artifactType) { + this.artifactType = artifactType; + } + + /** + * Set test-artifact. + * + * @param artifact receiving artifact in descriptor data + */ + public void setArtifact(String artifact) throws XMLStreamException { + this.artifactData = AXIOMUtil.stringToOM(artifact); + } + + /** + * Set test-artifact name or key. + * + * @param artifactNameOrKey name of the artifact in descriptor data + */ + public void setArtifactNameOrKey(String artifactNameOrKey) { + this.artifactNameOrKey = artifactNameOrKey; + } + + /** + * Set test-artifact transport method. + * + * @param transportMethod transport method of the artifact in descriptor data + */ + public void setTransportMethod(String transportMethod) { + this.transportMethod = transportMethod; + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/AssertEqual.java b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/AssertEqual.java new file mode 100755 index 000000000..2a130f439 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/AssertEqual.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest.testcase.data.classes; + +/** + * Class responsible for manage assertEqual data. + */ +public class AssertEqual { + + private String actual; + private String expected; + private String message; + + /** + * Get actual value of assertion. + * + * @return actual value + */ + public String getActual() { + return actual; + } + + /** + * Get expected value of assertion. + * + * @return expected value + */ + public String getExpected() { + return expected; + } + + /** + * Get message of assertion. + * + * @return message + */ + public String getMessage() { + return message; + } + + /** + * Set actual value of assertion. + * + * @param actual value + */ + public void setActual(String actual) { + this.actual = actual; + } + + /** + * Get expected value of assertion. + * + * @param expected value + */ + public void setExpected(String expected) { + this.expected = expected; + } + + /** + * Get message of assertion. + * + * @param message message of assert + */ + public void setMessage(String message) { + this.message = message; + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/AssertNotNull.java b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/AssertNotNull.java new file mode 100755 index 000000000..160fa1953 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/AssertNotNull.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest.testcase.data.classes; + +/** + * Class responsible for manage assertNotNull data. + * + */ +public class AssertNotNull { + + private String actual; + private String message; + + /** + * Get assert actual value. + * + * @return actual value of assert + */ + public String getActual() { + return actual; + } + + /** + * Get assert message. + * + * @return actual value of assert + */ + public String getMessage() { + return message; + } + + /** + * Set assert actual value. + * + * @param actual value of assert + */ + public void setActual(String actual) { + this.actual = actual; + } + + /** + * Set message value. + * + * @param message value of message + */ + public void setMessage(String message) { + this.message = message; + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/SynapseTestCase.java b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/SynapseTestCase.java new file mode 100755 index 000000000..7eb504119 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/SynapseTestCase.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest.testcase.data.classes; + +import org.apache.synapse.unittest.testcase.data.holders.ArtifactData; +import org.apache.synapse.unittest.testcase.data.holders.TestCaseData; + +/** + * Class responsible for holding artifact, test case and mock services data. + * + */ +public class SynapseTestCase { + + private ArtifactData artifacts; + private TestCaseData testCases; + + /** + * Get artifact data holder. + * + * @return artifact data holder + */ + public ArtifactData getArtifacts() { + return artifacts; + } + + /** + * Get test case data holder. + * + * @return test case data holder + */ + public TestCaseData getTestCases() { + return testCases; + } + + /** + * Set artifact data holder. + * + * @param artifacts artifact data holder + */ + public void setArtifacts(ArtifactData artifacts) { + this.artifacts = artifacts; + } + + /** + * Set test case data holder. + * + * @param testCases test case data holder + */ + public void setTestCases(TestCaseData testCases) { + this.testCases = testCases; + } + +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestCase.java b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestCase.java new file mode 100755 index 000000000..5cca0b373 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestCase.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest.testcase.data.classes; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class TestCase { + private String testCaseName; + private String requestPath; + private String requestMethod; + private String inputPayload; + private List> propertyMap = new ArrayList>(); + private List assertEquals = new ArrayList(); + private List assertNotNull = new ArrayList(); + + /** + * Get name of the test case. + * + * @return name of the requested test case + */ + public String getTestCaseName() { + return testCaseName; + } + + /** + * Get input payload of particular test case. + * + * @return input payload of requested test case + */ + public String getInputPayload() { + return inputPayload; + } + + /** + * Get input property values of particular test case. + * + * @return expected property values of requested test case + */ + public List> getPropertyMap() { + return propertyMap; + } + + /** + * Get assert equals set of particular test case. + * + * @return assert equals set of requested test case + */ + public List getAssertEquals() { + return assertEquals; + } + + /** + * Get assert not null set of particular test case. + * + * @return assert not null set of requested test case + */ + public List getAssertNotNull() { + return assertNotNull; + } + + /** + * Get request path of particular test case. + * + * @return request path of requested test case + */ + public String getRequestPath() { + return requestPath; + } + + /** + * Get request method of particular test case. + * + * @return request method of requested test case + */ + public String getRequestMethod() { + return requestMethod; + } + + /** + * Add input payload into a ArrayList. + * + * @param inputPayload input payload of a particular test case + */ + public void setInputPayload(String inputPayload) { + this.inputPayload = inputPayload; + } + + /** + * Add input property values into a ArrayList. + * + * @param propertyMap input property values of a particular test case + */ + public void setPropertyMap(List> propertyMap) { + this.propertyMap = propertyMap; + } + + /** + * Add assertEquals set into a ArrayList. + * + * @param assertEquals assertEquals set of a particular test case + */ + public void setAssertEquals(List assertEquals) { + this.assertEquals = assertEquals; + } + + /** + * Add assertNotNull set into a ArrayList. + * + * @param assertNotNull assertNotNull set of a particular test case + */ + public void setAssertNotNull(List assertNotNull) { + this.assertNotNull = assertNotNull; + } + + /** + * Add requestPath. + * + * @param requestPath requestPath of a particular test case + */ + public void setRequestPath(String requestPath) { + this.requestPath = requestPath; + } + + /** + * Add requestMethod. + * + * @param requestMethod requestMethod of a particular test case + */ + public void setRequestMethod(String requestMethod) { + this.requestMethod = requestMethod; + } + + /** + * Set test case name. + * + * @param testCaseName name of the particular test case + */ + public void setTestCaseName(String testCaseName) { + this.testCaseName = testCaseName; + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestCaseSummary.java b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestCaseSummary.java new file mode 100644 index 000000000..9734f9195 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestCaseSummary.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest.testcase.data.classes; + +public class TestCaseSummary { + + private static final String SKIPPED_STATE = "SKIPPED"; + private static final String FAILED_STATE = "FAILED"; + private String testCaseName; + private String exception; + private String mediationStatus = SKIPPED_STATE; + private String assertionStatus = SKIPPED_STATE; + + /** + * Get failure exception. + * + * @return failure exception + */ + public String getTestException() { + return exception; + } + + /** + * Get test case mediation status. + * + * @return test cases mediation status + */ + public String getMediationStatus() { + return mediationStatus; + } + + /** + * Get test case assertion status. + * + * @return test cases assertion status + */ + public String getAssertionStatus() { + return assertionStatus; + } + + /** + * Get test case name. + * + * @return test cases name + */ + public String getTestCaseName() { + return testCaseName; + } + + /** + * Set test case failure exception. + * + * @param exception test case exception + */ + public void setTestException(String exception) { + this.exception = exception; + } + + /** + * Set test case mediation status. + * + * @param mediationStatus test cases mediation status + */ + public void setMediationStatus(String mediationStatus) { + this.mediationStatus = mediationStatus; + } + + /** + * Set test case assertion status. + * + * @param assertionStatus test cases assertion status + */ + public void setAssertionStatus(String assertionStatus) { + this.assertionStatus = assertionStatus; + } + + /** + * Set test case name. + * + * @param testCaseName test cases name + */ + public void setTestCaseName(String testCaseName) { + this.testCaseName = testCaseName; + } + + /** + * Get test case passed or failed state. + * + * @return boolean value of test case pass or not + */ + public boolean isTestCasePassed() { + if (mediationStatus.equals(FAILED_STATE) || mediationStatus.equals(SKIPPED_STATE)) { + return false; + } + + if (assertionStatus.equals(FAILED_STATE) || assertionStatus.equals(SKIPPED_STATE)) { + return false; + } + + return true; + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestSuiteSummary.java b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestSuiteSummary.java new file mode 100644 index 000000000..a5d1555b9 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/classes/TestSuiteSummary.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest.testcase.data.classes; + +import java.util.ArrayList; +import java.util.List; + +public class TestSuiteSummary { + + private static final String SKIPPED_STATE = "SKIPPED"; + private static final String FAILED_STATE = "FAILED"; + private String exception; + private String description; + private String deploymentStatus = SKIPPED_STATE; + private String mediationStatus = SKIPPED_STATE; + private String recentTestCaseName; + private String mediationException; + private List testCases = new ArrayList(); + + /** + * Get test case deployment status. + * + * @return test cases deployment status + */ + public String getDeploymentStatus() { + return deploymentStatus; + } + + /** + * Set test case deployment status. + * + * @param deploymentStatus test cases deployment status + */ + public void setDeploymentStatus(String deploymentStatus) { + this.deploymentStatus = deploymentStatus; + } + + /** + * Get failure exception. + * + * @return failure exception + */ + public String getDeploymentException() { + return exception; + } + + /** + * Set test case failure exception. + * + * @param exception test case exception + */ + public void setDeploymentException(String exception) { + this.exception = exception; + } + + /** + * Get test case suite passed or failed state. + * + * @return boolean value of test case suite pass or not + */ + public boolean isTestSuiteDeploymentSuccess() { + if (deploymentStatus.equals(SKIPPED_STATE) || deploymentStatus.equals(FAILED_STATE)) { + return false; + } + + return true; + } + + /** + * Add test case summary object. + * + * @param summary test cases summary object + */ + public void addTestCaseSumamry(TestCaseSummary summary) { + testCases.add(summary); + } + + /** + * Get test case summary object list. + * + * @return summary test cases summary object list + */ + public List getTestCaseSumamryList() { + return testCases; + } + + /** + * Get test suite description. + * + * @return test suite description + */ + public String getDescription() { + return description; + } + + /** + * Get test suite name which failed in mediation state. + * + * @return test case name + */ + public String getRecentTestCaseName() { + return recentTestCaseName; + } + + /** + * Set test suite description. + * + * @param description test suite description + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Get test mediation status. + * + * @return test mediation status + */ + public String getMediationStatus() { + return mediationStatus; + } + + /** + * Get test mediation exception. + * + * @return test mediation exception + */ + public String getMediationException() { + return mediationException; + } + + /** + * Set test case mediation status. + * + * @param mediationStatus test case mediation status + */ + public void setMediationStatus(String mediationStatus) { + this.mediationStatus = mediationStatus; + } + + /** + * Set test case mediation exception. + * + * @param mediationException test case mediation exception + */ + public void setMediationException(String mediationException) { + this.mediationException = mediationException; + } + + /** + * Set test case name which run recently. + * + * @param recentTestCaseName test case name + */ + public void setRecentTestCaseName(String recentTestCaseName) { + this.recentTestCaseName = recentTestCaseName; + } + + /** + * Get test case suite mediate passed or failed state. + * + * @return boolean value of test case suite mediate pass or not + */ + public boolean isTestSuiteMediateSuccess() { + if (mediationStatus.equals(SKIPPED_STATE) || mediationStatus.equals(FAILED_STATE)) { + return false; + } + + return true; + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/holders/ArtifactData.java b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/holders/ArtifactData.java new file mode 100755 index 000000000..50df22153 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/holders/ArtifactData.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest.testcase.data.holders; + +import org.apache.synapse.unittest.testcase.data.classes.Artifact; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class responsible for the holding the data of synapse configuration data. + */ +public class ArtifactData { + + private int supportiveArtifactCount; + private Artifact testArtifact; + private ArrayList supportiveArtifacts = new ArrayList(); + private ArrayList connectorResources = new ArrayList(); + + /** + * Set supportive-artifact. + * + * @param supportiveArtifactCount receiving supportive artifact count + */ + public void setSupportiveArtifactCount(int supportiveArtifactCount) { + this.supportiveArtifactCount = supportiveArtifactCount; + } + + /** + * Set artifact. + * + * @param testArtifact receiving test-artifact + */ + public void setTestArtifact(Artifact testArtifact) { + this.testArtifact = testArtifact; + } + + /** + * Add supportive-artifact. + * + * @param supportiveArtifacts receiving test-artifact + */ + public void addSupportiveArtifact(Artifact supportiveArtifacts) { + this.supportiveArtifacts.add(supportiveArtifacts); + } + + /** + * Add connector-resources. + * + * @param base64Encode connector resource key + */ + public void addConnectorResource(String base64Encode) { + this.connectorResources.add(base64Encode); + } + + /** + * Get test-artifact. + * + * @return testArtifact + */ + public Artifact getTestArtifact() { + return testArtifact; + } + + /** + * Get supportive-artifact. + * + * @return supportive-Artifact + */ + public Artifact getSupportiveArtifact(int elementIndex) { + return supportiveArtifacts.get(elementIndex); + } + + /** + * Get connector resources. + * + * @return connector resources + */ + public List getConnectorResources() { + return connectorResources; + } + + /** + * Get supportive-artifact count. + * + * @return count of supportive artifact + */ + public int getSupportiveArtifactCount() { + return supportiveArtifactCount; + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/holders/TestCaseData.java b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/holders/TestCaseData.java new file mode 100755 index 000000000..cd6ea7523 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/unittest/testcase/data/holders/TestCaseData.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.synapse.unittest.testcase.data.holders; + +import org.apache.synapse.unittest.testcase.data.classes.TestCase; + +import java.util.ArrayList; + +/** + * Class responsible for the holding the data of test case data. + */ +public class TestCaseData { + + private int testCaseCount; + private ArrayList testCases = new ArrayList(); + + /** + * Get test case data. + * + * @param elementIndex index of the object + * @return test case object in descriptor data + */ + public TestCase getTestCase(int elementIndex) { + return testCases.get(elementIndex); + } + + /** + * Get test cases count. + * + * @return test cases count in descriptor data + */ + public int getTestCaseCount() { + return testCaseCount; + } + + /** + * Get test case data. + * + * @param testCases test case object + */ + public void setTestCases(TestCase testCases) { + this.testCases.add(testCases); + } + + /** + * Set test cases count. + * + * @param testCaseCount test cases count in descriptor data + */ + public void setTestCaseCount(int testCaseCount) { + this.testCaseCount = testCaseCount; + } +} diff --git a/modules/distribution/src/main/bin/synapse.sh b/modules/distribution/src/main/bin/synapse.sh index dad4a792f..e4c8d6f62 100644 --- a/modules/distribution/src/main/bin/synapse.sh +++ b/modules/distribution/src/main/bin/synapse.sh @@ -129,6 +129,10 @@ SYNAPSE_XML=$SYNAPSE_HOME/repository/conf/synapse-config # server name SERVER_NAME= +# synapse unit test parameters +SYNAPSE_TEST_PARAM= +SYNAPSE_TEST_PORT= + # ----- Uncomment the following line to enalbe the SSL debug options ---------- # TEMP_PROPS="-Djavax.net.debug=all" @@ -150,7 +154,7 @@ if [ "$1" = "-xdebug" ]; then SYNAPSE_DEBUG="synapseDebug" shift -elif [ "$1" = "-h" ]; then + elif [ "$1" = "-h" ]; then echo "Usage: synapse.sh ( commands ... )" echo "commands:" echo " -xdebug Start Synapse under JPDA debugger" @@ -160,6 +164,18 @@ elif [ "$1" = "-h" ]; then shift exit 0 + elif [[ $1 = -DsynapseTest ]]; then + SYNAPSE_TEST_PARAM=$1"=true" + shift 1 + + elif [[ "$1" = -DsynapseTest=true ]]; then + SYNAPSE_TEST_PARAM=$1 + shift 1 + + elif [[ "$1" = -DsynapseTestPort* ]]; then + SYNAPSE_TEST_PORT=$1 + shift 1 + else echo "Error: unknown command:$1" echo "For help: synapse.sh -h" @@ -180,6 +196,8 @@ echo "Using SYNAPSE_XML: $SYNAPSE_XML" $JAVA_HOME/bin/java -server -Xms512M -Xmx512M \ $XDEBUG \ $TEMP_PROPS \ + $SYNAPSE_TEST_PARAM \ + $SYNAPSE_TEST_PORT \ -Dorg.apache.xerces.xni.parser.XMLParserConfiguration=org.apache.xerces.parsers.XMLGrammarCachingConfiguration \ -Djava.endorsed.dirs=$SYNAPSE_ENDORSED \ -Djava.io.tmpdir=$SYNAPSE_HOME/work/temp/synapse \ diff --git a/pom.xml b/pom.xml index 78e2dba14..a3e6a68c6 100644 --- a/pom.xml +++ b/pom.xml @@ -751,6 +751,11 @@ httpcore-nio ${httpcore.nio.version} + + org.apache.httpcomponents + httpclient + ${hc.httpclient.version} + @@ -1010,6 +1015,11 @@ ${rabbitmq.version} compile + + com.google.code.gson + gson + ${com.google.code.gson.version} + @@ -1106,6 +1116,7 @@ 1.2.20 1.6.2 1.3.8 + 4.3.2 ${axis2.version} @@ -1143,6 +1154,7 @@ 2.5.3 3.1.2 1.49 + 2.8.5 1.2