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