RequestHandler.java
/*
Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.apache.synapse.unittest.testcase.data.classes.SynapseTestCase;
import org.apache.synapse.unittest.testcase.data.holders.ArtifactData;
import org.apache.synapse.unittest.testcase.data.holders.MockServiceData;
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 JsonObject responseToClient;
private boolean isTransportPassThroughPortChecked = false;
private String exception;
/**
* 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");
responseToClient = new JsonParser()
.parse("{'test-cases':'Failed while reading synapseTestCase data','Exception':'"
+ exception + "'}").getAsJsonObject();
}
writeData(responseToClient);
MockServiceCreator.stopServices();
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();
MockServiceData readMockServiceData = synapseTestcaseDataReader.readAndStoreMockServiceData();
//configure the artifact if there are mock-services to append
if (readMockServiceData.getMockServicesCount() > 0) {
ConfigModifier.endPointModifier(readArtifactData, readMockServiceData);
}
//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 = e.toString();
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<Boolean, String> supportiveArtifactDeployment = new AbstractMap.SimpleEntry<>(false, null);
Map.Entry<Boolean, String> 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);
}
//check supportive-artifact deployment is success or not
if (supportiveArtifactDeployment.getKey() || synapseTestCase.getArtifacts().getSupportiveArtifactCount() == 0) {
log.info("Test artifact deployment started");
testArtifactDeployment = agent.processTestArtifact(synapseTestCase);
} else if (!supportiveArtifactDeployment.getKey() && supportiveArtifactDeployment.getValue() != null) {
responseToClient = new JsonParser()
.parse("{'deployment':'failed', 'exception':'"
+ supportiveArtifactDeployment.getValue() + "'}").getAsJsonObject();
} else {
responseToClient = new JsonParser()
.parse("{'supportive-deployment':'failed'}").getAsJsonObject();
}
//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
Map.Entry<JsonObject, String> testCasesMediated = agent.processTestCases(synapseTestCase);
//check mediation or invoke is success or failed
if (testCasesMediated.getValue() == null) {
responseToClient = testCasesMediated.getKey();
} else {
responseToClient = new JsonParser()
.parse("{'mediation':'failed', 'exception':'"
+ testCasesMediated.getValue() + "'}").getAsJsonObject();
}
} else if (!testArtifactDeployment.getKey() && testArtifactDeployment.getValue() != null) {
responseToClient = new JsonParser()
.parse("{'deployment':'failed', 'exception':'"
+ testArtifactDeployment.getValue() + "'}").getAsJsonObject();
} else {
responseToClient = new JsonParser()
.parse("{'test-deployment':'failed'}").getAsJsonObject();
}
}
/**
* Write output data to the unit testing client.
*/
private void writeData(JsonObject jsonObject) throws IOException {
OutputStream out = socket.getOutputStream();
ObjectOutputStream o = new ObjectOutputStream(out);
o.writeObject(jsonObject.toString());
out.flush();
}
/**
* 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 = Integer.parseInt(System.getProperty("http.nio.port"));
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;
try (Socket socketTester = new Socket()) {
socketTester.connect(new InetSocketAddress("127.0.0.1", port));
isPortAvailable = false;
} catch (IOException e) {
isPortAvailable = true;
}
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);
}
}
}