b6b2dbc0ca36127c03851823a3e1b1db205443d9
[vnfsdk/refrepo.git] / vnfmarket-be / vnf-sdk-marketplace / src / main / java / org / onap / vtp / scenario / VTPScenarioResource.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.scenario;
18
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.FileReader;
22 import java.io.FileWriter;
23 import java.io.IOException;
24 import java.text.MessageFormat;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.regex.Matcher;
31
32 import javax.ws.rs.Consumes;
33 import javax.ws.rs.DELETE;
34 import javax.ws.rs.GET;
35 import javax.ws.rs.POST;
36 import javax.ws.rs.Path;
37 import javax.ws.rs.PathParam;
38 import javax.ws.rs.Produces;
39 import javax.ws.rs.QueryParam;
40 import javax.ws.rs.core.MediaType;
41 import javax.ws.rs.core.Response;
42
43 import com.google.common.collect.Maps;
44 import org.apache.commons.io.FileUtils;
45 import org.apache.cxf.common.util.CollectionUtils;
46 import org.eclipse.jetty.http.HttpStatus;
47 import org.glassfish.jersey.media.multipart.BodyPartEntity;
48 import org.glassfish.jersey.media.multipart.FormDataBodyPart;
49 import org.glassfish.jersey.media.multipart.FormDataParam;
50 import org.onap.vnfsdk.marketplace.common.CommonConstant;
51 import org.onap.vnfsdk.marketplace.common.FileUtil;
52 import org.onap.vnfsdk.marketplace.common.ToolUtil;
53 import org.onap.vtp.VTPResource;
54 import org.onap.vtp.error.VTPError;
55 import org.onap.vtp.error.VTPError.VTPException;
56 import org.onap.vtp.manager.DistManager;
57 import org.onap.vtp.scenario.model.VTPTestCase;
58 import org.onap.vtp.scenario.model.VTPTestScenario;
59 import org.onap.vtp.scenario.model.VTPTestSuite;
60 import org.onap.vtp.scenario.model.VTPTestCase.VTPTestCaseInput;
61 import org.onap.vtp.scenario.model.VTPTestCase.VTPTestCaseList;
62 import org.onap.vtp.scenario.model.VTPTestCase.VTPTestCaseOutput;
63 import org.onap.vtp.scenario.model.VTPTestScenario.VTPTestScenarioList;
64 import org.onap.vtp.scenario.model.VTPTestSuite.VTPTestSuiteList;
65
66 import com.google.gson.JsonArray;
67 import com.google.gson.JsonElement;
68 import com.google.gson.JsonObject;
69
70 import io.swagger.annotations.Api;
71 import io.swagger.annotations.ApiOperation;
72 import io.swagger.annotations.ApiParam;
73 import io.swagger.annotations.ApiResponse;
74 import io.swagger.annotations.ApiResponses;
75
76 @Path("/vtp")
77 @Api(tags = {"VTP Scenario"})
78 public class VTPScenarioResource extends VTPResource{
79     private static final String DESCRIPTION = "description";
80     private static final String PRODUCT_ARG="--product";
81     private static final String OPEN_CLI="open-cli";
82     private static final String FORMAT="--format";
83     private static final String IO_EXCEPTION_OCCURS ="IOException occurs";
84     private static final String SERVICE="service";
85     private static final String PRODUCT = "product";
86     private DistManager distManagerVtpScenarioResource = new DistManager();
87     public VTPTestScenarioList listTestScenariosHandler() throws VTPException {
88         List<String> args = new ArrayList<>();
89
90         args.addAll(Arrays.asList(
91                 PRODUCT_ARG, OPEN_CLI, "product-list", FORMAT, "json"
92         ));
93
94
95         JsonElement results = null;
96         if (isDistMode()) {
97             String endPoint="/manager/scenarios";
98             return  distManagerVtpScenarioResource.getScenarioListFromManager(endPoint);
99         }
100         else{
101             try {
102                 results = this.makeRpcAndGetJson(args);
103             } catch (IOException e) {
104                 LOG.error(IO_EXCEPTION_OCCURS, e);
105             }
106         }
107
108         VTPTestScenarioList list = new VTPTestScenarioList();
109
110         if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) {
111             JsonArray resultsArray = results.getAsJsonArray();
112             for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
113                 JsonElement jsonElement = it.next();
114                 JsonObject n = jsonElement.getAsJsonObject();
115                 if (n.entrySet().iterator().hasNext()) {
116                     String name = n.get(PRODUCT).getAsString();
117
118                     if (OPEN_CLI.equalsIgnoreCase(name))
119                         continue;
120
121                     list.getScenarios().add(new VTPTestScenario().setName(name).setDescription(
122                             n.get(DESCRIPTION).getAsString()));
123                 }
124             }
125         }
126
127         return list;
128     }
129
130     @Path("/scenarios")
131     @GET
132     @ApiOperation(tags = "VTP Scenario", value = " List available test scenarios", response = VTPTestScenario.class, responseContainer = "List")
133     @Produces(MediaType.APPLICATION_JSON)
134     @ApiResponses(value = {
135             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
136                     message = "Failed to perform the operation",
137                     response = VTPError.class) })
138     public Response listTestScenarios() throws VTPException {
139         return Response.ok(this.listTestScenariosHandler().getScenarios().toString(), MediaType.APPLICATION_JSON).build();
140     }
141
142     public VTPTestSuiteList listTestSutiesHandler(String scenario) throws VTPException {
143         List<String> args = new ArrayList<>();
144
145         args.addAll(Arrays.asList(
146                 PRODUCT_ARG, OPEN_CLI, "service-list", PRODUCT_ARG, scenario, FORMAT, "json"
147         ));
148
149         JsonElement results = null;
150         if (isDistMode()) {
151             String url="/manager/scenarios/"+scenario+"/testsuites";
152             return distManagerVtpScenarioResource.getSuiteListFromManager(url);
153         }else {
154             try {
155                 results = this.makeRpcAndGetJson(args);
156             } catch (IOException e) {
157                 LOG.error(IO_EXCEPTION_OCCURS,e);
158             }
159         }
160
161         VTPTestSuiteList list = new VTPTestSuiteList();
162
163         if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) {
164             JsonArray resultsArray = results.getAsJsonArray();
165             for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
166                 JsonElement jsonElement = it.next();
167                 JsonObject n = jsonElement.getAsJsonObject();
168                 if (n.entrySet().iterator().hasNext()) {
169                     list.getSuites().add(new VTPTestSuite().setName(n.get(SERVICE).getAsString()).setDescription(
170                             n.get(DESCRIPTION).getAsString()));
171                 }
172             }
173         }
174
175         return list;
176     }
177
178     @Path("/scenarios/{scenario}/testsuites")
179     @GET
180     @ApiOperation(tags = "VTP Scenario",  value = " List available test suties in given scenario", response = VTPTestSuite.class, responseContainer = "List")
181     @Produces(MediaType.APPLICATION_JSON)
182     @ApiResponses(value = {
183             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
184                     message = "Failed to perform the operation",
185                     response = VTPError.class) })
186     public Response listTestSuties(
187             @ApiParam("Test scenario name") @PathParam("scenario") String scenario) throws VTPException {
188
189         return Response.ok(this.listTestSutiesHandler(scenario).getSuites().toString(), MediaType.APPLICATION_JSON).build();
190     }
191
192     public VTPTestCaseList listTestcasesHandler(String testSuiteName, String scenario) throws VTPException {
193         List<String> args = new ArrayList<>();
194
195         args.addAll(Arrays.asList(
196                 PRODUCT_ARG, OPEN_CLI, "schema-list", PRODUCT_ARG, scenario, FORMAT, "json"
197         ));
198         if (testSuiteName != null) {
199             args.add("--service");
200             args.add(testSuiteName);
201         }
202
203         JsonElement results = null;
204         if (isDistMode()) {
205             String url = "/manager/scenarios/" + scenario + "/testcases";
206             return distManagerVtpScenarioResource.getTestCaseListFromManager(url);
207         } else {
208             try {
209                 results = this.makeRpcAndGetJson(args);
210             } catch (IOException e) {
211                 LOG.error(IO_EXCEPTION_OCCURS, e);
212             }
213         }
214
215         VTPTestCaseList list = new VTPTestCaseList();
216
217         if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) {
218             JsonArray resultsArray = results.getAsJsonArray();
219             for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
220                 JsonElement jsonElement = it.next();
221                 JsonObject n = jsonElement.getAsJsonObject();
222                 if (n.entrySet().iterator().hasNext())
223                     list.getTestCases().add(
224                             new VTPTestCase().setTestCaseName(
225                                     n.get("command").getAsString()).setTestSuiteName(
226                                     n.get(SERVICE).getAsString()));
227             }
228         }
229
230         return list;
231     }
232
233     @Path("/scenarios/{scenario}/testcases")
234     @GET
235     @ApiOperation(tags = "VTP Scenario", value = " List available test cases", response = VTPTestCase.class, responseContainer = "List")
236     @Produces(MediaType.APPLICATION_JSON)
237     @ApiResponses(value = {
238             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
239                     message = "Failed to perform the operation",
240                     response = VTPError.class) })
241     public Response listTestcases(
242             @ApiParam("Test scenario name") @PathParam("scenario") String scenario,
243             @ApiParam("Test suite name") @QueryParam("testSuiteName") String testSuiteName
244     ) throws VTPException {
245
246         return Response.ok(this.listTestcasesHandler(testSuiteName, scenario).getTestCases().toString(), MediaType.APPLICATION_JSON).build();
247     }
248
249     public VTPTestCase getTestcaseHandler(String scenario, String testSuiteName, String testCaseName) throws VTPException {
250         List<String> args = new ArrayList<>();
251         args.addAll(Arrays.asList(
252                 PRODUCT_ARG, OPEN_CLI, "schema-show", PRODUCT_ARG, scenario, "--service", testSuiteName, "--command", testCaseName , FORMAT, "json"
253         ));
254         JsonElement results = null;
255         try {
256             results = this.makeRpcAndGetJson(args);
257         } catch (IOException e) {
258             LOG.error(IO_EXCEPTION_OCCURS,e);
259         }
260
261         JsonObject schema = results.getAsJsonObject().getAsJsonObject("schema");
262
263         VTPTestCase tc = new VTPTestCase();
264         tc.setTestCaseName(schema.get("name").getAsString());
265         tc.setDescription(schema.get(DESCRIPTION).getAsString());
266         tc.setTestSuiteName(schema.get(SERVICE).getAsString());
267         tc.setAuthor(schema.get("author").getAsString());
268         JsonElement inputsJson = schema.get("inputs");
269         if (inputsJson != null && inputsJson.isJsonArray()) {
270             formatResponseData(tc, inputsJson);
271         }
272
273         JsonElement outputsJson = schema.get("outputs");
274         if (outputsJson != null && outputsJson.isJsonArray() && outputsJson.getAsJsonArray().size()>0) {
275             for (final JsonElement jsonElement: outputsJson.getAsJsonArray()) {
276                 JsonObject outputJson = jsonElement.getAsJsonObject();
277                 VTPTestCaseOutput output = new VTPTestCaseOutput();
278                 output.setName(outputJson.get("name").getAsString());
279                 output.setDescription(outputJson.get(DESCRIPTION).getAsString());
280                 output.setType(outputJson.get("type").getAsString());
281
282                 tc.getOutputs().add(output);
283             }
284         }
285
286         return tc;
287     }
288
289         private void formatResponseData(VTPTestCase tc, JsonElement inputsJson) {
290                 for (final JsonElement jsonElement: inputsJson.getAsJsonArray()) {
291                     JsonObject inputJson  = jsonElement.getAsJsonObject();
292                     VTPTestCaseInput input = new VTPTestCaseInput();
293
294                     input.setName(inputJson.get("name").getAsString());
295                     input.setDescription(inputJson.get(DESCRIPTION).getAsString());
296                     input.setType(inputJson.get("type").getAsString());
297
298                     if (inputJson.get("is_optional") != null)
299                         input.setIsOptional(inputJson.get("is_optional").getAsBoolean());
300
301                     if (inputJson.get("default_value") != null)
302                         input.setDefaultValue(inputJson.get("default_value").getAsString());
303
304                     if (inputJson.get("metadata") != null)
305                         input.setMetadata(inputJson.get("metadata"));
306
307                     tc.getInputs().add(input);
308                 }
309         }
310
311     @Path("/scenarios/{scenario}/testsuites/{testSuiteName}/testcases/{testCaseName}")
312     @GET
313     @ApiOperation(tags = "VTP Scenario",  value = "Retrieve test cases details like inputs outputs and test suite name", response = VTPTestCase.class)
314     @Produces(MediaType.APPLICATION_JSON)
315     @ApiResponses(value = {
316             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
317                     message = "Failed to perform the operation", response = VTPError.class),
318             @ApiResponse(code = HttpStatus.NOT_FOUND_404,
319                     message = "Test case does not exist", response = VTPError.class)})
320     public Response getTestcase(
321             @ApiParam("Test scenario name") @PathParam("scenario") String scenario,
322             @ApiParam(value = "Test case name") @PathParam("testSuiteName") String testSuiteName,
323             @ApiParam(value = "Test case name") @PathParam("testCaseName") String testCaseName)
324             throws VTPException {
325
326         return Response.ok(this.getTestcaseHandler(scenario, testSuiteName, testCaseName).toString(), MediaType.APPLICATION_JSON).build();
327     }
328
329     @Path("/scenarios")
330     @POST
331     @ApiOperation(tags = "VTP Scenario", value = "Create Scenario")
332     @Consumes(MediaType.MULTIPART_FORM_DATA)
333     @Produces(MediaType.APPLICATION_JSON)
334     @ApiResponses(value = {
335             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)})
336     public Response storageScenarios(@ApiParam(value = "file form data body parts", required = true)
337                                      @FormDataParam("files") List<FormDataBodyPart> bodyParts) throws VTPException {
338         bodyParts.forEach(bodyPart -> {
339             BodyPartEntity entity = (BodyPartEntity) bodyPart.getEntity();
340             String fileName = bodyPart.getContentDisposition().getFileName();
341             if (!ToolUtil.isYamlFile(new File(fileName))) {
342                 LOG.error("The fileName {} is not yaml !!!", fileName);
343                 return;
344             }
345             String scenario = fileName.substring(0, fileName.indexOf("-registry"));
346             File scenarioDir = new File(VTP_YAML_STORE, scenario);
347             File yamlFile = new File(VTP_YAML_STORE, fileName);
348
349             // 1、store the scenario yaml file and create the scenario dir
350             try {
351                 FileUtils.deleteQuietly(yamlFile);
352                 FileUtils.deleteDirectory(scenarioDir);
353                 FileUtils.forceMkdir(scenarioDir);
354                 FileUtils.copyInputStreamToFile(entity.getInputStream(), yamlFile);
355             } catch (IOException e) {
356                 LOG.error("Save yaml {} failed", fileName, e);
357             }
358
359             // 2、create the testsuits dir and copy the testcase to current scenarios by commands
360             try {
361                 Map<String, Object> yamlInfos = Maps.newHashMap();
362                 try (FileReader fileReader = new FileReader(yamlFile)) {
363                     yamlInfos = snakeYaml().load(fileReader);
364                 }
365                 for (Object service : (List) yamlInfos.get("services")) {
366                     processCurrentScenarioCommands(scenario, scenarioDir, service);
367                 }
368             } catch (Exception e) {
369                 LOG.error("Parse testcase yaml failed !!!", e);
370             }
371         });
372         return Response.ok("Save yaml success", MediaType.APPLICATION_JSON).build();
373     }
374
375         private void processCurrentScenarioCommands(String scenario, File scenarioDir, Object service)
376                         throws IOException, FileNotFoundException {
377                 Map<String, Object> serviceMap = (Map<String, Object>) service;
378                 String testsuite = serviceMap.get("name").toString();
379                 File testsuiteDir = new File(scenarioDir, testsuite);
380                 FileUtils.forceMkdir(testsuiteDir);
381                 if (!serviceMap.containsKey("commands")) {
382                     return;
383                 }
384                 for (Object cmd : (List) serviceMap.get("commands")) {
385                     File source = new File(VTP_YAML_STORE, cmd.toString().replaceAll("::", Matcher.quoteReplacement(File.separator)));
386                     if (!source.isFile()) {
387                         LOG.error("Source {} is not a yaml file !!!", source.getName());
388                         continue;
389                     }
390                     File dest = new File(testsuiteDir, cmd.toString().substring(cmd.toString().lastIndexOf("::") + 2));
391                     FileUtils.copyFile(source, dest);
392
393                     // 3、modify the testcase scenario and testsuite
394                     Map<String, Object> result = Maps.newHashMap();
395                     try (FileReader fileReader = new FileReader(dest)) {
396                         result = snakeYaml().load(fileReader);
397                     }
398                     Map<String, Object> info = (Map<String, Object>) result.get("info");
399                     info.put(PRODUCT, scenario);
400                     info.put(SERVICE, testsuite);
401                     try (FileWriter fileWriter = new FileWriter(dest)) {
402                         snakeYaml().dump(result, fileWriter);
403                     }
404                 }
405         }
406
407
408     @Path("/scenarios/{scenarioName}")
409     @DELETE
410     @ApiOperation(tags = "VTP Scenario", value = "Delete yaml string")
411     @Produces(MediaType.APPLICATION_JSON)
412     @ApiResponses(value = {
413             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)})
414     public Response deleteScenario(@ApiParam("Test scenario yaml") @PathParam("scenarioName") String scenarioName) throws VTPException {
415         String scenario = scenarioName.substring(0, scenarioName.indexOf("-registry"));
416         File scenarioDir = new File(VTP_YAML_STORE, scenario);
417         List<File> yamls =  FileUtil.searchFiles(scenarioDir, CommonConstant.YAML_SUFFIX);
418         if (!CollectionUtils.isEmpty(yamls)) {
419             LOG.error("The scenario yaml {} has sub testcase yamls, delete failed", scenarioName);
420             throw new VTPException(
421                     new VTPError().setMessage(MessageFormat.format("The scenario yaml {0} has sub testcase yamls, delete failed !!!", scenarioName))
422                             .setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR_500));
423         }
424
425         try {
426             FileUtils.deleteQuietly(new File(VTP_YAML_STORE, scenarioName));
427             FileUtils.deleteDirectory(scenarioDir);
428         } catch (IOException e) {
429             LOG.error("Delete scenario yaml {} failed", scenarioName, e);
430             throw new VTPException(
431                     new VTPError().setMessage("Delete yaml failed !!!").setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR_500));
432         }
433         return Response.ok("Delete yaml success", MediaType.APPLICATION_JSON).build();
434     }
435
436     @Path("/testcases")
437     @POST
438     @ApiOperation(tags = "VTP Scenario", value = "Create test case")
439     @Consumes(MediaType.MULTIPART_FORM_DATA)
440     @Produces(MediaType.APPLICATION_JSON)
441     @ApiResponses(value = {
442             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)})
443     public Response storageTestcases(@ApiParam(value = "file form data body parts", required = true)
444                                      @FormDataParam("files") List<FormDataBodyPart> bodyParts) throws VTPException {
445         bodyParts.forEach(bodyPart -> {
446             BodyPartEntity entity = (BodyPartEntity) bodyPart.getEntity();
447             String fileName = bodyPart.getContentDisposition().getFileName();
448             if (ToolUtil.isYamlFile(new File(fileName))) {
449                 // 1、store the testcase yaml file
450                 Map<String, Object> result = snakeYaml().load(entity.getInputStream());
451                 Map<String, Object> info = (Map<String, Object>) result.get("info");
452
453                 File yamlFile = new File(VTP_YAML_STORE, info.get(PRODUCT) + File.separator + info.get(SERVICE) + File.separator + fileName);
454                 try {
455                     FileUtils.deleteQuietly(yamlFile);
456                     FileUtils.copyInputStreamToFile(entity.getInputStream(), yamlFile);
457                 } catch (IOException e) {
458                     LOG.error("Save testcase yaml {} failed", yamlFile.getName(), e);
459                 }
460             } else {
461                 // 2、store the testcase script file
462                 File scriptFile = new File(VTP_SCRIPT_STORE, fileName);
463                 try {
464                     FileUtils.deleteQuietly(scriptFile);
465                     FileUtils.copyInputStreamToFile(entity.getInputStream(), scriptFile);
466                 } catch (IOException e) {
467                     LOG.error("Save testcase script {} failed", scriptFile.getName(), e);
468                 }
469             }
470         });
471         return Response.ok("Save success", MediaType.APPLICATION_JSON).build();
472     }
473 }