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