Code Improvements-Vnfsdk-refrepo sonar issue fixes
[vnfsdk/refrepo.git] / vnfmarket-be / vnf-sdk-marketplace / src / main / java / org / onap / vtp / execution / VTPExecutionResource.java
1 /**
2  * Copyright 2018 Huawei Technologies Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.vtp.execution;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.nio.file.StandardCopyOption;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Date;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.UUID;
30
31 import javax.ws.rs.Consumes;
32 import javax.ws.rs.DefaultValue;
33 import javax.ws.rs.GET;
34 import javax.ws.rs.POST;
35 import javax.ws.rs.Path;
36 import javax.ws.rs.PathParam;
37 import javax.ws.rs.Produces;
38 import javax.ws.rs.QueryParam;
39 import javax.ws.rs.core.MediaType;
40 import javax.ws.rs.core.Response;
41
42 import org.apache.commons.io.FileUtils;
43 import org.apache.commons.io.IOUtils;
44 import org.apache.commons.lang3.StringUtils;
45 import org.eclipse.jetty.http.HttpStatus;
46 import org.glassfish.jersey.media.multipart.BodyPartEntity;
47 import org.glassfish.jersey.media.multipart.FormDataBodyPart;
48 import org.glassfish.jersey.media.multipart.FormDataParam;
49 import org.onap.vtp.VTPResource;
50 import org.onap.vtp.error.VTPError;
51 import org.onap.vtp.error.VTPError.VTPException;
52 import org.onap.vtp.execution.model.VTPTestExecution;
53 import org.onap.vtp.execution.model.VTPTestExecution.VTPTestExecutionList;
54 import org.open.infc.grpc.Output;
55 import org.open.infc.grpc.Result;
56
57 import com.google.gson.Gson;
58 import com.google.gson.JsonElement;
59 import com.google.gson.JsonObject;
60 import com.google.gson.JsonArray;
61 import com.google.gson.JsonParser;
62 import com.google.gson.reflect.TypeToken;
63
64 import io.swagger.annotations.Api;
65 import io.swagger.annotations.ApiOperation;
66 import io.swagger.annotations.ApiParam;
67 import io.swagger.annotations.ApiResponse;
68 import io.swagger.annotations.ApiResponses;
69
70 @Path("/vtp")
71 @Api(tags = {"VTP Execution"})
72 public class VTPExecutionResource  extends VTPResource{
73     private static final String EXECUTION_ID = "execution-id";
74     private static final String START_TIME = "start-time";
75     private static final String END_TIME = "end-time";
76     private static final String REQUEST_ID = "request-id";
77     private static final String PRODUCT = "product";
78     private static final String SERVICE = "service";
79     private static final String COMMAND = "command";
80     private static final String PROFILE = "profile";
81     private static final String STATUS = "status";
82     private static final String OUTPUT = "output";
83     private static final String INPUT = "input";
84     private static final String ERROR = "error";
85     private static final String FILE = "file://";
86     private static final String EXCEPTION_OCCURS ="Exception occurs";
87     private static final String PRODUCT_ARG="--product";
88     private static final String OPEN_CLI="open-cli";
89     private static final String FORMAT="--format";
90
91     private static Gson gson = new Gson();
92
93     public VTPTestExecutionList executeHandler(VTPTestExecutionList executions, String requestId) throws VTPException {
94         if (requestId == null) {
95             requestId = UUID.randomUUID().toString();
96         }
97
98         for (VTPTestExecution execution: executions.getExecutions())  {
99             String startTime = dateFormatter.format(new Date());
100             execution.setStartTime(startTime);
101
102             //Run execution
103             Output output = this.makeRpc(
104                     execution.getScenario(),
105                     requestId,
106                     execution.getProfile(),
107                     execution.getTestCaseName(),
108                     execution.getParameters()
109                     );
110             String endTime = dateFormatter.format(new Date());
111             execution.setEndTime(endTime);
112             execution.setExecutionId(output.getAddonsMap().get(EXECUTION_ID));
113
114             // set execution status based on success from test.
115             if (output.getSuccess()) {
116               execution.setStatus(VTPTestExecution.Status.COMPLETED.name());
117             }
118             else {
119               execution.setStatus(VTPTestExecution.Status.FAILED.name());
120             }
121
122             // set the results from what is available in the output independent of status.
123             // tests can fail but still produce results.
124             JsonParser jsonParser = new JsonParser();
125             Map<String,String> m = output.getAttrsMap();
126             if ((m.containsKey(ERROR)) && (!StringUtils.equals(m.get(ERROR), "{}"))) {
127                 try {
128                     execution.setResults(jsonParser.parse(m.get(ERROR)));
129                 } catch (Exception e) { //NOSONAR
130                     LOG.error(EXCEPTION_OCCURS,e);
131                 }
132             }
133             else if (m.containsKey("results")) {
134                 try {
135                     execution.setResults(jsonParser.parse(m.get("results")));
136                 } catch (Exception e) { //NOSONAR
137                     LOG.error(EXCEPTION_OCCURS,e);
138                 }
139             }
140         }
141
142         return executions;
143     }
144
145     private Map<String, String> storeTestCaseInputFiles(List<FormDataBodyPart> bodyParts) throws IOException {
146         Map<String, String> map = new HashMap<>();
147         if (bodyParts != null) {
148             for (FormDataBodyPart part: bodyParts) {
149                 String name = part.getContentDisposition().getFileName();
150                 String path = VTP_EXECUTION_TEMP_STORE + "/" + name; //NOSONAR
151
152                 File f = new File(path);
153                 if (f.exists()) {
154                     FileUtils.forceDelete(f);
155                 }
156                 FileUtils.forceMkdir(f.getParentFile());
157
158                 BodyPartEntity fileEntity = (BodyPartEntity) part.getEntity();
159                 java.nio.file.Files.copy(
160                         fileEntity.getInputStream(),
161                         f.toPath(),
162                         StandardCopyOption.REPLACE_EXISTING);
163
164                 IOUtils.closeQuietly(fileEntity.getInputStream());
165
166                 map.put(name, path);
167             }
168
169         }
170
171         return map;
172     }
173
174     @Path("/executions")
175     @POST
176     @ApiOperation(tags = "VTP Execution", value = "Execute the test case with given inputs in 'executions' form-data "
177             + "as key-value pair of parameter's name vs parameter's value. If parameter is binary type then" +
178             "multi-part form-data 'file' should be used to feed the binary file content and it can be more than once. "
179             + "To use the given file as input parameter, prefix the value with file://<filename>." ,
180             response = VTPTestExecution.class, responseContainer = "List")
181     @Consumes({MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_JSON})
182     @Produces(MediaType.APPLICATION_JSON)
183     @ApiResponses(value = {
184             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
185                     message = "Failed to perform the operation",
186                     response = VTPError.class)})
187     public Response executeTestcases(
188              @ApiParam(value = "Request Id") @QueryParam("requestId") String requestId,
189              @ApiParam(value = "Testcase File arguments", required = false) @FormDataParam("file") List<FormDataBodyPart> bodyParts,
190              @FormDataParam("executions") String executionsJson) throws VTPException {
191
192         VTPTestExecutionList executions = new VTPTestExecution.VTPTestExecutionList();
193         Map<String, String> map = null;
194         try {
195             map = this.storeTestCaseInputFiles(bodyParts);
196         } catch (IOException e) {
197             LOG.error("IOException occurs",e);
198         }
199
200         if (map != null) {
201             for (Map.Entry<String, String> entry: map.entrySet()) {
202                 if (executionsJson.contains(FILE + entry.getKey())) {
203                     executionsJson = executionsJson.replaceAll(FILE + entry.getKey(), entry.getValue());
204                 }
205             }
206         }
207
208         if (executionsJson.contains(FILE)) {
209             VTPError err = new VTPError()
210                     .setMessage("Some file form-data is missing as executions has input parameter tagged with file://")
211                     .setHttpStatus(HttpStatus.BAD_REQUEST_400);
212             throw new VTPException(err);
213
214         }
215
216         try {
217             executions.setExecutions(
218                         gson.fromJson(executionsJson, new TypeToken<List<VTPTestExecution>>(){}.getType()));
219         } catch (Exception e) { //NOSONAR
220             LOG.error(EXCEPTION_OCCURS,e);
221         }
222
223         executions = this.executeHandler(executions, requestId);
224
225         if (map != null) {
226             for (Map.Entry<String, String> entry: map.entrySet()) {
227                 try {
228                     FileUtils.forceDelete(new File(entry.getValue()));
229                 } catch (IOException e) {
230                     LOG.error("IOException occurs",e);
231                 }
232             }
233         }
234
235         return Response.ok(executions.getExecutions().toString(), MediaType.APPLICATION_JSON).build();
236     }
237
238     public VTPTestExecutionList listTestExecutionsHandler(
239             String requestId,
240             String scenario,
241             String testSuiteName,
242             String testCaseName,
243             String profile, //NOSONAR
244             String startTime,
245             String endTime) throws VTPException, IOException {
246         List<String> args = new ArrayList<>();
247         args.addAll(Arrays.asList(
248                 PRODUCT_ARG, OPEN_CLI, "execution-list", FORMAT, "json"
249                 ));
250
251         if (startTime != null && !startTime.isEmpty()) {
252             args.add("--start-time");
253             args.add(startTime);
254         }
255
256         if (endTime != null && !endTime.isEmpty()) {
257             args.add("--end-time");
258             args.add(endTime);
259         }
260
261         if (requestId != null && !requestId.isEmpty()) {
262             args.add("--request-id");
263             args.add(requestId);
264         }
265
266         if (testSuiteName != null && !testSuiteName.isEmpty()) {
267             args.add("--service");
268             args.add(testSuiteName);
269         }
270
271         if (scenario != null && !scenario.isEmpty()) {
272             args.add(PRODUCT_ARG);
273             args.add(scenario);
274         }
275
276         if (testCaseName != null && !testCaseName.isEmpty()) {
277             args.add("--command");
278             args.add(testCaseName);
279         }
280
281         JsonElement results = this.makeRpcAndGetJson(args);
282
283         VTPTestExecutionList list = new VTPTestExecutionList();
284
285         if (results != null && results.isJsonArray() && results.getAsJsonArray().size() > 0) {
286             JsonArray resultsArray = results.getAsJsonArray();
287                 for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
288                     JsonElement jsonElement = it.next();
289                     JsonObject n = jsonElement.getAsJsonObject();
290                     if (n.entrySet().iterator().hasNext()) {
291                         VTPTestExecution exec = new VTPTestExecution();
292                         if (n.get(START_TIME) != null)
293                             exec.setStartTime(n.get(START_TIME).getAsString());
294
295                         if (n.get(END_TIME) != null)
296                             exec.setEndTime(n.get(END_TIME).getAsString());
297
298                         if (n.get(EXECUTION_ID) != null)
299                             exec.setExecutionId(n.get(EXECUTION_ID).getAsString());
300
301                         if (n.get(REQUEST_ID) != null)
302                             exec.setRequestId(n.get(REQUEST_ID).getAsString());
303
304                         if (n.get(PRODUCT) != null)
305                             exec.setScenario(n.get(PRODUCT).getAsString());
306
307                         if (n.get(SERVICE) != null)
308                             exec.setTestSuiteName(n.get(SERVICE).getAsString());
309
310                         if (n.get(COMMAND) != null)
311                             exec.setTestCaseName(n.get(COMMAND).getAsString());
312
313                         if (n.get(PROFILE) != null)
314                             exec.setProfile(n.get(PROFILE).getAsString());
315
316                         if (n.get(STATUS) != null)
317                             exec.setStatus(n.get(STATUS).getAsString());
318
319                         list.getExecutions().add(exec);
320                     }
321
322                 }
323         }
324
325         return list;
326     }
327
328     @Path("/executions")
329     @GET
330     @ApiOperation(tags = "VTP Execution", value = " List test executions", response = VTPTestExecution.class, responseContainer = "List")
331     @Produces(MediaType.APPLICATION_JSON)
332     @ApiResponses(value = {
333             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
334                     message = "Failed to perform the operation",
335                     response = VTPError.class) })
336     public Response listTestExecutions(
337              @ApiParam("Test request Id") @QueryParam("requestId") String requestId,
338              @ApiParam("Test scenario name") @QueryParam("scenario") String scenario,
339              @ApiParam("Test suite name") @QueryParam("testsuiteName") String testsuiteName,
340              @ApiParam("Test case name") @QueryParam("testcaseName") String testcaseName,
341              @ApiParam("Test profile name") @QueryParam("profileName") String profileName,
342              @ApiParam("Test execution start time") @QueryParam("startTime") String startTime,
343              @ApiParam("Test execution end time") @QueryParam("endTime") String endTime
344              ) throws VTPException, IOException  {
345
346         return Response.ok(this.listTestExecutionsHandler(
347                 requestId, scenario, testsuiteName, testcaseName, profileName, startTime, endTime).getExecutions().toString(), MediaType.APPLICATION_JSON).build();
348     }
349
350     public VTPTestExecution getTestExecutionHandler(
351             String executionId) throws VTPException, IOException {
352         List<String> args = new ArrayList<>();
353         args.addAll(Arrays.asList(
354                 PRODUCT_ARG, OPEN_CLI, "execution-show", "--execution-id", executionId, FORMAT, "json"
355                 ));
356
357
358         JsonElement result = this.makeRpcAndGetJson(args);
359
360         VTPTestExecution exec = new VTPTestExecution();
361
362         if (result != null && result.isJsonObject()) {
363
364             JsonObject resultObj = result.getAsJsonObject();
365             if (resultObj.entrySet().iterator().hasNext()){
366                 if (resultObj.get(START_TIME) != null)
367                     exec.setStartTime(resultObj.get(START_TIME).getAsString());
368
369                 if (resultObj.get(END_TIME) != null)
370                     exec.setEndTime(resultObj.get(END_TIME).getAsString());
371
372                 if (resultObj.get(EXECUTION_ID) != null)
373                     exec.setExecutionId(resultObj.get(EXECUTION_ID).getAsString());
374                 if (resultObj.get(REQUEST_ID) != null)
375                     exec.setExecutionId(resultObj.get(REQUEST_ID).getAsString());
376
377                 if (resultObj.get(PRODUCT) != null)
378                     exec.setScenario(resultObj.get(PRODUCT).getAsString());
379                 if (resultObj.get(SERVICE) != null)
380                     exec.setTestSuiteName(resultObj.get(SERVICE).getAsString());
381                 if (resultObj.get(COMMAND) != null)
382                     exec.setTestCaseName(resultObj.get(COMMAND).getAsString());
383                 if (resultObj.get(PROFILE) != null)
384                     exec.setExecutionId(resultObj.get(PROFILE).getAsString());
385                 if (resultObj.get(STATUS) != null)
386                     exec.setStatus(resultObj.get(STATUS).getAsString());
387                 if (resultObj.get(INPUT) != null ) {
388                     exec.setParameters(resultObj.get(INPUT));
389                 }
390                 if (resultObj.get(OUTPUT) != null) {
391                     JsonParser jsonParser = new JsonParser();
392                     JsonElement resultJson = null;
393                     try {
394                         resultJson = jsonParser.parse(resultObj.get(OUTPUT).getAsString());
395
396                     //workarround, sometimes its null.
397                         if (resultJson == null || resultJson.isJsonNull()) {
398                             resultJson = jsonParser.parse(resultObj.get(OUTPUT).toString());
399                         }
400                     } catch (Exception e) {
401                         LOG.error(EXCEPTION_OCCURS, e);
402                         JsonObject node = new JsonObject();
403                         node.addProperty(ERROR, resultObj.get(OUTPUT).toString());
404                         resultJson = node;
405                     }
406
407                     exec.setResults(resultJson);
408                 }
409             }
410         }
411
412         return exec;
413     }
414
415     @Path("/executions/{executionId}")
416     @GET
417     @ApiOperation(tags = "VTP Execution", value = " Retrieve test execution complete details", response = VTPTestExecution.class)
418     @Produces(MediaType.APPLICATION_JSON)
419     @ApiResponses(value = {
420             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
421                     message = "Failed to perform the operation",
422                     response = VTPError.class) })
423     public Response getTestExecution(
424              @ApiParam("Test execution Id") @PathParam("executionId") String executionId
425              ) throws VTPException, IOException  {
426
427         return Response.ok(this.getTestExecutionHandler(executionId).toString(), MediaType.APPLICATION_JSON).build();
428     }
429
430     public String getTestExecutionLogsHandler(
431             String executionId, String action) throws VTPException {
432         List<String> args = new ArrayList<>();
433         args.addAll(Arrays.asList(
434                 PRODUCT_ARG, OPEN_CLI, "execution-show-" + action, "--execution-id", executionId, FORMAT, "text"
435                 ));
436
437
438         Result result = this.makeRpc(args);
439
440         return result.getOutput();
441     }
442
443     @Path("/executions/{executionId}/logs")
444     @GET
445     @ApiOperation(tags = "VTP Execution", value = "Retrieve test execution logs details", response = String.class)
446     @Produces(MediaType.TEXT_PLAIN)
447     @ApiResponses(value = {
448             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
449                     message = "Failed to perform the operation",
450                     response = VTPError.class) })
451     public Response getTestExecutionLogs(
452              @ApiParam("Test execution Id") @PathParam("executionId") String executionId,
453              @ApiParam("Test console reports, Options: out, err, debug") @DefaultValue("out")  @QueryParam("option") String option
454              ) throws VTPException {
455         if (!("out".equalsIgnoreCase(option) || "err".equalsIgnoreCase(option) || "debug".equalsIgnoreCase(option))) {
456                 option = "out";
457         }
458
459         return Response.ok(this.getTestExecutionLogsHandler(executionId, option), MediaType.TEXT_PLAIN).build();
460     }
461 }