X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=otf-camunda%2Fsrc%2Fmain%2Fjava%2Forg%2Foran%2Fotf%2Fcamunda%2Fdelegate%2Fotf%2Fcommon%2Frunnable%2FTestHeadCallable.java;fp=otf-camunda%2Fsrc%2Fmain%2Fjava%2Forg%2Foran%2Fotf%2Fcamunda%2Fdelegate%2Fotf%2Fcommon%2Frunnable%2FTestHeadCallable.java;h=d0ee267d8edeb63856f545eb5d8a10ff4605fcef;hb=14f6f95c84a4a1fa8774190db4a03fd0214ec55f;hp=0000000000000000000000000000000000000000;hpb=f49bd1efeaaddd4891c1f329b18d8cfb28b3e75b;p=it%2Fotf.git diff --git a/otf-camunda/src/main/java/org/oran/otf/camunda/delegate/otf/common/runnable/TestHeadCallable.java b/otf-camunda/src/main/java/org/oran/otf/camunda/delegate/otf/common/runnable/TestHeadCallable.java new file mode 100644 index 0000000..d0ee267 --- /dev/null +++ b/otf-camunda/src/main/java/org/oran/otf/camunda/delegate/otf/common/runnable/TestHeadCallable.java @@ -0,0 +1,267 @@ +/* Copyright (c) 2019 AT&T Intellectual Property. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +##############################################################################*/ + + +package org.oran.otf.camunda.delegate.otf.common.runnable; + + +import org.oran.otf.camunda.exception.TestExecutionException; +import org.oran.otf.common.model.TestExecution; +import org.oran.otf.common.model.TestHead; +import org.oran.otf.common.model.local.TestHeadRequest; +import org.oran.otf.common.model.local.TestHeadResult; +import org.oran.otf.common.utility.Utility; +import org.oran.otf.common.utility.gson.Convert; +import org.oran.otf.common.utility.http.RequestUtility; +import com.google.common.base.Strings; +import com.google.gson.JsonParser; +import com.mongodb.client.result.UpdateResult; +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; + +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; +import org.oran.otf.common.utility.http.HeadersUtility; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; + +// TODO : Create a constructor that does not take a testexecution object as a parameter. This means +// that the result should only be returned, and the call to saveResult should be avoided. +public class TestHeadCallable implements Callable { + + private static Logger logger = LoggerFactory.getLogger(TestHeadCallable.class); + private final String logPrefix = Utility.getLoggerPrefix(); + private final TestExecution testExecution; + + private final int timeoutInMillis; + private final String httpMethod; + private final Map headers; + private final Map body; + private final TestHead testHead; + private final String activityId; + + private final MongoTemplate mongoOperation; + + private String url; + private TestHeadResult result; + private Date startTime; + private Date endTime; + + public TestHeadCallable( + int timeoutInMillis, + String httpMethod, + Map headers, + Map vthInput, + TestHead testHead, + String activityId, + TestExecution testExecution, + MongoTemplate mongoOperation) { + this.timeoutInMillis = timeoutInMillis; + this.httpMethod = httpMethod; + this.headers = headers; + this.body = vthInput; + this.testHead = testHead; + this.activityId = activityId; + this.testExecution = testExecution; + + this.mongoOperation = mongoOperation; + + // Generate the url after the test head is set. + this.url = generateUrl(); + } + + @Override + public TestHeadResult call() throws Exception { + // If simulation mode is set, then send back expected result after expected delay + if (testExecution.getHistoricTestInstance().isSimulationMode()) { + logger.info(logPrefix + "Start call to test head in simulation mode."); + startTime = new Date(System.currentTimeMillis()); + Map response = + simulateVTH( + this.activityId, testExecution.getHistoricTestInstance().getSimulationVthInput()); + endTime = new Date(System.currentTimeMillis()); + logger.info(logPrefix + "Finished call to test head in simulation mode."); + + //TODO: This will need to change if enhancement is made to allow status codes + TestHeadResult result = generateResult(response); + testExecution.getTestHeadResults().add(result); + saveResult(testExecution); + return result; + } + logger.info(logPrefix + "Start call to test head."); + HttpResponse response = null; + TestHeadResult result = null; + // Set the start time right before the request. + startTime = new Date(System.currentTimeMillis()); + + // add api key to headers if required + setApiKeyIfEnabled(); + + //TODO RG Added to slow Execution + //Thread.sleep(60000); + + try { + switch (httpMethod.toLowerCase()) { + case "post": + response = + timeoutInMillis > 0 + ? RequestUtility.postSync( + url, Convert.mapToJson(body), headers, timeoutInMillis, false) + : RequestUtility.postSync(url, Convert.mapToJson(body), headers, false); + break; + case "get": + response = + timeoutInMillis > 0 + ? RequestUtility.getSync(url, headers, timeoutInMillis, false) + : RequestUtility.getSync(url, headers, false); + break; + default: + throw new RuntimeException(); + } + // Set the end time when the request returns. + endTime = new Date(System.currentTimeMillis()); + logger.info(logPrefix + "Finished call to test head."); + + // Generate and return the result. + result = generateResult(response); + } catch (Exception e) { + Map error = new HashMap<>(); + error.put("error", e.getMessage()); + result = generateFailedResult(error); + + logger.info(logPrefix + "There was an error calling the test head."); + } + + testExecution.getTestHeadResults().add(result); + saveResult(testExecution); + return result; + } + + private void setApiKeyIfEnabled(){ + if(this.testHead.getAuthorizationEnabled() != null && this.testHead.getAuthorizationEnabled().booleanValue()){ + this.headers.put(HttpHeaders.AUTHORIZATION, testHead.getAuthorizationType() + " " + testHead.getAuthorizationCredential()); + } + } + + private String generateUrl() { + String resource = testHead.getResourcePath(); + // Prepend a forward-slash if the resource path exists, and does NOT already start with one. The + // order of this condition is relevant for null-checks. + if (!Strings.isNullOrEmpty(resource) && !resource.startsWith("/")) { + resource = "/" + resource; + } + return testHead.getHostname() + ":" + testHead.getPort() + resource; + } + + private TestHeadResult generateFailedResult(Map error) { + int statusCodeError = -1; + TestHeadRequest requestContent = new TestHeadRequest(HeadersUtility.maskAuth(headers), body); + + return new TestHeadResult( + testHead.get_id(), testHead.getTestHeadName(), testHead.getGroupId(), activityId, statusCodeError, requestContent, error, startTime, endTime); + } + + private TestHeadResult generateResult(HttpResponse response) throws IOException { + String sRes = EntityUtils.toString(response.getEntity()); + JsonParser parser = new JsonParser(); + Map res; + try { + res = Convert.jsonToMap(sRes); + } catch (Exception e) { + res = new HashMap<>(); + res.put("response", sRes); + } + + TestHeadRequest requestContent = new TestHeadRequest(HeadersUtility.maskAuth(headers), body); + + return new TestHeadResult( + testHead.get_id(), testHead.getTestHeadName(), testHead.getGroupId(), activityId, response.getStatusLine().getStatusCode(), requestContent, res, startTime, endTime); + } + + private TestHeadResult generateResult(Map res) { + + //TODO: This will need to change if enhancement is made to allow status codes + TestHeadRequest requestContent = new TestHeadRequest(HeadersUtility.maskAuth(headers), body); + + return new TestHeadResult( + testHead.get_id(), testHead.getTestHeadName(), testHead.getGroupId(), activityId, 200, requestContent, res, startTime, endTime); + } + + private void saveResult(TestExecution testExecution) { + Query query = new Query(); + query.addCriteria(Criteria.where("_id").is(testExecution.get_id())); + // Also add businessKey as a criteria because the object won't be found if the business key + // was somehow modified in the workflow. + query.addCriteria(Criteria.where("businessKey").is(testExecution.getBusinessKey())); + Update update = new Update(); + update.set("testHeadResults", testExecution.getTestHeadResults()); + UpdateResult result = mongoOperation.updateFirst(query, update, TestExecution.class); + // Check the status of the findAndUpdate database, and appropriately handle the errors. + if (result.getMatchedCount() == 0) { + throw new TestExecutionException( + String.format( + "Unable to log the test result because a testExecution associated with _id, %s and businessKey %s, was not found.", + testExecution.get_id(), testExecution.getBusinessKey())); + } else if (result.getModifiedCount() == 0) { + throw new TestExecutionException("Unable to persist the testExecution to the database."); + } + } + + private Map simulateVTH(String activityId, Map simulationVth) { + int delay = 0; + Map response = new HashMap(); + if (simulationVth.containsKey(activityId)) { + Object obj = simulationVth.get(activityId); + if (obj instanceof Map) { + simulationVth = (Map) obj; + } + } else { + return null; + } + + if (simulationVth.containsKey("delay")) { + Object obj = simulationVth.get("delay"); + if (obj instanceof Integer) { + delay = (int) obj; + } + } + + if (simulationVth.containsKey("response")) { + Object obj = simulationVth.get("response"); + if (obj instanceof Map) { + response = (Map) obj; + } + } + logger.info(logPrefix + "Starting simulated call to test head."); + + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + e.printStackTrace(); + logger.info(logPrefix + "Error simulating call to test head."); + return null; + } + logger.info(logPrefix + "Finished simulating call to test head."); + return response; + } +}