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.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;
30 import java.util.regex.Matcher;
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;
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;
66 import com.google.gson.JsonArray;
67 import com.google.gson.JsonElement;
68 import com.google.gson.JsonObject;
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;
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<>();
90 args.addAll(Arrays.asList(
91 PRODUCT_ARG, OPEN_CLI, "product-list", FORMAT, "json"
95 JsonElement results = null;
97 String endPoint="/manager/scenarios";
98 return distManagerVtpScenarioResource.getScenarioListFromManager(endPoint);
102 results = this.makeRpcAndGetJson(args);
103 } catch (IOException e) {
104 LOG.error(IO_EXCEPTION_OCCURS, e);
108 VTPTestScenarioList list = new VTPTestScenarioList();
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();
118 if (OPEN_CLI.equalsIgnoreCase(name))
121 list.getScenarios().add(new VTPTestScenario().setName(name).setDescription(
122 n.get(DESCRIPTION).getAsString()));
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();
142 public VTPTestSuiteList listTestSutiesHandler(String scenario) throws VTPException {
143 List<String> args = new ArrayList<>();
145 args.addAll(Arrays.asList(
146 PRODUCT_ARG, OPEN_CLI, "service-list", PRODUCT_ARG, scenario, FORMAT, "json"
149 JsonElement results = null;
151 String url="/manager/scenarios/"+scenario+"/testsuites";
152 return distManagerVtpScenarioResource.getSuiteListFromManager(url);
155 results = this.makeRpcAndGetJson(args);
156 } catch (IOException e) {
157 LOG.error(IO_EXCEPTION_OCCURS,e);
161 VTPTestSuiteList list = new VTPTestSuiteList();
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()));
178 @Path("/scenarios/{scenario}/testsuites")
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 {
189 return Response.ok(this.listTestSutiesHandler(scenario).getSuites().toString(), MediaType.APPLICATION_JSON).build();
192 public VTPTestCaseList listTestcasesHandler(String testSuiteName, String scenario) throws VTPException {
193 List<String> args = new ArrayList<>();
195 args.addAll(Arrays.asList(
196 PRODUCT_ARG, OPEN_CLI, "schema-list", PRODUCT_ARG, scenario, FORMAT, "json"
198 if (testSuiteName != null) {
199 args.add("--service");
200 args.add(testSuiteName);
203 JsonElement results = null;
205 String url = "/manager/scenarios/" + scenario + "/testcases";
206 return distManagerVtpScenarioResource.getTestCaseListFromManager(url);
209 results = this.makeRpcAndGetJson(args);
210 } catch (IOException e) {
211 LOG.error(IO_EXCEPTION_OCCURS, e);
215 VTPTestCaseList list = new VTPTestCaseList();
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()));
233 @Path("/scenarios/{scenario}/testcases")
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 {
246 return Response.ok(this.listTestcasesHandler(testSuiteName, scenario).getTestCases().toString(), MediaType.APPLICATION_JSON).build();
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"
254 JsonElement results = null;
256 results = this.makeRpcAndGetJson(args);
257 } catch (IOException e) {
258 LOG.error(IO_EXCEPTION_OCCURS,e);
261 JsonObject schema = results.getAsJsonObject().getAsJsonObject("schema");
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);
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());
282 tc.getOutputs().add(output);
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();
294 input.setName(inputJson.get("name").getAsString());
295 input.setDescription(inputJson.get(DESCRIPTION).getAsString());
296 input.setType(inputJson.get("type").getAsString());
298 if (inputJson.get("is_optional") != null)
299 input.setIsOptional(inputJson.get("is_optional").getAsBoolean());
301 if (inputJson.get("default_value") != null)
302 input.setDefaultValue(inputJson.get("default_value").getAsString());
304 if (inputJson.get("metadata") != null)
305 input.setMetadata(inputJson.get("metadata"));
307 tc.getInputs().add(input);
311 @Path("/scenarios/{scenario}/testsuites/{testSuiteName}/testcases/{testCaseName}")
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 {
326 return Response.ok(this.getTestcaseHandler(scenario, testSuiteName, testCaseName).toString(), MediaType.APPLICATION_JSON).build();
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);
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);
349 // 1、store the scenario yaml file and create the scenario dir
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);
359 // 2、create the testsuits dir and copy the testcase to current scenarios by commands
361 Map<String, Object> yamlInfos = Maps.newHashMap();
362 try (FileReader fileReader = new FileReader(yamlFile)) {
363 yamlInfos = snakeYaml().load(fileReader);
365 for (Object service : (List) yamlInfos.get("services")) {
366 processCurrentScenarioCommands(scenario, scenarioDir, service);
368 } catch (Exception e) {
369 LOG.error("Parse testcase yaml failed !!!", e);
372 return Response.ok("Save yaml success", MediaType.APPLICATION_JSON).build();
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")) {
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());
390 File dest = new File(testsuiteDir, cmd.toString().substring(cmd.toString().lastIndexOf("::") + 2));
391 FileUtils.copyFile(source, dest);
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);
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);
408 @Path("/scenarios/{scenarioName}")
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));
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));
433 return Response.ok("Delete yaml success", MediaType.APPLICATION_JSON).build();
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");
453 File yamlFile = new File(VTP_YAML_STORE, info.get(PRODUCT) + File.separator + info.get(SERVICE) + File.separator + fileName);
455 FileUtils.deleteQuietly(yamlFile);
456 FileUtils.copyInputStreamToFile(entity.getInputStream(), yamlFile);
457 } catch (IOException e) {
458 LOG.error("Save testcase yaml {} failed", yamlFile.getName(), e);
461 // 2、store the testcase script file
462 File scriptFile = new File(VTP_SCRIPT_STORE, fileName);
464 FileUtils.deleteQuietly(scriptFile);
465 FileUtils.copyInputStreamToFile(entity.getInputStream(), scriptFile);
466 } catch (IOException e) {
467 LOG.error("Save testcase script {} failed", scriptFile.getName(), e);
471 return Response.ok("Save success", MediaType.APPLICATION_JSON).build();