diff options
author | Bartosz Gardziejewski <bartosz.gardziejewski@nokia.com> | 2021-05-06 10:14:57 +0200 |
---|---|---|
committer | Bartosz Gardziejewski <bartosz.gardziejewski@nokia.com> | 2021-05-06 10:52:21 +0200 |
commit | 0fce7537299e6af0d2b1fdb1d5c01654ce9573c0 (patch) | |
tree | eb7e726f921fe96738443be684bc77e05f6d76c5 /dictionaryvalidation/src/main | |
parent | 1ff8bc0e7475934c1ad463571444d7b46c7b5761 (diff) |
Rename PM_Dictionary_Validator to Dictionary_Validatoristanbul
Signed-off-by: Bartosz Gardziejewski <bartosz.gardziejewski@nokia.com>
Change-Id: Icb65e6f832804aa4a958e530422d35e079ffe3c1
Issue-ID: VNFSDK-769
Diffstat (limited to 'dictionaryvalidation/src/main')
36 files changed, 1928 insertions, 0 deletions
diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/Main.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/Main.java new file mode 100644 index 0000000..ddeecbf --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/Main.java @@ -0,0 +1,48 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli; + +import org.onap.validation.cli.command.validate.ResponseStorage; +import org.onap.validation.cli.command.validate.ToJsonConverter; +import org.onap.validation.cli.command.validate.ValidateDictionaryYamlCommand; +import org.onap.validation.cli.core.Cli; +import org.onap.validation.cli.core.Console; +import org.onap.validation.yaml.util.Args; + +import java.util.List; + +public class Main { + + public static void main(String[] args) { + final Console console = new Console(); + final ResponseStorage storage = new ResponseStorage(); + + System.exit( + run(args, console, storage) + ); + } + + static int run(String[] args, Console console, ResponseStorage responseStorage) { + + Cli<String> cli = new Cli<>(console, responseStorage); + + return cli.run( + new Args(List.of(args)), + new ValidateDictionaryYamlCommand(new ToJsonConverter()) + ); + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/OutputFilePathGenerator.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/OutputFilePathGenerator.java new file mode 100644 index 0000000..2ed7285 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/OutputFilePathGenerator.java @@ -0,0 +1,41 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.command.validate; + +import java.nio.file.Path; + +public class OutputFilePathGenerator { + + public static final int FILE_NAME_ABBREVIATION_INDEX = 0; + public static final String BY_PERIOD_REGEX = "\\."; + public static final String POST_FIX = "-validation-results.json"; + + public Path responsePathFor(Path filePath) { + final Path parent = filePath.getParent(); + final String fileNameAbbreviation = getFileNameAbbreviation(filePath); + return Path.of(parent.toString(), createFileName(fileNameAbbreviation)); + } + + private String createFileName(String fileNameAbbreviation) { + return fileNameAbbreviation + POST_FIX; + } + + private String getFileNameAbbreviation(Path filePath) { + final Path fileName = filePath.getFileName(); + return fileName.toString().split(BY_PERIOD_REGEX)[FILE_NAME_ABBREVIATION_INDEX]; + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ResponseModel.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ResponseModel.java new file mode 100644 index 0000000..033031d --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ResponseModel.java @@ -0,0 +1,51 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.command.validate; + +import org.onap.validation.yaml.error.YamlDocumentValidationError; + +import java.util.Collections; +import java.util.List; + +public class ResponseModel { + + private final String file; + private final ResponseStatus status; + private final List<YamlDocumentValidationError> errors; + + public ResponseModel(String file, ResponseStatus status, List<YamlDocumentValidationError> errors) { + this.file = file; + this.status = status; + this.errors = errors; + } + + public String getFile() { + return file; + } + + public List<YamlDocumentValidationError> getErrors() { + return Collections.unmodifiableList(errors); + } + + public ResponseStatus getStatus() { + return status; + } + + public enum ResponseStatus { + PASS, FAILED + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ResponseStorage.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ResponseStorage.java new file mode 100644 index 0000000..3daed16 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ResponseStorage.java @@ -0,0 +1,30 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.command.validate; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; + +public class ResponseStorage{ + + public <T> void store(Path filePath, T response) throws IOException { + try (PrintWriter out = new PrintWriter(filePath.toFile())) { + out.println(response); + } + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ToJsonConverter.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ToJsonConverter.java new file mode 100644 index 0000000..168daf8 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ToJsonConverter.java @@ -0,0 +1,28 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.command.validate; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + + +public class ToJsonConverter { + public String convert(ResponseModel responseModel) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + return gson.toJson(responseModel); + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ToResponseModelConverter.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ToResponseModelConverter.java new file mode 100644 index 0000000..674068f --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ToResponseModelConverter.java @@ -0,0 +1,31 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.command.validate; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public final class ToResponseModelConverter { + + private ToResponseModelConverter() { + } + + public static ResponseModel toModel(String json) { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + return gson.fromJson(json, ResponseModel.class); + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ValidateDictionaryYamlCommand.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ValidateDictionaryYamlCommand.java new file mode 100644 index 0000000..68b0b7a --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/command/validate/ValidateDictionaryYamlCommand.java @@ -0,0 +1,92 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.command.validate; + +import org.onap.validation.cli.core.Command; +import org.onap.validation.cli.core.CommandException; +import org.onap.validation.cli.core.CommandResponse; +import org.onap.validation.yaml.YamlContentValidator; +import org.onap.validation.yaml.error.YamlDocumentValidationError; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.util.Args; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +public class ValidateDictionaryYamlCommand implements Command<String> { + + public static final int PATH_TO_FILE_INDEX = 0; + private final YamlContentValidator yamlContentValidator = new YamlContentValidator(); + + private final ToJsonConverter toJsonConverter; + private final OutputFilePathGenerator filePathGenerator = new OutputFilePathGenerator(); + + public ValidateDictionaryYamlCommand(ToJsonConverter toJsonConverter) { + this.toJsonConverter = toJsonConverter; + } + + @Override + public CommandResponse<String> execute(Args args) throws CommandException { + final String pathToFile = resolvePathToFile(args); + + try { + return validate(pathToFile); + } catch (YamlProcessingException e) { + throw new CommandException("Provided yaml file has invalid structure!", e); + } + } + + @Override + public String getName() { + return "Validate Dictionary yaml"; + } + + @Override + public Path getOutputFilePath(Args args) throws CommandException { + final String pathToFile = resolvePathToFile(args); + return this.filePathGenerator.responsePathFor(Path.of(pathToFile)); + } + + private CommandResponse<String> validate(String pathToFile) throws YamlProcessingException { + final List<YamlDocumentValidationError> errors = yamlContentValidator.validate(pathToFile); + return new CommandResponse<>( + toJsonConverter.convert(new ResponseModel(pathToFile, resolveResponseStatus(errors), errors)) + ,resolveCommandStatus(errors) + ); + } + + private ResponseModel.ResponseStatus resolveResponseStatus(List<YamlDocumentValidationError> errors) { + return errors.isEmpty() ? ResponseModel.ResponseStatus.PASS : ResponseModel.ResponseStatus.FAILED; + } + + private CommandResponse.CommandStatus resolveCommandStatus(List<YamlDocumentValidationError> errors) { + return errors.isEmpty() ? CommandResponse.CommandStatus.PASS : CommandResponse.CommandStatus.FAILED; + } + + private String resolvePathToFile(Args args) throws CommandException { + try { + final String pathToFile = args.getArg(PATH_TO_FILE_INDEX); + if (!Files.exists(Path.of(pathToFile))) { + throw new CommandException(String.format("File '%s' does not exist!", pathToFile)); + } + return pathToFile; + } catch (IllegalArgumentException ex) { + throw new CommandException("Command argument is missing: provide a path to file", ex); + } + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/Cli.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/Cli.java new file mode 100644 index 0000000..bf2abad --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/Cli.java @@ -0,0 +1,85 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.core; + +import org.onap.validation.cli.command.validate.ResponseStorage; +import org.onap.validation.cli.core.CommandResponse.CommandStatus; +import org.onap.validation.yaml.util.Args; + +import java.nio.file.Path; + +public class Cli<T> { + + public static final int INTERNAL_ERROR_STATUS_CODE = 2; + public static final int FAILED_STATUS_CODE = 1; + public static final int PASS_STATUS_CODE = 0; + + public static final String APPLICATION_INTERNAL_ERROR_MSG = "\n# Application fails with internal error."; + public static final String APPLICATION_EXIT_SUCCESSFULLY_MSG = "\n# Application exits successfully."; + + private final Console console; + private final ResponseStorage responseStorage; + + public Cli(Console console, ResponseStorage responseStorage) { + this.console = console; + this.responseStorage = responseStorage; + } + + public int run(Args args, Command<T> command) { + try { + final CommandResponse<T> commandResponse = processCommand(args, command); + + logResultInfo(commandResponse.getResult()); + storeResult(args, command, commandResponse.getResult()); + + this.console.info(APPLICATION_EXIT_SUCCESSFULLY_MSG); + + return resolveCliStatusCodeFor(commandResponse); + } catch (Exception e) { + logException(e); + return INTERNAL_ERROR_STATUS_CODE; + } + } + + private int resolveCliStatusCodeFor(CommandResponse<T> commandResponse) { + return commandResponse.getCommandStatus() == CommandStatus.PASS ? PASS_STATUS_CODE : FAILED_STATUS_CODE; + } + + private void logException(Exception e) { + this.console.error("# Command error: "); + this.console.error(e); + this.console.error(APPLICATION_INTERNAL_ERROR_MSG); + } + + private void storeResult(Args args, Command<T> command, T result) throws CommandException, java.io.IOException { + final Path pathToFileWithResponse = command.getOutputFilePath(args); + this.responseStorage.store(pathToFileWithResponse, result); + this.console.info(String.format("%n# Result was stored in a file: '%s'", pathToFileWithResponse)); + } + + private void logResultInfo(T result) { + this.console.info("\n# Operation result:\n"); + this.console.info(result.toString()); + } + + private CommandResponse<T> processCommand(Args args, Command<T> command) throws CommandException { + this.console.info(String.format("# Executing a '%s' operation ...", command.getName())); + final CommandResponse<T> commandResponse = command.execute(args); + this.console.info("# ... Done."); + return commandResponse; + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/Command.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/Command.java new file mode 100644 index 0000000..1da724f --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/Command.java @@ -0,0 +1,29 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.core; + +import org.onap.validation.yaml.util.Args; + +import java.nio.file.Path; + +public interface Command<T> { + CommandResponse<T> execute(Args args) throws CommandException; + + String getName(); + + Path getOutputFilePath(Args args) throws CommandException; +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/CommandException.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/CommandException.java new file mode 100644 index 0000000..2c72ff8 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/CommandException.java @@ -0,0 +1,27 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.core; + +public class CommandException extends Exception { + public CommandException(String msg) { + super(msg); + } + + public CommandException(String msg, Exception ex) { + super(msg, ex); + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/CommandResponse.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/CommandResponse.java new file mode 100644 index 0000000..73db4ab --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/CommandResponse.java @@ -0,0 +1,48 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.core; + +public class CommandResponse<T> { + + private final T result; + private final CommandStatus commandStatus; + + public CommandResponse(T result, CommandStatus commandStatus) { + this.result = result; + this.commandStatus = commandStatus; + } + + public T getResult() { + return result; + } + + public CommandStatus getCommandStatus() { + return commandStatus; + } + + public enum CommandStatus { + PASS, FAILED + } + + @Override + public String toString() { + return "CommandResponse{" + + "result=" + result + + ", commandStatus=" + commandStatus + + '}'; + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/Console.java b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/Console.java new file mode 100644 index 0000000..4c20437 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/cli/core/Console.java @@ -0,0 +1,41 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.cli.core; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Console { + + public static final Logger logger = LoggerFactory.getLogger(Console.class); + + public void info(String msg) { + System.out.println(msg); + logger.info(msg); + } + + public void error(Exception ex) { + System.err.println(ex.getMessage() + ", more information in log file."); + logger.error("Internal error", ex); + } + + public void error(String msg) { + System.err.println(msg); + logger.error(msg); + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/rule/DictionaryValidate.java b/dictionaryvalidation/src/main/java/org/onap/validation/rule/DictionaryValidate.java new file mode 100644 index 0000000..c3b96b4 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/rule/DictionaryValidate.java @@ -0,0 +1,120 @@ +/* + * Copyright 2019 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onap.validation.rule; + +import com.google.gson.Gson; +import org.onap.cli.fw.cmd.OnapCommand; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.output.OnapCommandResultType; +import org.onap.cli.fw.schema.OnapCommandSchema; +import org.onap.validation.cli.command.validate.ResponseModel; +import org.onap.validation.cli.command.validate.ResponseModel.ResponseStatus; +import org.onap.validation.cli.command.validate.ToJsonConverter; +import org.onap.validation.cli.command.validate.ToResponseModelConverter; +import org.onap.validation.cli.command.validate.ValidateDictionaryYamlCommand; +import org.onap.validation.cli.core.CommandException; +import org.onap.validation.cli.core.CommandResponse; +import org.onap.validation.yaml.util.Args; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.List; + +/** + * Validates CSAR + */ +@OnapCommandSchema(schema = "dictionary-validate.yaml") +public class DictionaryValidate extends OnapCommand { + + private static final String VALIDATION_PASS = "PASS"; + private static final String VALIDATION_FAILED = "FAILED"; + public static final String PARAM_IN_YAML = "yaml"; + public static final String PARAM_OUT_FILE = "file"; + public static final String PARAM_OUT_DATE = "date"; + public static final String PARAM_OUT_CRITERIA = "criteria"; + public static final String PARAM_OUT_ERRORS = "errors"; + private final Gson gson = new Gson(); + + private static final Logger logger = LoggerFactory.getLogger(DictionaryValidate.class); + + @Override + protected void run() throws OnapCommandException { + + final Date timestamp = new Date(); + final String yamlPath = (String) getParametersMap().get(PARAM_IN_YAML).getValue(); + + try { + final ResponseModel responseModel = executeValidation(yamlPath); + handleResponse(responseModel, timestamp); + } catch (CommandException e) { + handleError(timestamp, yamlPath, e); + } + } + + private void handleResponse(ResponseModel responseModel, Date timestamp) { + setOclipResponse(responseModel.getFile(), + timestamp, + getCriteria(responseModel), + transformToJson(responseModel.getErrors()) + ); + } + + private void handleError(Date validationTimestamp, String path, CommandException e) { + setOclipResponse(path, + validationTimestamp, + VALIDATION_FAILED, + transformToJson(e.getMessage()) + ); + logger.error("Internal application error", e); + } + + private String getCriteria(ResponseModel responseModel) { + return responseModel.getStatus().equals(ResponseStatus.PASS) ? VALIDATION_PASS : VALIDATION_FAILED; + } + + private <T> String transformToJson(T data) { + return gson.toJson(data); + } + + private void setOclipResponse(String pathToFile, Date timestamp, String criteria, String errors) { + final DictionaryValidateResponse dictionaryValidateResponse = new DictionaryValidateResponse( + pathToFile, + timestamp.toString(), + criteria, + errors + ); + setOclipResponse(dictionaryValidateResponse); + } + + private void setOclipResponse(DictionaryValidateResponse dictionaryValidateResponse) { + this.getResult().getRecordsMap().get(PARAM_OUT_FILE).getValues().add(dictionaryValidateResponse.getFile()); + this.getResult().getRecordsMap().get(PARAM_OUT_DATE).getValues().add(dictionaryValidateResponse.getDate()); + this.getResult().getRecordsMap().get(PARAM_OUT_CRITERIA).getValues().add(dictionaryValidateResponse.getCriteria()); + this.getResult().getRecordsMap().get(PARAM_OUT_ERRORS).getValues().add(dictionaryValidateResponse.getErrors()); + this.getResult().setOutput(transformToJson(dictionaryValidateResponse)); + this.getResult().setType(OnapCommandResultType.TEXT); + } + + private ResponseModel executeValidation(String path) throws CommandException { + final ValidateDictionaryYamlCommand validation = new ValidateDictionaryYamlCommand(new ToJsonConverter()); + final CommandResponse<String> commandResponse = validation.execute(new Args(List.of(path))); + final String result = commandResponse.getResult(); + + return ToResponseModelConverter.toModel(result); + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/rule/DictionaryValidateResponse.java b/dictionaryvalidation/src/main/java/org/onap/validation/rule/DictionaryValidateResponse.java new file mode 100644 index 0000000..684cf7b --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/rule/DictionaryValidateResponse.java @@ -0,0 +1,57 @@ +/* + * Copyright 2019 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onap.validation.rule; + +public class DictionaryValidateResponse { + + public static final String PLATFORM_VTP_1_0 = "Dictionary Test Platform (VTP) 1.0"; + public static final String ONAP_DISCUSS_LISTS_ONAP_ORG = "ONAP VTP Team onap-discuss@lists.onap.org"; + private final String file; + private final String date; + private final String criteria; + private final String errors; + + public DictionaryValidateResponse(String file, String date, String criteria, String errors) { + this.file = file; + this.date = date; + this.criteria = criteria; + this.errors = errors; + } + + public String getFile() { + return file; + } + + public String getDate() { + return date; + } + + public String getContact() { + return ONAP_DISCUSS_LISTS_ONAP_ORG; + } + + public String getPlatform() { + return PLATFORM_VTP_1_0; + } + + public String getCriteria() { + return criteria; + } + + public String getErrors() { + return errors; + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/YamlContentValidator.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/YamlContentValidator.java new file mode 100644 index 0000000..4501113 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/YamlContentValidator.java @@ -0,0 +1,83 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml; + +import org.onap.validation.yaml.error.SchemaValidationError; +import org.onap.validation.yaml.error.YamlDocumentValidationError; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.model.YamlDocumentFactory; +import org.onap.validation.yaml.schema.YamlSchema; +import org.onap.validation.yaml.schema.YamlSchemaFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class YamlContentValidator { + + private static final int FIRST_DOCUMENT_INDEX = 1; + private static final YamlLoader YAML_LOADER = new YamlLoader(new YamlDocumentFactory()); + + public List<YamlDocumentValidationError> validate(String pathToFile) + throws YamlProcessingException { + List<YamlDocument> documents = YAML_LOADER.loadMultiDocumentYamlFile(pathToFile); + return getYamlDocumentValidationErrors(documents); + } + + public List<YamlDocumentValidationError> validate(byte[] yamlWithSchema) + throws YamlProcessingException { + List<YamlDocument> documents = YAML_LOADER.loadMultiDocumentYaml(yamlWithSchema); + return getYamlDocumentValidationErrors(documents); + } + + private List<YamlDocumentValidationError> getYamlDocumentValidationErrors(List<YamlDocument> documents) throws YamlProcessingException { + if (documents.isEmpty()) { + throw new YamlProcessingException("Dictionary YAML file is empty"); + } else { + return validateDocuments(documents); + } + } + + private List<YamlDocumentValidationError> validateDocuments(List<YamlDocument> documents) + throws YamlProcessingException { + + List<YamlDocumentValidationError> yamlFileValidationErrors = new ArrayList<>(); + YamlSchema schema = extractSchema(documents); + YamlValidator validator = new YamlValidator(schema); + + for (int index = FIRST_DOCUMENT_INDEX; index < documents.size(); index++) { + List<SchemaValidationError> validationErrors = validator.validate(documents.get(index)); + yamlFileValidationErrors.addAll(transformErrors(index, validationErrors)); + } + + return yamlFileValidationErrors; + } + + private List<YamlDocumentValidationError> transformErrors(int index, List<SchemaValidationError> validationErrors) { + return validationErrors + .stream() + .map(error -> new YamlDocumentValidationError(index, error.getPath(), error.getMessage())) + .collect(Collectors.toList()); + } + + private YamlSchema extractSchema(List<YamlDocument> documents) throws YamlProcessingException { + return new YamlSchemaFactory().createTreeStructuredYamlSchema(documents.get(0)); + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/YamlLoader.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/YamlLoader.java new file mode 100644 index 0000000..c23da0a --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/YamlLoader.java @@ -0,0 +1,82 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml; + +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.model.YamlDocumentFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +class YamlLoader { + + private static final Logger LOGGER = LoggerFactory.getLogger(YamlLoader.class); + private final YamlDocumentFactory documentFactory; + + YamlLoader(YamlDocumentFactory documentFactory) { + this.documentFactory = documentFactory; + } + + List<YamlDocument> loadMultiDocumentYaml(byte[] yamlWithSchema) + throws YamlDocumentFactory.YamlDocumentParsingException { + List<YamlDocument> documents = new ArrayList<>(); + try (InputStream yamlStream = new ByteArrayInputStream(yamlWithSchema)) { + documents.addAll(loadMultiDocumentYaml(yamlStream)); + } catch (IOException e) { + LOGGER.error("Failed to load multi document YAML", e); + } + return documents; + } + + List<YamlDocument> loadMultiDocumentYamlFile(URL path) + throws YamlDocumentFactory.YamlDocumentParsingException { + List<YamlDocument> documents = new ArrayList<>(); + try (InputStream yamlStream = path.openStream()) { + documents.addAll(loadMultiDocumentYaml(yamlStream)); + } catch (IOException e) { + LOGGER.error("Failed to load multi document YAML file", e); + } + return documents; + } + + List<YamlDocument> loadMultiDocumentYamlFile(String path) + throws YamlProcessingException { + try { + return loadMultiDocumentYamlFile(new URL("file://" + path)); + } catch (MalformedURLException e) { + throw new YamlProcessingException("Fail to read file under given path.", e); + } + } + + private List<YamlDocument> loadMultiDocumentYaml(InputStream yamlStream) throws YamlDocumentFactory.YamlDocumentParsingException { + List<YamlDocument> documents = new ArrayList<>(); + for (Object yamlDocument : new Yaml().loadAll(yamlStream)) { + documents.add(documentFactory.createYamlDocument(yamlDocument)); + } + return documents; + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/YamlValidator.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/YamlValidator.java new file mode 100644 index 0000000..30ba646 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/YamlValidator.java @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml; + +import org.onap.validation.yaml.error.SchemaValidationError; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.process.YamlValidationProcess; +import org.onap.validation.yaml.schema.YamlSchema; + +import java.util.List; + +public class YamlValidator { + + private final YamlSchema schema; + + YamlValidator(YamlSchema schema) { + this.schema = schema; + } + + public List<SchemaValidationError> validate(YamlDocument document) throws YamlProcessingException { + return new YamlValidationProcess(schema,document).validate(); + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/error/SchemaValidationError.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/error/SchemaValidationError.java new file mode 100644 index 0000000..6ffe6d4 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/error/SchemaValidationError.java @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.error; + +public class SchemaValidationError { + private final String path; + private final String message; + + public String getPath() { + return path; + } + + public String getMessage() { + return message; + } + + public SchemaValidationError(String path, String message) { + this.path = path; + this.message = message; + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/error/YamlDocumentValidationError.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/error/YamlDocumentValidationError.java new file mode 100644 index 0000000..f04708f --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/error/YamlDocumentValidationError.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.error; + +public class YamlDocumentValidationError { + private final int yamlDocumentNumber; + private final String path; + private final String message; + + public YamlDocumentValidationError(int yamlDocumentNumber, String path, String message) { + this.yamlDocumentNumber = yamlDocumentNumber; + this.path = path; + this.message = message; + } + + public int getYamlDocumentNumber() { + return yamlDocumentNumber; + } + + public String getPath() { + return path; + } + + public String getMessage() { + return message; + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/exception/YamlProcessingException.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/exception/YamlProcessingException.java new file mode 100644 index 0000000..99c2437 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/exception/YamlProcessingException.java @@ -0,0 +1,33 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.exception; + +public class YamlProcessingException extends Exception { + + public YamlProcessingException(String message, Throwable throwable) { + super(message, throwable); + } + + public YamlProcessingException(String message) { + super(message); + } + + public YamlProcessingException(Throwable throwable) { + super(throwable); + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocument.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocument.java new file mode 100644 index 0000000..557b6fd --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocument.java @@ -0,0 +1,56 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.model; + +import java.util.Map; + +public class YamlDocument { + + private final Map<String, Object> yaml; + + YamlDocument(Map<String, Object> yaml) { + this.yaml = yaml; + } + + public Map<String, Object> getYaml() { + return yaml; + } + + public boolean containsKey(String key) { + return yaml.containsKey(key); + } + + public String getValue(String key) { + return yaml.get(key).toString(); + } + + public YamlParametersList getListOfValues(String key) { + return new YamlParameterListFactory().createYamlParameterList( + yaml.get(key) + ); + } + + public YamlDocument getSubStructure(String name) + throws YamlDocumentFactory.YamlDocumentParsingException { + return new YamlDocumentFactory().createYamlDocument( + yaml.get(name) + ); + } +} + + diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocumentFactory.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocumentFactory.java new file mode 100644 index 0000000..b56422c --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocumentFactory.java @@ -0,0 +1,52 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.model; + +import org.onap.validation.yaml.exception.YamlProcessingException; + +import java.util.HashMap; +import java.util.Map; + +public class YamlDocumentFactory { + + public YamlDocument createYamlDocument(Object yaml) throws YamlDocumentParsingException { + try { + Map<String, Object> parsedYaml = transformMap((Map) yaml); + return new YamlDocument(parsedYaml); + } catch (ClassCastException e) { + throw new YamlDocumentParsingException( + String.format("Fail to parse given objects: %s as yaml document.", yaml), e + ); + } + } + + private Map<String, Object> transformMap(Map<Object, Object> yaml) { + Map<String, Object> parsedYaml = new HashMap<>(); + for (Map.Entry<Object, Object> entry: yaml.entrySet()) { + parsedYaml.put(entry.getKey().toString(), entry.getValue()); + } + return parsedYaml; + } + + public static class YamlDocumentParsingException extends YamlProcessingException { + YamlDocumentParsingException(String message, Throwable throwable) { + super(message, throwable); + } + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlParameterListFactory.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlParameterListFactory.java new file mode 100644 index 0000000..5f41c5c --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlParameterListFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class YamlParameterListFactory { + + public YamlParametersList createEmptyYamlParameterList() { + return new YamlParametersList(Collections.emptyList()); + } + + public YamlParametersList createYamlParameterList(Object yaml) { + List<String> parametersList = new ArrayList<>(); + if( yaml instanceof List) { + for (Object element : (List) yaml) { + parametersList.add(element.toString()); + } + } else { + parametersList.add(yaml.toString()); + } + return new YamlParametersList(parametersList); + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlParametersList.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlParametersList.java new file mode 100644 index 0000000..2b93c74 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/model/YamlParametersList.java @@ -0,0 +1,34 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.model; + +import java.util.List; + +public class YamlParametersList { + + private final List<String> parameters; + + YamlParametersList(List<String> parameters) { + this.parameters = parameters; + } + + public List<String> getParameters() { + return parameters; + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationProcess.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationProcess.java new file mode 100644 index 0000000..ebd37ce --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationProcess.java @@ -0,0 +1,111 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.process; + +import org.onap.validation.yaml.error.SchemaValidationError; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.schema.YamlSchema; +import org.onap.validation.yaml.schema.node.YamlSchemaNode; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class YamlValidationProcess { + + private final Queue<YamlValidationStep> validationSteps; + private final List<SchemaValidationError> errors; + private final YamlSchema schema; + private final YamlDocument document; + + public YamlValidationProcess(YamlSchema schema, YamlDocument document) { + this.schema = schema; + this.document = document; + errors = new ArrayList<>(); + validationSteps = new LinkedList<>(); + } + + public List<SchemaValidationError> validate() throws YamlProcessingException { + validationSteps.add(new YamlValidationStep(schema.getRootNodes(), document)); + while (!validationSteps.isEmpty()) { + YamlValidationStep nextValidationNode = validationSteps.poll(); + validateStep(nextValidationNode); + } + return errors; + } + + private void validateStep(YamlValidationStep validationNode) + throws YamlProcessingException { + for (YamlSchemaNode schemaNode : validationNode.getSchemaNodes()) { + validateNode(validationNode.getDocument(), schemaNode); + } + } + + private void validateNode(YamlDocument document, YamlSchemaNode schemaNode) + throws YamlProcessingException { + + if (document.containsKey(schemaNode.getName())) { + if (schemaNode.isContainingSubStructure()) { + addNextLevelNodeToValidationNodesQueue(document, schemaNode); + } else if (!isValueOfNodeInAcceptedValuesList(document, schemaNode)) { + addIncorrectValueError(document, schemaNode); + } + } else if (schemaNode.isRequired()) { + addRequiredKeyNotFoundError(schemaNode); + } + } + + private boolean isValueOfNodeInAcceptedValuesList(YamlDocument document, YamlSchemaNode node) { + return node.getAcceptedValues().isEmpty() || + node.getAcceptedValues().containsAll( + document.getListOfValues(node.getName()).getParameters() + ); + } + + private void addNextLevelNodeToValidationNodesQueue(YamlDocument document, YamlSchemaNode node) + throws YamlProcessingException { + validationSteps.add( + new YamlValidationStep( + node.getNextNodes(), + document.getSubStructure(node.getName()) + ) + ); + } + + private void addRequiredKeyNotFoundError(YamlSchemaNode node) { + errors.add( + new SchemaValidationError( + node.getPath(), + String.format("Key not found: %s", node.getName()) + ) + ); + } + + private void addIncorrectValueError(YamlDocument document, YamlSchemaNode node) { + errors.add( + new SchemaValidationError( + node.getPath() + node.getName(), + String.format( + "Value(s) is/are not in array of accepted values.%n value(s): %s%n accepted value(s): %s", + document.getValue(node.getName()), node.getAcceptedValues()) + ) + ); + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationStep.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationStep.java new file mode 100644 index 0000000..eb5ab8e --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationStep.java @@ -0,0 +1,45 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.process; + +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.schema.node.YamlSchemaNode; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +class YamlValidationStep { + + private final List<YamlSchemaNode> schemaNodes; + private final YamlDocument document; + + YamlValidationStep(List<YamlSchemaNode> nodes, YamlDocument yaml) { + this.schemaNodes = new ArrayList<>(nodes); + this.document = yaml; + } + + List<YamlSchemaNode> getSchemaNodes() { + return Collections.unmodifiableList(schemaNodes); + } + + YamlDocument getDocument() { + return document; + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchema.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchema.java new file mode 100644 index 0000000..69bb6cd --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchema.java @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.schema; + +import org.onap.validation.yaml.schema.node.YamlSchemaNode; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class YamlSchema { + + private final List<YamlSchemaNode> rootNodes; + + public List<YamlSchemaNode> getRootNodes() { + return Collections.unmodifiableList(rootNodes); + } + + YamlSchema(List<YamlSchemaNode> rootNodes) { + this.rootNodes = new ArrayList<>(rootNodes); + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchemaFactory.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchemaFactory.java new file mode 100644 index 0000000..df7d673 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchemaFactory.java @@ -0,0 +1,59 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +package org.onap.validation.yaml.schema; + +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.model.YamlDocumentFactory; +import org.onap.validation.yaml.schema.node.YamlSchemaNode; +import org.onap.validation.yaml.schema.node.YamlSchemaNodeFactory; + +import java.util.ArrayList; +import java.util.List; + +public class YamlSchemaFactory { + + + private static final String ROOT_PATH = "/"; + + public YamlSchema createTreeStructuredYamlSchema(YamlDocument schema) + throws YamlProcessingException { + + return new YamlSchema(getRootNodes(schema)); + } + + private List<YamlSchemaNode> getRootNodes(YamlDocument yamlDocument) + throws YamlProcessingException { + + List<YamlSchemaNode> nextNodes = new ArrayList<>(); + for(String nodeName: yamlDocument.getYaml().keySet()) { + nextNodes.add( + new YamlSchemaNodeFactory().createNode( + nodeName, + ROOT_PATH, + new YamlDocumentFactory().createYamlDocument( + yamlDocument.getYaml().get(nodeName) + ) + ) + ); + } + return nextNodes; + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaBranchNode.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaBranchNode.java new file mode 100644 index 0000000..a3e9636 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaBranchNode.java @@ -0,0 +1,78 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.schema.node; + +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.model.YamlDocumentFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class YamlSchemaBranchNode extends YamlSchemaNode { + + private final YamlDocument nextNodesInLazyForm; + private List<YamlSchemaNode> nextNodes = Collections.emptyList(); + + YamlSchemaBranchNode(String name, String path, boolean required, String comment, + YamlDocument nextNodesInLazyForm) { + super(name, path, required, comment); + this.nextNodesInLazyForm = nextNodesInLazyForm; + } + + @Override + public boolean isContainingSubStructure() { + return true; + } + + @Override + public List<String> getAcceptedValues() { + return Collections.emptyList(); + } + + @Override + public synchronized List<YamlSchemaNode> getNextNodes() throws YamlSchemaProcessingException { + try { + return nextNodes.isEmpty() ? this.loadNextNodes() : nextNodes; + } catch (YamlSchemaLazyLoadingException lazyLoadingException) { + throw new YamlSchemaProcessingException(lazyLoadingException); + } + } + + private List<YamlSchemaNode> loadNextNodes() { + try { + List<YamlSchemaNode> loadedNextNodes = new ArrayList<>(); + for (String key : nextNodesInLazyForm.getYaml().keySet()) { + YamlDocument substructure = new YamlDocumentFactory() + .createYamlDocument(nextNodesInLazyForm.getYaml().get(key)); + loadedNextNodes.add(new YamlSchemaNodeFactory().createNode(key, getPath() + getName() + "/", substructure)); + } + nextNodes = loadedNextNodes; + return loadedNextNodes; + } catch (YamlProcessingException e) { + throw new YamlSchemaLazyLoadingException("Lazy loading failed, due to yaml parsing exception.",e); + } + } + + static class YamlSchemaLazyLoadingException extends RuntimeException { + YamlSchemaLazyLoadingException(String message, Throwable throwable) { + super(message, throwable); + } + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaLeafNode.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaLeafNode.java new file mode 100644 index 0000000..c98f41e --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaLeafNode.java @@ -0,0 +1,50 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.schema.node; + +import org.onap.validation.yaml.model.YamlParametersList; + +import java.util.Collections; +import java.util.List; + +public class YamlSchemaLeafNode extends YamlSchemaNode { + + private final YamlParametersList acceptedValues; + + YamlSchemaLeafNode(String name, String path, boolean required, String comment, + YamlParametersList acceptedValues) { + super(name, path, required, comment); + this.acceptedValues = acceptedValues; + } + + @Override + public List<String> getAcceptedValues() { + return acceptedValues.getParameters(); + } + + @Override + public List<YamlSchemaNode> getNextNodes() { + return Collections.emptyList(); + } + + @Override + public boolean isContainingSubStructure() { + return false; + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNode.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNode.java new file mode 100644 index 0000000..28913a2 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNode.java @@ -0,0 +1,66 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.schema.node; + +import org.onap.validation.yaml.exception.YamlProcessingException; + +import java.util.List; + +public abstract class YamlSchemaNode { + + private final String path; + private final String name; + private final boolean required; + private final String comment; + + + public String getName() { + return name; + } + + public String getPath() { + return path; + } + + public boolean isRequired() { + return required; + } + + public abstract List<String> getAcceptedValues(); + + public abstract List<YamlSchemaNode> getNextNodes() throws YamlSchemaProcessingException; + + public abstract boolean isContainingSubStructure(); + + public String getComment() { + return comment; + } + + YamlSchemaNode(String name, String path, boolean required, String comment) { + this.name = name; + this.path = path; + this.required = required; + this.comment = comment; + } + + static class YamlSchemaProcessingException extends YamlProcessingException { + YamlSchemaProcessingException(Throwable throwable) { + super(throwable); + } + } +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNodeFactory.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNodeFactory.java new file mode 100644 index 0000000..79a8f14 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNodeFactory.java @@ -0,0 +1,84 @@ +/* + * Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.onap.validation.yaml.schema.node; + +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.model.YamlDocumentFactory; +import org.onap.validation.yaml.model.YamlParameterListFactory; +import org.onap.validation.yaml.model.YamlParametersList; + +import static org.onap.validation.yaml.model.YamlDocumentFactory.YamlDocumentParsingException; + +public class YamlSchemaNodeFactory { + + public static final String EMPTY_COMMENT = "no comment available"; + static final String STRUCTURE_KEY = "structure"; + static final String COMMENT_KEY = "comment"; + static final String VALUE_KET = "value"; + static final String PRESENCE_KEY = "presence"; + static final String PRESENCE_REQUIRED_KEY = "required"; + + public YamlSchemaNode createNode(String nodeName, String path, YamlDocument yamlDocument) + throws YamlProcessingException { + + YamlSchemaNode yamlSchemaNode; + if(isYamlContainingKey(yamlDocument, STRUCTURE_KEY)) { + yamlSchemaNode = new YamlSchemaBranchNode( + nodeName, path, getIsPresenceRequired(yamlDocument), getComment(yamlDocument), + getNextNodes(yamlDocument) + ); + } else { + yamlSchemaNode = new YamlSchemaLeafNode( + nodeName, path, getIsPresenceRequired(yamlDocument), getComment(yamlDocument), + getAcceptedValues(yamlDocument) + ); + } + return yamlSchemaNode; + } + + private YamlDocument getNextNodes(YamlDocument yamlDocument) + throws YamlDocumentParsingException { + return new YamlDocumentFactory().createYamlDocument(yamlDocument.getYaml().get(STRUCTURE_KEY)); + } + + private String getComment(YamlDocument yamlDocument) { + + return isYamlContainingKey(yamlDocument, COMMENT_KEY) + ? yamlDocument.getYaml().get(COMMENT_KEY).toString() + : EMPTY_COMMENT; + } + + private YamlParametersList getAcceptedValues(YamlDocument yamlDocument) { + + return isYamlContainingKey(yamlDocument, VALUE_KET) + ? new YamlParameterListFactory().createYamlParameterList(yamlDocument.getYaml().get(VALUE_KET)) + : new YamlParameterListFactory().createEmptyYamlParameterList(); + } + + private boolean getIsPresenceRequired(YamlDocument yamlDocument) { + + return isYamlContainingKey(yamlDocument, PRESENCE_KEY) + && yamlDocument.getYaml().get(PRESENCE_KEY).equals(PRESENCE_REQUIRED_KEY); + } + + private boolean isYamlContainingKey(YamlDocument yamlDocument, String structureKey) { + return yamlDocument.getYaml().containsKey(structureKey); + } + +} diff --git a/dictionaryvalidation/src/main/java/org/onap/validation/yaml/util/Args.java b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/util/Args.java new file mode 100644 index 0000000..9ae44c8 --- /dev/null +++ b/dictionaryvalidation/src/main/java/org/onap/validation/yaml/util/Args.java @@ -0,0 +1,36 @@ +/* + *Copyright 2020 Nokia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.onap.validation.yaml.util; + +import java.util.ArrayList; +import java.util.List; + +public class Args { + + private final List<String> data; + + public Args(List<String> data) { + this.data = new ArrayList<>(data); + } + + public String getArg(int index) { + if (this.data.size() <= index) { + throw new IllegalArgumentException(String.format("Argument with index %d is not available!", index)); + } + return this.data.get(index); + } +} diff --git a/dictionaryvalidation/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand b/dictionaryvalidation/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand new file mode 100644 index 0000000..9d1b8a2 --- /dev/null +++ b/dictionaryvalidation/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand @@ -0,0 +1,15 @@ +# Copyright 2020 Nokia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +org.onap.validation.rule.DictionaryValidate diff --git a/dictionaryvalidation/src/main/resources/log4j2.properties b/dictionaryvalidation/src/main/resources/log4j2.properties new file mode 100644 index 0000000..8ef4de1 --- /dev/null +++ b/dictionaryvalidation/src/main/resources/log4j2.properties @@ -0,0 +1,56 @@ +# Copyright Nokia 2020 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# By default, log4j2 will look for a configuration file named log4j2.xml on the classpath. +# reference: https://logging.apache.org/log4j/2.x/faq.html#troubleshooting + + +status = error +dest = err +name = PropertiesConfig + +property.filename = ./dictionary-validate.log + +filter.threshold.type = ThresholdFilter +filter.threshold.level = debug + +appender.console.type = Console +appender.console.name = STDOUT +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %m%n +appender.console.filter.threshold.type = ThresholdFilter +appender.console.filter.threshold.level = error + +appender.rolling.type = RollingFile +appender.rolling.name = RollingFile +appender.rolling.fileName = ${filename} +appender.rolling.filePattern = ./dictionary-validate.%d{yyyy-MM-dd-HH:mm:ss}.log +appender.rolling.layout.type = PatternLayout +appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n +appender.rolling.policies.type = Policies +appender.rolling.policies.time.type = TimeBasedTriggeringPolicy +appender.rolling.policies.time.interval = 2 +appender.rolling.policies.time.modulate = true +appender.rolling.policies.size.type = SizeBasedTriggeringPolicy +appender.rolling.policies.size.size=5MB +appender.rolling.strategy.type = DefaultRolloverStrategy +appender.rolling.strategy.max = 5 + +logger.rolling.name = org.onap.validation +logger.rolling.level = debug +logger.rolling.additivity = false +logger.rolling.appenderRef.rolling.ref = RollingFile + +rootLogger.level = info +rootLogger.appenderRef.stdout.ref = STDOUT diff --git a/dictionaryvalidation/src/main/resources/open-cli-schema/dictionary-validate.yaml b/dictionaryvalidation/src/main/resources/open-cli-schema/dictionary-validate.yaml new file mode 100644 index 0000000..1f5801d --- /dev/null +++ b/dictionaryvalidation/src/main/resources/open-cli-schema/dictionary-validate.yaml @@ -0,0 +1,63 @@ +# Copyright 2020 Nokia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +open_cli_schema_version: 1.0 + +name: dictionary-validate + +description: Validate Dictionary Yaml file + +info: + product: onap-honolulu + version: 1.0 + service: vnf-compliance + author: ONAP VTP Team onap-discuss@lists.onap.org + +parameters: + - name: yaml + description: Yaml file path + long_option: yaml + short_option: b + type: binary + is_optional: false + +results: + direction: portrait + attributes: + - name: file + description: Dictionary Yaml file + scope: short + type: string + - name: date + description: Validation date + scope: short + type: string + - name: platform + description: Platform used to test the reqs + scope: short + type: string + default_value: Dictionary Test Platform (VTP) 1.0 + - name: contact + description: Owner for this test case + scope: short + type: string + default_value: ONAP VTP Team onap-discuss@lists.onap.org + - name: criteria + description: Overall test reqs passed? PASS or FAILED + scope: short + type: string + - name: errors + description: All test cases errors + scope: short + type: json |