2 * Copyright 2018 Huawei Technologies Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.onap.vtp.scenario;
20 import java.io.FileReader;
21 import java.io.FileWriter;
22 import java.io.IOException;
23 import java.text.MessageFormat;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Iterator;
27 import java.util.List;
29 import java.util.regex.Matcher;
31 import javax.ws.rs.Consumes;
32 import javax.ws.rs.DELETE;
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;
42 import com.google.common.collect.Maps;
43 import org.apache.commons.io.FileUtils;
44 import org.apache.cxf.common.util.CollectionUtils;
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.vnfsdk.marketplace.common.CommonConstant;
50 import org.onap.vnfsdk.marketplace.common.FileUtil;
51 import org.onap.vnfsdk.marketplace.common.ToolUtil;
52 import org.onap.vtp.VTPResource;
53 import org.onap.vtp.error.VTPError;
54 import org.onap.vtp.error.VTPError.VTPException;
55 import org.onap.vtp.scenario.model.VTPTestCase;
56 import org.onap.vtp.scenario.model.VTPTestScenario;
57 import org.onap.vtp.scenario.model.VTPTestSuite;
58 import org.onap.vtp.scenario.model.VTPTestCase.VTPTestCaseInput;
59 import org.onap.vtp.scenario.model.VTPTestCase.VTPTestCaseList;
60 import org.onap.vtp.scenario.model.VTPTestCase.VTPTestCaseOutput;
61 import org.onap.vtp.scenario.model.VTPTestScenario.VTPTestScenarioList;
62 import org.onap.vtp.scenario.model.VTPTestSuite.VTPTestSuiteList;
64 import com.google.gson.JsonArray;
65 import com.google.gson.JsonElement;
66 import com.google.gson.JsonObject;
68 import io.swagger.annotations.Api;
69 import io.swagger.annotations.ApiOperation;
70 import io.swagger.annotations.ApiParam;
71 import io.swagger.annotations.ApiResponse;
72 import io.swagger.annotations.ApiResponses;
75 @Api(tags = {"VTP Scenario"})
76 public class VTPScenarioResource extends VTPResource{
77 private static final String DESCRIPTION = "description";
78 private static final String PRODUCT_ARG="--product";
79 private static final String OPEN_CLI="open-cli";
80 private static final String FORMAT="--format";
81 private static final String IO_EXCEPTION_OCCURS ="IOException occurs";
82 private static final String SERVICE="service";
83 public VTPTestScenarioList listTestScenariosHandler() throws VTPException {
84 List<String> args = new ArrayList<>();
86 args.addAll(Arrays.asList(
87 PRODUCT_ARG, OPEN_CLI, "product-list", FORMAT, "json"
91 JsonElement results = null;
93 results = this.makeRpcAndGetJson(args);
94 } catch (IOException e) {
95 LOG.error(IO_EXCEPTION_OCCURS,e);
98 VTPTestScenarioList list = new VTPTestScenarioList();
100 if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) {
101 JsonArray resultsArray = results.getAsJsonArray();
102 for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
103 JsonElement jsonElement = it.next();
104 JsonObject n = jsonElement.getAsJsonObject();
105 if (n.entrySet().iterator().hasNext()) {
106 String name = n.get("product").getAsString();
108 if (OPEN_CLI.equalsIgnoreCase(name))
111 list.getScenarios().add(new VTPTestScenario().setName(name).setDescription(
112 n.get(DESCRIPTION).getAsString()));
122 @ApiOperation(tags = "VTP Scenario", value = " List available test scenarios", response = VTPTestScenario.class, responseContainer = "List")
123 @Produces(MediaType.APPLICATION_JSON)
124 @ApiResponses(value = {
125 @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
126 message = "Failed to perform the operation",
127 response = VTPError.class) })
128 public Response listTestScenarios() throws VTPException {
129 return Response.ok(this.listTestScenariosHandler().getScenarios().toString(), MediaType.APPLICATION_JSON).build();
132 public VTPTestSuiteList listTestSutiesHandler(String scenario) throws VTPException {
133 List<String> args = new ArrayList<>();
135 args.addAll(Arrays.asList(
136 PRODUCT_ARG, OPEN_CLI, "service-list", PRODUCT_ARG, scenario, FORMAT, "json"
139 JsonElement results = null;
141 results = this.makeRpcAndGetJson(args);
142 } catch (IOException e) {
143 LOG.error(IO_EXCEPTION_OCCURS,e);
146 VTPTestSuiteList list = new VTPTestSuiteList();
148 if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) {
149 JsonArray resultsArray = results.getAsJsonArray();
150 for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
151 JsonElement jsonElement = it.next();
152 JsonObject n = jsonElement.getAsJsonObject();
153 if (n.entrySet().iterator().hasNext()) {
154 list.getSuites().add(new VTPTestSuite().setName(n.get(SERVICE).getAsString()).setDescription(
155 n.get(DESCRIPTION).getAsString()));
163 @Path("/scenarios/{scenario}/testsuites")
165 @ApiOperation(tags = "VTP Scenario", value = " List available test suties in given scenario", response = VTPTestSuite.class, responseContainer = "List")
166 @Produces(MediaType.APPLICATION_JSON)
167 @ApiResponses(value = {
168 @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
169 message = "Failed to perform the operation",
170 response = VTPError.class) })
171 public Response listTestSuties(
172 @ApiParam("Test scenario name") @PathParam("scenario") String scenario) throws VTPException {
174 return Response.ok(this.listTestSutiesHandler(scenario).getSuites().toString(), MediaType.APPLICATION_JSON).build();
177 public VTPTestCaseList listTestcasesHandler(String testSuiteName, String scenario) throws VTPException {
178 List<String> args = new ArrayList<>();
180 args.addAll(Arrays.asList(
181 PRODUCT_ARG, OPEN_CLI, "schema-list", PRODUCT_ARG, scenario, FORMAT, "json"
183 if (testSuiteName != null) {
184 args.add("--service");
185 args.add(testSuiteName);
188 JsonElement results = null;
190 results = this.makeRpcAndGetJson(args);
191 } catch (IOException e) {
192 LOG.error(IO_EXCEPTION_OCCURS,e);
195 VTPTestCaseList list = new VTPTestCaseList();
197 if (results != null && results.isJsonArray() && results.getAsJsonArray().size()>0) {
198 JsonArray resultsArray = results.getAsJsonArray();
199 for (Iterator<JsonElement> it = resultsArray.iterator(); it.hasNext();) {
200 JsonElement jsonElement = it.next();
201 JsonObject n = jsonElement.getAsJsonObject();
202 if (n.entrySet().iterator().hasNext())
203 list.getTestCases().add(
204 new VTPTestCase().setTestCaseName(
205 n.get("command").getAsString()).setTestSuiteName(
206 n.get(SERVICE).getAsString()));
213 @Path("/scenarios/{scenario}/testcases")
215 @ApiOperation(tags = "VTP Scenario", value = " List available test cases", response = VTPTestCase.class, responseContainer = "List")
216 @Produces(MediaType.APPLICATION_JSON)
217 @ApiResponses(value = {
218 @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
219 message = "Failed to perform the operation",
220 response = VTPError.class) })
221 public Response listTestcases(
222 @ApiParam("Test scenario name") @PathParam("scenario") String scenario,
223 @ApiParam("Test suite name") @QueryParam("testSuiteName") String testSuiteName
224 ) throws VTPException {
226 return Response.ok(this.listTestcasesHandler(testSuiteName, scenario).getTestCases().toString(), MediaType.APPLICATION_JSON).build();
229 public VTPTestCase getTestcaseHandler(String scenario, String testSuiteName, String testCaseName) throws VTPException {
230 List<String> args = new ArrayList<>();
231 args.addAll(Arrays.asList(
232 PRODUCT_ARG, OPEN_CLI, "schema-show", PRODUCT_ARG, scenario, "--service", testSuiteName, "--command", testCaseName , FORMAT, "json"
234 JsonElement results = null;
236 results = this.makeRpcAndGetJson(args);
237 } catch (IOException e) {
238 LOG.error(IO_EXCEPTION_OCCURS,e);
241 JsonObject schema = results.getAsJsonObject().getAsJsonObject("schema");
243 VTPTestCase tc = new VTPTestCase();
244 tc.setTestCaseName(schema.get("name").getAsString());
245 tc.setDescription(schema.get(DESCRIPTION).getAsString());
246 tc.setTestSuiteName(schema.get(SERVICE).getAsString());
247 tc.setAuthor(schema.get("author").getAsString());
248 JsonElement inputsJson = schema.get("inputs");
249 if (inputsJson != null && inputsJson.isJsonArray()) {
250 for (final JsonElement jsonElement: inputsJson.getAsJsonArray()) {
251 JsonObject inputJson = jsonElement.getAsJsonObject();
252 VTPTestCaseInput input = new VTPTestCaseInput();
254 input.setName(inputJson.get("name").getAsString());
255 input.setDescription(inputJson.get(DESCRIPTION).getAsString());
256 input.setType(inputJson.get("type").getAsString());
258 if (inputJson.get("is_optional") != null)
259 input.setIsOptional(inputJson.get("is_optional").getAsBoolean());
261 if (inputJson.get("default_value") != null)
262 input.setDefaultValue(inputJson.get("default_value").getAsString());
264 if (inputJson.get("metadata") != null)
265 input.setMetadata(inputJson.get("metadata"));
267 tc.getInputs().add(input);
271 JsonElement outputsJson = schema.get("outputs");
272 if (outputsJson != null && outputsJson.isJsonArray() && outputsJson.getAsJsonArray().size()>0) {
273 for (final JsonElement jsonElement: outputsJson.getAsJsonArray()) {
274 JsonObject outputJson = jsonElement.getAsJsonObject();
275 VTPTestCaseOutput output = new VTPTestCaseOutput();
276 output.setName(outputJson.get("name").getAsString());
277 output.setDescription(outputJson.get(DESCRIPTION).getAsString());
278 output.setType(outputJson.get("type").getAsString());
280 tc.getOutputs().add(output);
287 @Path("/scenarios/{scenario}/testsuites/{testSuiteName}/testcases/{testCaseName}")
289 @ApiOperation(tags = "VTP Scenario", value = "Retrieve test cases details like inputs outputs and test suite name", response = VTPTestCase.class)
290 @Produces(MediaType.APPLICATION_JSON)
291 @ApiResponses(value = {
292 @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500,
293 message = "Failed to perform the operation", response = VTPError.class),
294 @ApiResponse(code = HttpStatus.NOT_FOUND_404,
295 message = "Test case does not exist", response = VTPError.class)})
296 public Response getTestcase(
297 @ApiParam("Test scenario name") @PathParam("scenario") String scenario,
298 @ApiParam(value = "Test case name") @PathParam("testSuiteName") String testSuiteName,
299 @ApiParam(value = "Test case name") @PathParam("testCaseName") String testCaseName)
300 throws VTPException {
302 return Response.ok(this.getTestcaseHandler(scenario, testSuiteName, testCaseName).toString(), MediaType.APPLICATION_JSON).build();
307 @ApiOperation(tags = "VTP Scenario", value = "Create Scenario")
308 @Consumes(MediaType.MULTIPART_FORM_DATA)
309 @Produces(MediaType.APPLICATION_JSON)
310 @ApiResponses(value = {
311 @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)})
312 public Response storageScenarios(@ApiParam(value = "file form data body parts", required = true)
313 @FormDataParam("files") List<FormDataBodyPart> bodyParts) throws VTPException {
314 bodyParts.forEach(bodyPart -> {
315 BodyPartEntity entity = (BodyPartEntity) bodyPart.getEntity();
316 String fileName = bodyPart.getContentDisposition().getFileName();
317 if (!ToolUtil.isYamlFile(new File(fileName))) {
318 LOG.error("The fileName {} is not yaml !!!", fileName);
321 String scenario = fileName.substring(0, fileName.indexOf("-registry"));
322 File scenarioDir = new File(VTP_YAML_STORE, scenario);
323 File yamlFile = new File(VTP_YAML_STORE, fileName);
325 // 1、store the scenario yaml file and create the scenario dir
327 FileUtils.deleteQuietly(yamlFile);
328 FileUtils.deleteDirectory(scenarioDir);
329 FileUtils.forceMkdir(scenarioDir);
330 FileUtils.copyInputStreamToFile(entity.getInputStream(), yamlFile);
331 } catch (IOException e) {
332 LOG.error("Save yaml {} failed", fileName, e);
335 // 2、create the testsuits dir and copy the testcase to current scenarios by commands
337 Map<String, Object> yamlInfos = Maps.newHashMap();
338 try (FileReader fileReader = new FileReader(yamlFile)) {
339 yamlInfos = snakeYaml().load(fileReader);
341 for (Object service : (List) yamlInfos.get("services")) {
342 Map<String, Object> serviceMap = (Map<String, Object>) service;
343 String testsuite = serviceMap.get("name").toString();
344 File testsuiteDir = new File(scenarioDir, testsuite);
345 FileUtils.forceMkdir(testsuiteDir);
346 if (!serviceMap.containsKey("commands")) {
349 for (Object cmd : (List) serviceMap.get("commands")) {
350 File source = new File(VTP_YAML_STORE, cmd.toString().replaceAll("::", Matcher.quoteReplacement(File.separator)));
351 if (!source.isFile()) {
352 LOG.error("Source {} is not a yaml file !!!", source.getName());
355 File dest = new File(testsuiteDir, cmd.toString().substring(cmd.toString().lastIndexOf("::") + 2));
356 FileUtils.copyFile(source, dest);
358 // 3、modify the testcase scenario and testsuite
359 Map<String, Object> result = Maps.newHashMap();
360 try (FileReader fileReader = new FileReader(dest)) {
361 result = snakeYaml().load(fileReader);
363 Map<String, Object> info = (Map<String, Object>) result.get("info");
364 info.put("product", scenario);
365 info.put("service", testsuite);
366 try (FileWriter fileWriter = new FileWriter(dest)) {
367 snakeYaml().dump(result, fileWriter);
371 } catch (Exception e) {
372 LOG.error("Parse testcase yaml failed !!!", e);
375 return Response.ok("Save yaml success", MediaType.APPLICATION_JSON).build();
379 @Path("/scenarios/{scenarioName}")
381 @ApiOperation(tags = "VTP Scenario", value = "Delete yaml string")
382 @Produces(MediaType.APPLICATION_JSON)
383 @ApiResponses(value = {
384 @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Failed to perform the operation", response = VTPError.class)})
385 public Response deleteScenario(@ApiParam("Test scenario yaml") @PathParam("scenarioName") String scenarioName) throws VTPException {
386 String scenario = scenarioName.substring(0, scenarioName.indexOf("-registry"));
387 File scenarioDir = new File(VTP_YAML_STORE, scenario);
388 List<File> yamls = FileUtil.searchFiles(scenarioDir, CommonConstant.YAML_SUFFIX);
389 if (!CollectionUtils.isEmpty(yamls)) {
390 LOG.error("The scenario yaml {} has sub testcase yamls, delete failed", scenarioName);
391 throw new VTPException(
392 new VTPError().setMessage(MessageFormat.format("The scenario yaml {0} has sub testcase yamls, delete failed !!!", scenarioName))
393 .setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR_500));
397 FileUtils.deleteQuietly(new File(VTP_YAML_STORE, scenarioName));
398 FileUtils.deleteDirectory(scenarioDir);
399 } catch (IOException e) {
400 LOG.error("Delete scenario yaml {} failed", scenarioName, e);
401 throw new VTPException(
402 new VTPError().setMessage("Delete yaml failed !!!").setHttpStatus(HttpStatus.INTERNAL_SERVER_ERROR_500));
404 return Response.ok("Delete yaml success", MediaType.APPLICATION_JSON).build();
409 @ApiOperation(tags = "VTP Scenario", value = "Create test case")
410 @Consumes(MediaType.MULTIPART_FORM_DATA)
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 storageTestcases(@ApiParam(value = "file form data body parts", required = true)
415 @FormDataParam("files") List<FormDataBodyPart> bodyParts) throws VTPException {
416 bodyParts.forEach(bodyPart -> {
417 BodyPartEntity entity = (BodyPartEntity) bodyPart.getEntity();
418 String fileName = bodyPart.getContentDisposition().getFileName();
419 if (ToolUtil.isYamlFile(new File(fileName))) {
420 // 1、store the testcase yaml file
421 Map<String, Object> result = snakeYaml().load(entity.getInputStream());
422 Map<String, Object> info = (Map<String, Object>) result.get("info");
424 File yamlFile = new File(VTP_YAML_STORE, info.get("product") + File.separator + info.get("service") + File.separator + fileName);
426 FileUtils.deleteQuietly(yamlFile);
427 FileUtils.copyInputStreamToFile(entity.getInputStream(), yamlFile);
428 } catch (IOException e) {
429 LOG.error("Save testcase yaml {} failed", yamlFile.getName(), e);
432 // 2、store the testcase script file
433 File scriptFile = new File(VTP_SCRIPT_STORE, fileName);
435 FileUtils.deleteQuietly(scriptFile);
436 FileUtils.copyInputStreamToFile(entity.getInputStream(), scriptFile);
437 } catch (IOException e) {
438 LOG.error("Save testcase script {} failed", scriptFile.getName(), e);
442 return Response.ok("Save success", MediaType.APPLICATION_JSON).build();