diff options
153 files changed, 5913 insertions, 694 deletions
diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..8bf5b52 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,106 @@ +# Changelog +All notable changes to this project will be documented in this file. + + +## [1.2.5] + +### Added +- Added rule R972082 to enabled PNF requirements. + - https://jira.onap.org/browse/VNFSDK-585 + +### Fixed +- Fixed package integrity issue with non mano arifacts. + - https://jira.onap.org/browse/VNFSDK-581 +- Fixed VNF/PNF package integrity issue with CMS signature not containing certificate. + - https://jira.onap.org/browse/VNFSDK-582 +- Fixed bug that was showing errors during validation of CSAR, + when any other non_mano_artifact_set than onap_pnf_sw_information was present in manifest file. + - https://jira.onap.org/browse/VNFSDK-585 + +## [1.2.6] + +### Added +- Added file extension validation of file related in onap_pnf_sw_information artifact set. + - https://jira.onap.org/browse/VNFSDK-585 + +### Fixed +- Fixed bug that was generating invalid report when user run validation with all rules and single validation fails. + - https://jira.onap.org/browse/VNFSDK-586 + + +## [1.2.7] + +### Fixed +- Fixed bug that was causing problem with loading rules properties. + - https://jira.onap.org/browse/VNFSDK-587 +- Fixed package security SOL004 Option 1 make rule less restrictive as this rule is not implemented in SDC Onboarding + - https://jira.onap.org/browse/VNFSDK-595 + +## [1.2.8] + +## Fixed +- Fixed VNFSDK doesn't check if all files in package are listed in manifest file + - https://jira.onap.org/browse/VNFSDK-583 + +## [1.2.9] + +### Added +- Added rule R972082 to validate PM_Dictionary using schema. + - https://jira.onap.org/browse/VNFSDK-594 + +## Fixed +- Fixed rule R01123 that was reporting all files in ZIP as not present in manifest + - https://jira.onap.org/browse/VNFSDK-583 + + +## [1.2.10] + +### Added +- Added parameters list validation to PM Dictionary . + - https://jira.onap.org/browse/VNFSDK-594 + + +## [1.2.11] + +## Fixed +- Fixed rule R816745 that wasn't sending all exceptions connected with YAML parsing as validation error + - https://jira.onap.org/browse/VNFSDK-644 + +## [1.2.12] + +## Fixed +- Fixed rule R816745 that was searching for the path to PM_Dictionary in manifest file under name source, + instead of Source (starting with a capital letter). + Now both versions (source and Source) are accepted by this rule. + - https://jira.onap.org/browse/VNFSDK-645 +- Fixed commons-codec vulnerability + - https://jira.onap.org/browse/VNFSDK-584 + +## Added +- Added non-vulnerable log4j version + - https://jira.onap.org/browse/VNFSDK-553 + +## Upgrade +- Upgraded from java 8 to java 11 + - https://jira.onap.org/browse/VNFSDK-631 + +## [1.2.13] + +## Fixed +- Fixed rule R130206 CMS and certificate searching and validation mechanism + - https://jira.onap.org/browse/VNFSDK-595 + +## Added +- Add new field called "warnings" to oclip json response. All ignored errors are now reported as warnings. + - https://jira.onap.org/browse/VNFSDK-596 + +## [1.2.14] + +## Fixed +- Fixed rule R130206 handling of CSARs with no TOSCA meta and no Certificate in root directory + - https://jira.onap.org/browse/VNFSDK-481 +- Fixed rule R816745 that was not reporting error when CMS and TOSCA meta file were present, + however TOSCA did not contain ETSI-Entry-Certificate + - https://jira.onap.org/browse/VNFSDK-660 + +## [1.2.15] diff --git a/csarvalidation/pom.xml b/csarvalidation/pom.xml index 968d242..729c82d 100644 --- a/csarvalidation/pom.xml +++ b/csarvalidation/pom.xml @@ -14,7 +14,7 @@ <parent> <groupId>org.onap.vnfsdk.validation</groupId> <artifactId>validation</artifactId> - <version>1.2.4-SNAPSHOT</version> + <version>1.2.15-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>validation-csar</artifactId> @@ -34,11 +34,29 @@ </repository> </repositories> + <properties> + <log4j-slf4j-impl.version>2.13.3</log4j-slf4j-impl.version> + <snakeyaml.version>1.26</snakeyaml.version> + <jackson-core.version>2.9.4</jackson-core.version> + <junit.version>4.12</junit.version> + <commons-lang3.version>3.2.1</commons-lang3.version> + <commons-io.version>2.7</commons-io.version> + <bcpkix-jdk15on.version>1.61</bcpkix-jdk15on.version> + <cli-framework.version>5.0.3</cli-framework.version> + <cli-main.version>5.0.2</cli-main.version> + <assertj-core.version>3.11.1</assertj-core.version> + <lombok.version>1.18.2</lombok.version> + <commons-collections.version>3.2.2</commons-collections.version> + <maven-war-plugin.version>2.6</maven-war-plugin.version> + <maven-dependency-plugin.version>3.0.0</maven-dependency-plugin.version> + <mockito-core.version>3.5.0</mockito-core.version> + </properties> + <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> - <version>2.13.0</version> + <version>${log4j-slf4j-impl.version}</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> @@ -49,69 +67,85 @@ <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> - <version>1.18</version> + <version>${snakeyaml.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> - <version>2.9.4</version> + <version>${jackson-core.version}</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - <scope>test</scope> - </dependency> + <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> - <version>3.2.1</version> + <version>${commons-lang3.version}</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> - <version>2.5</version> + <version>${commons-io.version}</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> - <version>1.61</version> + <version>${bcpkix-jdk15on.version}</version> </dependency> <dependency> <groupId>org.onap.cli</groupId> <artifactId>cli-framework</artifactId> - <version>5.0.3</version> + <version>${cli-framework.version}</version> + <exclusions> + <exclusion> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + </exclusion> + </exclusions> </dependency> - <dependency> - <groupId>org.onap.cli</groupId> - <artifactId>cli-main</artifactId> - <version>5.0.2</version> - <scope>test</scope> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + <version>1.14</version> </dependency> - - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <version>3.11.1</version> - <scope>test</scope> - </dependency> - <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> - <version>1.18.2</version> + <version>${lombok.version}</version> </dependency> <dependency> <artifactId>commons-collections</artifactId> <groupId>commons-collections</groupId> - <version>3.2.2</version> + <version>${commons-collections.version}</version> </dependency> + <!-- TEST dependencies --> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>${mockito-core.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onap.cli</groupId> + <artifactId>cli-main</artifactId> + <version>${cli-main.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>${assertj-core.version}</version> + <scope>test</scope> + </dependency> </dependencies> <profiles> @@ -124,7 +158,6 @@ </profile> </profiles> - <build> <finalName>${project.artifactId}-${project.version}</finalName> @@ -132,7 +165,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> - <version>3.0.2</version> + <version>${maven-jar-plugin.version}</version> <configuration> <archive> <manifest> @@ -142,20 +175,11 @@ </archive> </configuration> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.1</version> - <configuration> - <source>1.8</source> - <target>1.8</target> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> - <version>3.0.0</version> + <version>${maven-dependency-plugin.version}</version> <executions> <execution> <id>copy-artifact</id> @@ -186,7 +210,7 @@ <overWriteReleases>false</overWriteReleases> <overWriteSnapshots>false</overWriteSnapshots> <overWriteIfNewer>true</overWriteIfNewer> - <excludeArtifactIds>junit,jmockit</excludeArtifactIds> + <excludeArtifactIds>junit</excludeArtifactIds> </configuration> </execution> </executions> @@ -194,7 +218,7 @@ <plugin> <artifactId>maven-war-plugin</artifactId> - <version>2.6</version> + <version>${maven-war-plugin.version}</version> <configuration> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/CSARArchive.java b/csarvalidation/src/main/java/org/onap/cvc/csar/CSARArchive.java index 1c05948..05f2070 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/CSARArchive.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/CSARArchive.java @@ -92,6 +92,9 @@ public class CSARArchive implements AutoCloseable { public static final String CSAR_ARCHIVE = "CSAR Archive"; public static final String DOESS_NOT_EXIST = " does not exist"; + public static final String CERT = ".cert"; + public static final String YAML = ".yaml"; + public static final String MF = ".mf"; public enum Mode { WITH_TOSCA_META_DIR, @@ -496,7 +499,7 @@ public class CSARArchive implements AutoCloseable { CSAR_ARCHIVE, -1, "Manifest file name should match the definition YAML name", - definitionYaml + ".mf", //fix the name part + definitionYaml + MF, //fix the name part manifest); this.setCode("0x0013"); @@ -521,13 +524,20 @@ public class CSARArchive implements AutoCloseable { CSAR_ARCHIVE, -1, "certificate file name should match the definition YAML name", - definitionYaml + ".cert", //fix the name part + definitionYaml + CERT, //fix the name part certificate); this.setCode("0x0015"); } } + public static class CSARErrorNoManifestsFound extends CSARError { + public CSARErrorNoManifestsFound() { + super("0x0016"); + this.message = "No manifest file found in CSAR!"; + } + } + /** * Holds the CSAR meta data values in both Modes * @@ -966,32 +976,29 @@ public class CSARArchive implements AutoCloseable { lineNo ++; line = line.trim(); - if (line.startsWith("#") || line.trim().isEmpty()) { - continue; - } - - String []lineTokens = line.split(":"); + if (!line.startsWith("#") && !line.trim().isEmpty()) { + String []lineTokens = line.split(":"); - if (lineTokens.length != 2) { - errors.add( - new CSARErrorIgnored( - line, - TOSCA_METADATA_TOSCA_META, - lineNo, - null)); - continue; - } + if (lineTokens.length != 2) { + errors.add( + new CSARErrorIgnored( + line, + TOSCA_METADATA_TOSCA_META, + lineNo, + null)); + continue; + } - String key = lineTokens[0].trim(); - String value = lineTokens[1].trim(); + String key = lineTokens[0].trim(); + String value = lineTokens[1].trim(); - if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_TOSCA_META_FILE_VERSION)) { + if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_TOSCA_META_FILE_VERSION)) { this.toscaMeta.setMetaDataFileVersion(value); - } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_CSAR_VERSION)){ + } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_CSAR_VERSION)){ this.toscaMeta.setCsarVersion(value); - } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_CREATED_BY)) { + } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_CREATED_BY)) { this.toscaMeta.setCompanyName(value); - } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_ENTRY_DEFINITIONS)) { + } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_ENTRY_DEFINITIONS)) { this.toscaMeta.setEntryDefinitionYaml(value); this.definitionYamlFile = new File(this.tempDir.toFile().getAbsolutePath() + File.separator + (this.toscaMeta.getEntryDefinitionYaml())); @@ -1001,7 +1008,7 @@ public class CSARArchive implements AutoCloseable { this.toscaMeta.getEntryDefinitionYaml(), lineNo)); } - } else if(key.equalsIgnoreCase(getEntryManifestParamName())) { + } else if(key.equalsIgnoreCase(getEntryManifestParamName())) { this.toscaMeta.setEntryManifestMf(value); this.manifestMfFile = this.tempDir.resolve(this.toscaMeta.getEntryManifestMf()).toFile(); if (!this.manifestMfFile.exists()) { @@ -1009,7 +1016,7 @@ public class CSARArchive implements AutoCloseable { this.toscaMeta.getEntryManifestMf(), lineNo, getEntryManifestParamName())); } - } else if(key.equalsIgnoreCase(getEntryChangeLogParamName())) { + } else if(key.equalsIgnoreCase(getEntryChangeLogParamName())) { this.toscaMeta.setEntryChangeLog(value); this.changeLogTxtFile = this.tempDir.resolve(this.toscaMeta.getEntryChangeLog()).toFile(); if (!this.changeLogTxtFile.exists()) { @@ -1017,37 +1024,38 @@ public class CSARArchive implements AutoCloseable { this.toscaMeta.getEntryChangeLog(), lineNo, getEntryChangeLogParamName())); } - } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_ENTRY_TESTS)) { + } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_ENTRY_TESTS)) { this.toscaMeta.setEntryTest(value); - this.testsFolder= this.tempDir.resolve(this.toscaMeta.getEntryTest()).toFile(); + this.testsFolder = this.tempDir.resolve(this.toscaMeta.getEntryTest()).toFile(); if (!this.testsFolder.exists() || !this.testsFolder.isDirectory()) { errors.add(new CSARErrorInvalidEntryValueTestsNotFound( this.toscaMeta.getEntryTest(), lineNo)); } - } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_ENTRY_LICENSES)) { + } else if(key.equalsIgnoreCase(TOSCA_METADATA_TOSCA_META_ENTRY_LICENSES)) { this.toscaMeta.setEntryLicense(value); - this.licensesFolder= this.tempDir.resolve(this.toscaMeta.getEntryLicense()).toFile(); + this.licensesFolder = this.tempDir.resolve(this.toscaMeta.getEntryLicense()).toFile(); if (!this.licensesFolder.exists() || !this.licensesFolder.isDirectory()) { errors.add(new CSARErrorInvalidEntryValueLicenseNotFound( this.toscaMeta.getEntryLicense(), lineNo)); } - } else if(key.equalsIgnoreCase(getEntryCertificateParamName())) { + } else if(key.equalsIgnoreCase(getEntryCertificateParamName())) { this.toscaMeta.setEntryCertificate(value); - this.certificatesFile= this.tempDir.resolve(this.toscaMeta.getEntryCertificate()).toFile(); + this.certificatesFile = this.tempDir.resolve(this.toscaMeta.getEntryCertificate()).toFile(); if (!this.certificatesFile.exists()) { errors.add(new CSARErrorInvalidEntryValueCertificatesNotFound( this.toscaMeta.getEntryCertificate(), lineNo)); } - } else { + } else { errors.add( new CSARErrorIgnored( key, TOSCA_METADATA_TOSCA_META, lineNo, null)); + } } } @@ -1071,7 +1079,7 @@ public class CSARArchive implements AutoCloseable { } else { //definition files - File []files = this.tempDir.toFile().listFiles((dir, name) -> name.endsWith(".yaml")); + File []files = this.tempDir.toFile().listFiles((dir, name) -> name.endsWith(YAML)); if (files.length == 0) { errors.add( @@ -1088,9 +1096,12 @@ public class CSARArchive implements AutoCloseable { this.toscaMeta.setEntryDefinitionYaml(this.definitionYamlFile.getName()); //manifest - files = this.tempDir.toFile().listFiles((dir, name) -> name.endsWith(".mf")); + files = this.tempDir.toFile().listFiles((dir, name) -> name.endsWith(MF)); - if (files.length > 1) { + if (files.length == 0) { + errors.add(new CSARErrorNoManifestsFound()); + this.toscaMeta.setEntryManifestMf(null); + } else if (files.length > 1) { List<String> fileNames = new ArrayList<>(); for (File f: files) { fileNames.add(f.getName()); @@ -1102,9 +1113,9 @@ public class CSARArchive implements AutoCloseable { //name should match the definition yaml String defYaml = this.toscaMeta.getEntryDefinitionYaml().substring( - 0, this.toscaMeta.getEntryDefinitionYaml().lastIndexOf(".yaml")); + 0, this.toscaMeta.getEntryDefinitionYaml().lastIndexOf(YAML)); String mfFile = this.toscaMeta.getEntryManifestMf().substring( - 0, this.toscaMeta.getEntryManifestMf().lastIndexOf(".mf")); + 0, this.toscaMeta.getEntryManifestMf().lastIndexOf(MF)); if (!defYaml.equalsIgnoreCase(mfFile)) { errors.add(new CSARErrorMismatchDefinitionYamlVsManifestMf( @@ -1115,9 +1126,11 @@ public class CSARArchive implements AutoCloseable { } //certificate - files = this.tempDir.toFile().listFiles((dir, name) -> name.endsWith(".cert")); + files = this.tempDir.toFile().listFiles((dir, name) -> name.endsWith(CERT)); - if (files.length > 1) { + if (files.length == 0) { + this.toscaMeta.setEntryCertificate(null); + } else if (files.length > 1) { List<String> fileNames = new ArrayList<>(); for (File f: files) { fileNames.add(f.getName()); @@ -1130,9 +1143,9 @@ public class CSARArchive implements AutoCloseable { //name should match the definition yaml String defYaml = this.toscaMeta.getEntryDefinitionYaml().substring( - 0, this.toscaMeta.getEntryDefinitionYaml().lastIndexOf(".yaml")); + 0, this.toscaMeta.getEntryDefinitionYaml().lastIndexOf(YAML)); String certFile = this.toscaMeta.getEntryCertificate().substring( - 0, this.toscaMeta.getEntryCertificate().lastIndexOf(".cert")); + 0, this.toscaMeta.getEntryCertificate().lastIndexOf(CERT)); if (!defYaml.equalsIgnoreCase(certFile)) { errors.add(new CSARErrorMismatchDefinitionYamlVsCertificateCert( diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/VTPValidateCSAR.java b/csarvalidation/src/main/java/org/onap/cvc/csar/VTPValidateCSAR.java index 30eb043..74697f1 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/VTPValidateCSAR.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/VTPValidateCSAR.java @@ -16,11 +16,12 @@ package org.onap.cvc.csar; +import com.google.gson.Gson; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Properties; - import org.onap.cli.fw.cmd.OnapCommand; import org.onap.cli.fw.error.OnapCommandException; import org.onap.cli.fw.error.OnapCommandExecutionFailed; @@ -33,19 +34,20 @@ import org.onap.cvc.csar.CSARArchive.CSARError; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.Gson; - /** * Validates CSAR */ @OnapCommandSchema(schema = "vtp-validate-csar.yaml") public class VTPValidateCSAR extends OnapCommand { + private static Gson gson = new Gson(); private static final Logger LOG = LoggerFactory.getLogger(VTPValidateCSAR.class); public static final String PNF_ATTRIBUTE_NAME = "pnf"; public static class CSARValidation { + public static class VNF { + private String name; private String vendor; private String version; @@ -55,30 +57,39 @@ public class VTPValidateCSAR extends OnapCommand { public String getName() { return name; } + public void setName(String name) { this.name = name; } + public String getVendor() { return vendor; } + public void setVendor(String vendor) { this.vendor = vendor; } + public String getVersion() { return version; } + public void setVersion(String version) { this.version = version; } + public String getType() { return type; } + public void setType(String type) { this.type = type; } + public String getMode() { return mode; } + public void setMode(String mode) { this.mode = mode; } @@ -89,35 +100,52 @@ public class VTPValidateCSAR extends OnapCommand { private String criteria; public static class Result { + private boolean passed; private String vnfreqName; private String description; private List<CSARError> errors = new ArrayList<>(); + private List<CSARError> warnings = new ArrayList<>(); + public boolean isPassed() { return passed; } + public void setPassed(boolean passed) { this.passed = passed; } + public String getVnfreqName() { return vnfreqName; } + public void setVnfreqName(String vnfreqName) { this.vnfreqName = vnfreqName; } + public List<CSARError> getErrors() { - return errors; + return Collections.unmodifiableList(errors); } - public void setErrors(List<CSARError> errors) { - this.errors = errors; + + public void addError(CSARError error) { + this.errors.add(error); } + public String getDescription() { return description; } + public void setDescription(String description) { this.description = description; } + public List<CSARError> getWarnings() { + return Collections.unmodifiableList(warnings); + } + + public void addErrorAsWarning(CSARError error) { + this.warnings.add(error); + } } private List<Result> results = new ArrayList<>(); @@ -176,9 +204,10 @@ public class VTPValidateCSAR extends OnapCommand { } private static Properties properties = new Properties(); + static { try { - properties.load(VTPValidateCSAR.class.getClass().getResourceAsStream("/vnfreqs.properties")); + properties.load(VTPValidateCSAR.class.getResourceAsStream("/vnfreqs.properties")); } catch (Exception e) { LOG.error(e.getMessage(), e); } @@ -191,23 +220,23 @@ public class VTPValidateCSAR extends OnapCommand { boolean isPnf = (boolean) getParametersMap().get(PNF_ATTRIBUTE_NAME).getValue(); boolean overallPass = true; - try(CSARArchive csar = isPnf ? new PnfCSARArchive(): new CSARArchive()){ + try (CSARArchive csar = isPnf ? new PnfCSARArchive() : new CSARArchive()) { csar.init(path); csar.parse(); CSARValidation validation = createCsarValidationFor(csar); String keyErrors = isPnf ? "pnferrors.ignored" : "vnferrors.ignored"; - List <String> ignoreCodes = this.getPropertiesList(keyErrors); + List<String> ignoreCodes = this.getPropertiesList(keyErrors); //Add SOL004 error codes CSARValidation.Result resultSOL004 = new CSARValidation.Result(); resultSOL004.setVnfreqName("SOL004"); resultSOL004.setDescription(csar.getSOL004Version()); - for (CSARError error: csar.getErrors()) { + for (CSARError error : csar.getErrors()) { if (!ignoreCodes.contains(error.getCode())) { - resultSOL004.getErrors().add(error); + resultSOL004.addError(error); overallPass = false; } } @@ -217,34 +246,11 @@ public class VTPValidateCSAR extends OnapCommand { //Run thru the vnfreqs requirement checks String keyReqs = isPnf ? "pnfreqs.enabled" : "vnfreqs.enabled"; - for (String vnfreq: this.getPropertiesList(keyReqs)) { + for (String vnfreq : this.getPropertiesList(keyReqs)) { CSARValidation.Result result = new CSARValidation.Result(); result.setVnfreqName(vnfreq); - try { - String command = "csar-validate-" + vnfreq; - OnapCommand cmd = OnapCommandRegistrar.getRegistrar().get(command, this.getInfo().getProduct()); - cmd.getParametersMap().get("csar").setValue(path); - setPnfValueIfAvailable(isPnf, cmd); - - result.setDescription(cmd.getDescription()); - cmd.execute(); - - for (CSARError error: (List<CSARError>) cmd.getResult().getOutput()) { - if (!ignoreCodes.contains(error.getCode()) && !ignoreCodes.contains(vnfreq + "-"+ error.getCode())) { - result.getErrors().add(error); - overallPass = false; - } - } - - result.setPassed(overallPass); - validation.getResults().add(result); - } catch (Exception e) { - result.setPassed(false); - overallPass = false; - result.getErrors().add(new CSARArchive.CSARErrorUnknown(e.getMessage())); - validation.getResults().add(result); - } + overallPass = validateVnfOrPnf(path, validation, ignoreCodes, vnfreq, result, isPnf, overallPass); } validation.setDate(new Date().toString()); @@ -257,6 +263,41 @@ public class VTPValidateCSAR extends OnapCommand { } } + private boolean validateVnfOrPnf(String path, CSARValidation validation, + List<String> ignoreCodes, String vnfreq, CSARValidation.Result result, boolean isPnf, boolean overallPass) { + try { + String command = "csar-validate-" + vnfreq; + OnapCommand cmd = OnapCommandRegistrar.getRegistrar().get(command, this.getInfo().getProduct()); + cmd.getParametersMap().get("csar").setValue(path); + setPnfValueIfAvailable(isPnf, cmd); + + result.setDescription(cmd.getDescription()); + cmd.execute(); + + for (CSARError error : (List<CSARError>) cmd.getResult().getOutput()) { + if (!isErrorIgnored(ignoreCodes, vnfreq, error)) { + result.addError(error); + overallPass = false; + } else { + result.addErrorAsWarning(error); + } + } + + result.setPassed(result.getErrors().isEmpty()); + validation.getResults().add(result); + } catch (Exception e) { + result.setPassed(false); + overallPass = false; + result.addError(new CSARArchive.CSARErrorUnknown(e.getMessage())); + validation.getResults().add(result); + } + return overallPass; + } + + private boolean isErrorIgnored(List<String> ignoreCodes, String vnfreq, CSARError error) { + return ignoreCodes.contains(error.getCode()) || ignoreCodes.contains(vnfreq + "-" + error.getCode()); + } + static CSARValidation createCsarValidationFor(CSARArchive csar) { //Fill up the basic details CSARValidation validation = new CSARValidation(); @@ -270,11 +311,11 @@ public class VTPValidateCSAR extends OnapCommand { private void setOperationResult(CSARValidation validation) throws Exception { //NOSONAR this.getResult().getRecordsMap().get("vnf").getValues().add( - gson.toJson(validation.getVnf())); + gson.toJson(validation.getVnf())); this.getResult().getRecordsMap().get("date").getValues().add(validation.getDate()); this.getResult().getRecordsMap().get("criteria").getValues().add(validation.getCriteria()); this.getResult().getRecordsMap().get("results").getValues().add( - gson.toJson(validation.getResults())); + gson.toJson(validation.getResults())); this.getResult().setOutput(gson.toJson(validation)); this.getResult().setType(OnapCommandResultType.TEXT); @@ -282,7 +323,7 @@ public class VTPValidateCSAR extends OnapCommand { private void setPnfValueIfAvailable(boolean isPnf, OnapCommand cmd) throws OnapCommandInvalidParameterValue { final OnapCommandParameter pnf = cmd.getParametersMap().get(PNF_ATTRIBUTE_NAME); - if(pnf!=null) { + if (pnf != null) { pnf.setValue(isPnf); } } @@ -290,7 +331,7 @@ public class VTPValidateCSAR extends OnapCommand { private List<String> getPropertiesList(String key) { String[] enabledReqs = properties.getProperty(key, "").split(","); List<String> list = new ArrayList<>(); - for(String req: enabledReqs) { + for (String req : enabledReqs) { if (!req.isEmpty()) { list.add(req); } diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/VTPValidateCSARBase.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/VTPValidateCSARBase.java index a5a13e3..b004858 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/VTPValidateCSARBase.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/VTPValidateCSARBase.java @@ -34,7 +34,7 @@ public abstract class VTPValidateCSARBase extends OnapCommand { protected List<CSARError> errors = new ArrayList<>(); - protected abstract void validateCSAR(CSARArchive csar) throws Exception; + protected abstract void validateCSAR(CSARArchive csar) throws Exception; //NOSONAR protected abstract String getVnfReqsNo(); @@ -57,7 +57,7 @@ public abstract class VTPValidateCSARBase extends OnapCommand { this.validateCSAR(csar); } catch (Exception e) { - LOG.error(this.getVnfReqsNo() + ": Failed to validate CSAR" , e); + LOG.error("{}: Failed to validate CSAR {}", this.getVnfReqsNo(), e); throw new OnapCommandExecutionFailed(e.getMessage()); } diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol001/VTPValidateCSARR02454.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol001/VTPValidateCSARR02454.java index 7d0489e..4270d87 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol001/VTPValidateCSARR02454.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol001/VTPValidateCSARR02454.java @@ -60,10 +60,11 @@ public class VTPValidateCSARR02454 extends VTPValidateCSARBase { } } - if (!vlExist) - this.errors.add(new CSARErrorEntryMissingSwImage( + if (!vlExist) { + this.errors.add(new CSARErrorEntryMissingSwImage( csar.getDefinitionYamlFile().getName(), "Software Image")); + } } } } diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol001/VTPValidateCSARR35851.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol001/VTPValidateCSARR35851.java index 52582a6..78be3e6 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol001/VTPValidateCSARR35851.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol001/VTPValidateCSARR35851.java @@ -59,7 +59,7 @@ public class VTPValidateCSARR35851 extends VTPValidateCSARBase { yaml = (Map<String, ?>) yaml.get("topology_template"); Map<String, ?> nodeTmpls = (Map<String,?>) yaml.get("node_templates"); - boolean vlExist[] = new boolean[3]; + boolean[] vlExist = new boolean[3]; for (Object nodeO: nodeTmpls.values()) { Map<String, ?> node = (Map<String, ?>) nodeO; diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR01123.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR01123.java index 5afc1d9..a7c5737 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR01123.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR01123.java @@ -1,5 +1,6 @@ /* * Copyright 2017 Huawei Technologies Co., Ltd. + * Modified 2020 Nokia. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +21,16 @@ import org.onap.cli.fw.schema.OnapCommandSchema; import org.onap.cvc.csar.CSARArchive; import org.onap.cvc.csar.CSARArchive.CSARErrorEntryMissing; import org.onap.cvc.csar.cc.VTPValidateCSARBase; +import org.onap.cvc.csar.parser.SourcesParser; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; @OnapCommandSchema(schema = "vtp-validate-csar-r01123.yaml") public class VTPValidateCSARR01123 extends VTPValidateCSARBase { @@ -27,19 +38,115 @@ public class VTPValidateCSARR01123 extends VTPValidateCSARBase { public static class CSARErrorEntryVNFProviderDetailsNotFound extends CSARErrorEntryMissing { public CSARErrorEntryVNFProviderDetailsNotFound() { super("VNF Vendor details", - CSARArchive.TOSCA_METADATA + " or " + CSARArchive.TOSCA_METADATA_TOSCA_META_ENTRY_DEFINITIONS + " file"); + CSARArchive.TOSCA_METADATA + " or " + CSARArchive.TOSCA_METADATA_TOSCA_META_ENTRY_DEFINITIONS + " file"); this.setCode("0x1000"); } } + public static class CSARErrorNotAllFilesLocatedInCSARWhereListedInManifest extends CSARErrorEntryMissing { + CSARErrorNotAllFilesLocatedInCSARWhereListedInManifest(List<String> fileInCsarThatAreNotLocatedInManifest) { + super("Source", + CSARArchive.TOSCA_METADATA); + this.setCode("0x1001"); + this.message = "file(s): [" + + String.join(", ", fileInCsarThatAreNotLocatedInManifest) + + "] available in CSAR, but cannot be found in Manifest as Source"; + } + } + + public static class CSARErrorNotAllFilesLocatedInManifestWhereListedInCsar extends CSARErrorEntryMissing { + CSARErrorNotAllFilesLocatedInManifestWhereListedInCsar(List<String> fileInCsarThatAreNotLocatedInManifest) { + super("Source", + CSARArchive.TOSCA_METADATA); + this.setCode("0x1002"); + this.message = "file(s): [" + + String.join(", ", fileInCsarThatAreNotLocatedInManifest) + + "] defined in Manifest as Source, but cannot be found in CSAR"; + } + } + @Override protected void validateCSAR(CSARArchive csar) throws Exception { + verifyThatProviderDataAreDefined(csar); + verifyPackageFileStructure(csar); + } + + private void verifyPackageFileStructure(CSARArchive csar) throws IOException { + Path rootFolder = getRootFolder(csar); + List<String> filesInCsar = getAllFilesInDirectory(rootFolder); + List<String> sourcesInManifest = getAllFilesFromManifestSources(csar.getManifest()); + + if (areAllFilesDefinedInManifest(filesInCsar, sourcesInManifest)) { + verifyThatAllFilesFromCsarAreDefinedInManifest(filesInCsar, sourcesInManifest); + verifyThatAllFilesDefinedInManifestAreAvailableInCsar(sourcesInManifest, filesInCsar); + } + } + + private void verifyThatProviderDataAreDefined(CSARArchive csar) { if (csar.getVendorName() == null || - csar.getVersion() == null) { + csar.getVersion() == null) { errors.add(new CSARErrorEntryVNFProviderDetailsNotFound()); } } + private Path getRootFolder(CSARArchive csar) throws IOException { + return csar.getWorkspace().getPathToCsarFolder() + .orElseThrow(() -> new IOException("Couldn't find CSAR root catalog")); + } + + + private void verifyThatAllFilesDefinedInManifestAreAvailableInCsar(List<String> sourcesInManifest, List<String> filesInCsar) { + if(!filesInCsar.containsAll(sourcesInManifest)){ + List<String> sourcesNotAvailableInCsarFile = fetchElementsNotAvailableAtSecondList(sourcesInManifest, filesInCsar); + errors.add(new CSARErrorNotAllFilesLocatedInManifestWhereListedInCsar(sourcesNotAvailableInCsarFile)); + } + } + + private void verifyThatAllFilesFromCsarAreDefinedInManifest(List<String> filesInCsar, List<String> sourcesInManifest) { + if(!sourcesInManifest.containsAll(filesInCsar) ){ + List<String> filesNotDefinedInManifestFile = fetchElementsNotAvailableAtSecondList(filesInCsar, sourcesInManifest); + errors.add(new CSARErrorNotAllFilesLocatedInCSARWhereListedInManifest(filesNotDefinedInManifestFile)); + } + } + + private List<String> fetchElementsNotAvailableAtSecondList(List<String> firstList, List<String> secondList) { + List<String> copyOfFirstList = new ArrayList<>(firstList); + copyOfFirstList.removeAll(secondList); + return copyOfFirstList; + } + + private boolean areAllFilesDefinedInManifest(List<String> filesInCsar, List<String> sourcesInManifest) { + return filesInCsar.size() != sourcesInManifest.size(); + } + + private List<String> getAllFilesFromManifestSources(CSARArchive.Manifest manifest) { + return manifest.getSources() + .stream() + .map(SourcesParser.Source::getValue) + .filter(filterOutManifestFile()) + .collect(Collectors.toList()); + } + + private List<String> getAllFilesInDirectory(Path rootPath) throws IOException { + try (Stream<Path> paths = Files.walk(rootPath, Integer.MAX_VALUE)) { + return paths + .filter(filterOutDirectories()) + .map(rootPath::relativize) + .map(String::valueOf) + .filter(filterOutManifestFile()) + .collect(Collectors.toList()); + } + } + + private Predicate<Path> filterOutDirectories() { + return path -> !Files.isDirectory(path); + } + + + private Predicate<String> filterOutManifestFile() { + return path -> !path.endsWith(".mf"); + } + @Override protected String getVnfReqsNo() { return "R01123"; diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java index fefe65b..05feb54 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206.java @@ -26,6 +26,10 @@ import org.onap.cvc.csar.cc.VTPValidateCSARBase; import org.onap.cvc.csar.parser.ManifestFileModel; import org.onap.cvc.csar.parser.ManifestFileSplitter; import org.onap.cvc.csar.parser.SourcesParser; +import org.onap.cvc.csar.security.CertificateLoadingException; +import org.onap.cvc.csar.security.CmsSignatureData; +import org.onap.cvc.csar.security.CmsSignatureDataFactory; +import org.onap.cvc.csar.security.CmsSignatureLoadingException; import org.onap.cvc.csar.security.CmsSignatureValidator; import org.onap.cvc.csar.security.CmsSignatureValidatorException; import org.onap.cvc.csar.security.ShaHashCodeGenerator; @@ -50,23 +54,31 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { private static final Logger LOG = LoggerFactory.getLogger(VTPValidateCSARR130206.class); private static final String SHA_256 = "SHA-256"; private static final String SHA_512 = "SHA-512"; + private static final String EMPTY_STRING = ""; private final ShaHashCodeGenerator shaHashCodeGenerator = new ShaHashCodeGenerator(); private final ManifestFileSignatureValidator manifestFileSignatureValidator = new ManifestFileSignatureValidator(); public static class CSARErrorUnableToFindCertificate extends CSARArchive.CSARError { - CSARErrorUnableToFindCertificate(String paramName) { + CSARErrorUnableToFindCertificate() { super("0x4001"); - this.message = String.format("Unable to find cert file defined by %s!", paramName); + this.message = "Unable to find cert file!"; } } - public static class CSARErrorUnableToFindCmsSection extends CSARArchive.CSARError { + public static class CSARErrorUnableToFindCms extends CSARArchive.CSARError { - CSARErrorUnableToFindCmsSection() { + CSARErrorUnableToFindCms() { super("0x4002"); - this.message = "Unable to find CMS section in manifest!"; + this.message = "Unable to find cms signature!"; + } + } + + public static class CSARErrorUnableToLoadCms extends CSARArchive.CSARError { + CSARErrorUnableToLoadCms() { + super("0x4002"); + this.message = "Unable to load cms signature!"; } } @@ -106,7 +118,7 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { CSARErrorInvalidSignature() { super("0x4007"); - this.message = "File has invalid CMS signature!"; + this.message = "File has invalid signature!"; } } @@ -118,6 +130,61 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { } } + public static class CSARErrorUnableToFindEntryCertificate extends CSARArchive.CSARError { + + CSARErrorUnableToFindEntryCertificate() { + super("0x4009"); + this.message = "Unable to find cert file defined by ETSI-Entry-Certificate!"; + } + } + + public static class CSARErrorEntryCertificateIsDefinedDespiteTheCms extends CSARArchive.CSARError { + + CSARErrorEntryCertificateIsDefinedDespiteTheCms() { + super("0x4011"); + this.message = "ETSI-Entry-Certificate entry in Tosca.meta is defined despite the certificate is included in the signature container"; + } + } + + public static class CSARErrorEntryCertificateIsPresentDespiteTheCms extends CSARArchive.CSARError { + + CSARErrorEntryCertificateIsPresentDespiteTheCms() { + super("0x4012"); + this.message = "ETSI-Entry-Certificate certificate present despite the certificate is included in the signature container"; + } + } + + public static class CSARErrorRootCertificateIsPresentDespiteTheCms extends CSARArchive.CSARError { + + CSARErrorRootCertificateIsPresentDespiteTheCms() { + super("0x4013"); + this.message = "Certificate present in root catalog despite the certificate is included in the signature container"; + } + } + + public static class CSARErrorRootCertificateIsPresentDespiteTheEtsiEntryCertificate extends CSARArchive.CSARError { + + CSARErrorRootCertificateIsPresentDespiteTheEtsiEntryCertificate() { + super("0x4013"); + this.message = "Certificate present in root catalog despite the TOSCA.meta file"; + } + } + + public static class CSARErrorUnableToFindCertificateEntryInTosca extends CSARArchive.CSARError { + + CSARErrorUnableToFindCertificateEntryInTosca() { + super("0x4014"); + this.message = "Unable to find ETSI-Entry-Certificate in Tosca file"; + } + } + + public static class CSARWarningNoSecurity extends CSARArchive.CSARErrorWarning { + CSARWarningNoSecurity() { + super(EMPTY_STRING, EMPTY_STRING, -1, EMPTY_STRING); + this.message = "Warning. Consider adding package integrity and authenticity assurance according to ETSI NFV-SOL 004 Security Option 1"; + } + } + @Override protected void validateCSAR(CSARArchive csar) throws OnapCommandException { @@ -137,20 +204,146 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { } private void validate(CSARArchive csar, Path csarRootDirectory) throws IOException, NoSuchAlgorithmException { - final CSARArchive.Manifest manifest = csar.getManifest(); + if (containsCms(csar.getManifest())) { + validateCmsSignature(csar, csarRootDirectory); + } else if ( + ( containsToscaMeta(csar) && containsCertificateInTosca(csar.getToscaMeta()) ) || + containsCertificateInRootCatalog(csar) || + containsHashOrAlgorithm(csar.getManifest())) { + this.errors.add(new CSARErrorUnableToFindCms()); + } else { + this.errors.add(new CSARWarningNoSecurity()); + } + } + + private void validateCmsSignature(CSARArchive csar, Path csarRootDirectory) throws NoSuchAlgorithmException, IOException { + try { + CmsSignatureData signatureData = this.manifestFileSignatureValidator.createSignatureData(csar.getManifestMfFile()); + if (signatureData.getCertificate().isPresent()) { + validateCertificationUsingCmsCertificate(signatureData, csar, csarRootDirectory); + } else if (containsToscaMeta(csar)) { + validateCertificationUsingTosca(signatureData, csar, csarRootDirectory); + } else if (containsCertificateInRootCatalog(csar)) { + validateCertificationUsingCertificateFromRootDirectory(signatureData, csar, csarRootDirectory); + } else { + this.errors.add(new CSARErrorUnableToFindCertificate()); + } + } catch (CmsSignatureLoadingException e) { + LOG.error("Unable to load CMS!", e); + this.errors.add(new CSARErrorUnableToLoadCms()); + } + } + + private boolean containsCms(CSARArchive.Manifest manifest) { + String cms = manifest.getCms(); + return cms != null && !cms.equals(EMPTY_STRING); + } + + private boolean containsToscaMeta(CSARArchive archive) { + return archive.getToscaMetaFile() != null; + } + + private boolean containsCertificateInTosca(CSARArchive.TOSCAMeta toscaMeta) { + String certificate = toscaMeta.getEntryCertificate(); + return certificate != null && !certificate.equals(EMPTY_STRING); + } + + private boolean containsCertificateInRootCatalog(CSARArchive csar) { + File potentialCertificateFileInRootDirectory = getCertificateFromRootDirectory(csar); + return potentialCertificateFileInRootDirectory.exists(); + } - validateSecurityStructure(csar, csarRootDirectory); + private boolean containsHashOrAlgorithm(CSARArchive.Manifest manifest) { + return manifest.getSources().stream().anyMatch( + source -> + !source.getAlgorithm().equals(EMPTY_STRING) || + !source.getHash().equals(EMPTY_STRING) + ); + } + + private void validateCertificationUsingCmsCertificate(CmsSignatureData signatureData, CSARArchive csar, Path csarRootDirectory) + throws NoSuchAlgorithmException, IOException { + validateAllSources(csar, csarRootDirectory); + validateFileSignature(signatureData); + if (containsCertificateInTosca(csar.getToscaMeta())) { + errors.add(new CSARErrorEntryCertificateIsDefinedDespiteTheCms()); + if (csar.getFileFromCsar(csar.getToscaMeta().getEntryCertificate()).exists()) { + errors.add(new CSARErrorEntryCertificateIsPresentDespiteTheCms()); + } + } + if (containsCertificateInRootCatalog(csar)) { + errors.add(new CSARErrorRootCertificateIsPresentDespiteTheCms()); + } + } + + private void validateCertificationUsingTosca(CmsSignatureData signatureData, CSARArchive csar, Path csarRootDirectory) + throws NoSuchAlgorithmException, IOException { + validateAllSources(csar, csarRootDirectory); + if (loadCertificateFromTosca(signatureData, csar)) { + validateFileSignature(signatureData); + } + if (containsCertificateInRootCatalog(csar) && rootCertificateIsNotReferredAsToscaEtsiEntryCertificate(csar)) { + errors.add(new CSARErrorRootCertificateIsPresentDespiteTheEtsiEntryCertificate()); + } + } + + private boolean loadCertificateFromTosca(CmsSignatureData signatureData, CSARArchive csar) { + if(csar.getToscaMeta().getEntryCertificate() != null) { + try { + final Path absolutePathToEntryCertificate = csar.getFileFromCsar(csar.getToscaMeta().getEntryCertificate()).toPath(); + signatureData.loadCertificate(absolutePathToEntryCertificate); + return true; + } catch (CertificateLoadingException e) { + this.errors.add(new CSARErrorUnableToFindEntryCertificate()); + return false; + } + } else { + this.errors.add(new CSARErrorUnableToFindCertificateEntryInTosca()); + return false; + } + } + + private boolean rootCertificateIsNotReferredAsToscaEtsiEntryCertificate(CSARArchive csar) { + String pathToRootCertificate = getCertificateFromRootDirectory(csar).getPath(); + String pathToEntryEtsiCertificate = csar.getFileFromCsar(csar.getToscaMeta().getEntryCertificate()).getPath(); + return !pathToRootCertificate.equals(pathToEntryEtsiCertificate); + } + + private void validateCertificationUsingCertificateFromRootDirectory(CmsSignatureData signatureData, CSARArchive csar, Path csarRootDirectory) + throws NoSuchAlgorithmException, IOException { + validateAllSources(csar, csarRootDirectory); + if (loadCertificateFromRootDirectory(signatureData, csar)) { + validateFileSignature(signatureData); + } + } + + private boolean loadCertificateFromRootDirectory(CmsSignatureData signatureData, CSARArchive csar) { + try { + File certificateFileFromRootDirectory = getCertificateFromRootDirectory(csar); + signatureData.loadCertificate(certificateFileFromRootDirectory.toPath()); + return true; + } catch (CertificateLoadingException e) { + LOG.error("Uable to read ETSI entry certificate file!", e); + return false; + } + } + + private File getCertificateFromRootDirectory(CSARArchive csar) { + String nameOfCertificate = + csar.getManifestMfFile().getName().split("\\.")[0] + + ".cert"; + return csar.getFileFromCsar(nameOfCertificate); + } + + private void validateAllSources(CSARArchive csar, Path csarRootDirectory) + throws NoSuchAlgorithmException, IOException { + final CSARArchive.Manifest manifest = csar.getManifest(); validateSources(csarRootDirectory, manifest); final Map<String, Map<String, List<String>>> nonMano = manifest.getNonMano(); final List<SourcesParser.Source> sources = manifest.getSources(); validateNonManoCohesionWithSources(nonMano, sources); - - final File manifestMfFile = csar.getManifestMfFile(); - if (manifestMfFile != null) { - validateFileSignature(manifestMfFile); - } } private void validateNonManoCohesionWithSources(final Map<String, Map<String, List<String>>> nonMano, @@ -174,36 +367,13 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { } - private void validateFileSignature(File manifestMfFile) { - final boolean isValid = this.manifestFileSignatureValidator.isValid(manifestMfFile); + private void validateFileSignature(CmsSignatureData signatureData) { + final boolean isValid = this.manifestFileSignatureValidator.isValid(signatureData); if (!isValid) { this.errors.add(new CSARErrorInvalidSignature()); } } - private void validateSecurityStructure(CSARArchive csar, Path csarRootDirectory) { - final CSARArchive.Manifest manifest = csar.getManifest(); - final CSARArchive.TOSCAMeta toscaMeta = csar.getToscaMeta(); - final String entryCertificateParamName = csar.getEntryCertificateParamName(); - final Optional<File> entryCertificate = resolveCertificateFilePath(toscaMeta, csarRootDirectory); - if (!entryCertificate.isPresent() || !entryCertificate.get().exists()) { - this.errors.add(new CSARErrorUnableToFindCertificate(entryCertificateParamName)); - } - - if (manifest.getCms() == null || manifest.getCms().isEmpty()) { - this.errors.add(new CSARErrorUnableToFindCmsSection()); - } - } - - private Optional<File> resolveCertificateFilePath(CSARArchive.TOSCAMeta toscaMeta, Path csarRootDirectory) { - final String certificatePath = toscaMeta.getEntryCertificate(); - if (certificatePath == null) { - return Optional.empty(); - } else { - return Optional.of(csarRootDirectory.resolve(certificatePath).toFile()); - } - } - private void validateSources(Path csarRootDirectory, CSARArchive.Manifest manifest) throws NoSuchAlgorithmException, IOException { final List<SourcesParser.Source> sources = manifest.getSources(); @@ -256,18 +426,23 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { } - class ManifestFileSignatureValidator { + static class ManifestFileSignatureValidator { - private final Logger LOG = LoggerFactory.getLogger(ManifestFileSignatureValidator.class); private final ManifestFileSplitter manifestFileSplitter = new ManifestFileSplitter(); private final CmsSignatureValidator cmsSignatureValidator = new CmsSignatureValidator(); + private final CmsSignatureDataFactory cmsSignatureDataFactory = new CmsSignatureDataFactory(); + + CmsSignatureData createSignatureData(File manifestFile) throws CmsSignatureLoadingException { + ManifestFileModel mf = manifestFileSplitter.split(manifestFile); + return cmsSignatureDataFactory.createForFirstSigner( + toBytes(mf.getCMS(), mf.getNewLine()), + toBytes(mf.getData(), mf.getNewLine()) + ); + } - boolean isValid(File manifestFile) { + boolean isValid(CmsSignatureData signatureData) { try { - ManifestFileModel mf = manifestFileSplitter.split(manifestFile); - return cmsSignatureValidator.verifySignedData(toBytes(mf.getCMS(), mf.getNewLine()), - Optional.empty(), - toBytes(mf.getData(), mf.getNewLine())); + return cmsSignatureValidator.verifySignedData(signatureData); } catch (CmsSignatureValidatorException e) { LOG.error("Unable to verify signed data!", e); return false; @@ -279,4 +454,5 @@ public class VTPValidateCSARR130206 extends VTPValidateCSARBase { return updatedData.getBytes(Charset.defaultCharset()); } } + } diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR816745.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR816745.java new file mode 100644 index 0000000..b43dbba --- /dev/null +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR816745.java @@ -0,0 +1,140 @@ +/* + * 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.cvc.csar.cc.sol004; + +import org.onap.cli.fw.schema.OnapCommandSchema; +import org.onap.cvc.csar.CSARArchive; +import org.onap.cvc.csar.cc.VTPValidateCSARBase; +import org.onap.validation.yaml.YamlFileValidator; +import org.onap.validation.yaml.error.YamlDocumentValidationError; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.error.YAMLException; + +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@OnapCommandSchema(schema = "vtp-validate-csar-r816745.yaml") +public class VTPValidateCSARR816745 extends VTPValidateCSARBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(VTPValidateCSARR816745.class); + + private static class CSARPmDictionaryValidationError extends CSARArchive.CSARError { + + CSARPmDictionaryValidationError(int documentNumber, String file, String path, String message) { + super("0x1000"); + this.message = String.format( + "Invalid YAML document in PM_Dictionary file. %n" + + "In document number %s (excluding document with schema) error occur. %n" + + "Path: %s%n" + + "%s", + documentNumber, path, message + ); + this.file = file; + } + + } + + private static class CSARPmDictionaryLoadingError extends CSARArchive.CSARError { + + CSARPmDictionaryLoadingError(String file, String message) { + super("0x2000"); + this.message = String.format( + "Fail to load PM_Dictionary With error: %s", + message + ); + this.file = file; + } + + } + + private static final String PM_DICTIONARY = "onap_pm_dictionary"; + private static final String SOURCE_ELEMENT_TAG = "Source"; + + @Override + protected void validateCSAR(CSARArchive csar) { + Map<String, Map<String, List<String>>> nonManoFields = csar.getManifest().getNonMano(); + String rootPath = csar.getWorkspace().getPathToCsarFolder().map(Path::toString).orElse("/"); + if (nonManoFields.containsKey(PM_DICTIONARY)) { + getLocationOfPmDictionaryFile(nonManoFields, csar.getManifestMfFile().getName()).ifPresent(pmDictionary -> + validateYamlFile(rootPath+"/",pmDictionary) + ); + } + } + + private Optional<String> getLocationOfPmDictionaryFile(Map<String, Map<String, List<String>>> nonManoFields, String manifestFileName) { + if(nonManoFields.get(PM_DICTIONARY).containsKey(SOURCE_ELEMENT_TAG)) { + return getPathToPmDictionary(nonManoFields, SOURCE_ELEMENT_TAG); + } else if(nonManoFields.get(PM_DICTIONARY).containsKey(SOURCE_ELEMENT_TAG.toLowerCase())) { + return getPathToPmDictionary(nonManoFields, SOURCE_ELEMENT_TAG.toLowerCase()); + } else { + addPmDictionaryLoadingError(manifestFileName, PM_DICTIONARY +" in manifest does not contains key 'Source'"); + return Optional.empty(); + } + } + + private Optional<String> getPathToPmDictionary(Map<String, Map<String, List<String>>> nonManoFields, String sourceElementTag) { + return Optional.ofNullable(nonManoFields.get(PM_DICTIONARY).get(sourceElementTag).get(0)); + } + + private void validateYamlFile(String rootPath, String artifactPath) { + try { + List<YamlDocumentValidationError> validationErrors = + new YamlFileValidator().validateYamlFileWithSchema(rootPath+artifactPath); + addAllErrorsReportedByVaidator(artifactPath, validationErrors); + } catch (YamlProcessingException | YAMLException e) { + LOGGER.error("Failed to load PM_Dictionary file.", e); + addPmDictionaryLoadingError(artifactPath, e); + } + + } + + private void addPmDictionaryLoadingError(String artifactPath, Exception e) { + addPmDictionaryLoadingError(artifactPath,e.getMessage()); + } + + private void addPmDictionaryLoadingError(String artifactPath, String message) { + errors.add(new CSARPmDictionaryLoadingError( + artifactPath, + message + )); + } + + private void addAllErrorsReportedByVaidator(String artifactPath, List<YamlDocumentValidationError> validationErrors) { + for(YamlDocumentValidationError validationError: validationErrors) { + addPmDictionaryValidationError(artifactPath, validationError); + } + } + + private void addPmDictionaryValidationError(String artifactPath, YamlDocumentValidationError validationError) { + errors.add(new CSARPmDictionaryValidationError( + validationError.getYamlDocumentNumber(), + artifactPath, + validationError.getPath(), + validationError.getMessage() + )); + } + + @Override + protected String getVnfReqsNo() { + return "R816745"; + } + +} diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082.java b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082.java index 1061480..27e3ce9 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082.java @@ -23,13 +23,14 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.util.ArrayList; -import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; + import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; @@ -113,15 +114,24 @@ public class VTPValidateCSARR972082 extends VTPValidateCSARBase { } } + private static class InvalidFileExtensionError extends PnfCSARError { + + private InvalidFileExtensionError(final String fileName) { + super(ERROR_CODE, + String.format("Invalid. File extension %s is invalid", fileName), + UNKNOWN_LINE_NUMBER, + fileName); + } + } + private static class ValidateNonManoSection { + private static final String ATTRIBUTE_NAME = "onap_pnf_sw_information"; + private final CSARArchive csar; private final String fileName; private final Map<String, Map<String, List<String>>> nonMano; private final List<CSARError> errors = new ArrayList<>(); - private final List<String> attributeNames = Arrays.asList( - "onap_pnf_sw_information" - ); private ValidateNonManoSection(final CSARArchive csar, final String fileName, final Map<String, Map<String, List<String>>> nonMano) { @@ -141,28 +151,20 @@ public class VTPValidateCSARR972082 extends VTPValidateCSARBase { } private List<CSARError> validate() { - if (nonMano.keySet().stream().filter(Objects::nonNull).count() > 0) { - nonMano.keySet().stream().filter(Objects::nonNull).forEach(this::validateAttribute); + List<String> attributesNotNull = nonMano.keySet().stream() + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (!attributesNotNull.isEmpty()) { + attributesNotNull.forEach(this::validateAttribute); } else { - errors.add(new PnfCSARErrorEntryMissing( - attributeNames.toString(), - fileName, - UNKNOWN_LINE_NUMBER) - ); + errors.add(new PnfCSARErrorEntryMissing(ATTRIBUTE_NAME, fileName, UNKNOWN_LINE_NUMBER)); } return errors; } private void validateAttribute(final String nonManoAttributes) { - - if (!attributeNames.contains(nonManoAttributes)) { - errors.add(new PnfCSARErrorEntryMissing( - nonManoAttributes, - fileName, - UNKNOWN_LINE_NUMBER) - ); - } else { + if (ATTRIBUTE_NAME.equals(nonManoAttributes)) { validateSourceElementsUnderAttribute(nonManoAttributes); } } @@ -194,6 +196,9 @@ public class VTPValidateCSARR972082 extends VTPValidateCSARBase { if (StringUtils.isEmpty(swInformationFilePath)) { errors.add(new MissingSourceElementUnderAttributeError("", swInformationFilePath)); return; + } else if (!swInformationFilePath.matches(".*\\.yaml$")) { + errors.add(new InvalidFileExtensionError(swInformationFilePath)); + return; } final Optional<PnfSoftwareInformation> parsedYaml = parse(swInformationFilePath); if (!parsedYaml.isPresent()) { diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/parser/ManifestLine.java b/csarvalidation/src/main/java/org/onap/cvc/csar/parser/ManifestLine.java index 390c534..eefc771 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/parser/ManifestLine.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/parser/ManifestLine.java @@ -54,4 +54,8 @@ public class ManifestLine { return line.trim().isEmpty(); } + boolean contains(String word) { + return line.contains(word); + } + } diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/parser/MetadataParser.java b/csarvalidation/src/main/java/org/onap/cvc/csar/parser/MetadataParser.java index b0c06ee..f529c45 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/parser/MetadataParser.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/parser/MetadataParser.java @@ -85,7 +85,7 @@ public class MetadataParser { private boolean isNewSection(Pair<String, String> data) { String key = data.getKey().trim(); String value = data.getValue().trim(); - return key.matches("[a-zA-z_0-9]+") && (value.isEmpty() || ManifestLine.of(value).startsWith("#")); + return key.matches("[a-zA-Z_0-9]+") && (value.isEmpty() || ManifestLine.of(value).startsWith("#")); } private boolean isSourceSection(Pair<String, String> data) { diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/parser/NonManoArtifactsParser.java b/csarvalidation/src/main/java/org/onap/cvc/csar/parser/NonManoArtifactsParser.java index d27ef68..1aa7d32 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/parser/NonManoArtifactsParser.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/parser/NonManoArtifactsParser.java @@ -26,10 +26,12 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import static org.onap.cvc.csar.parser.ManifestConsts.BEGIN_CMS_SECTION; import static org.onap.cvc.csar.parser.ManifestConsts.NON_MANO_ARTIFACT_SETS_TAG_SECTION; public class NonManoArtifactsParser { + public Optional<Pair<Map<String, Map<String, List<String>>>, List<CSARArchive.CSARError>>> parse(List<String> lines) { Map<String, Map<String, List<String>>> nonManoArtifacts = new HashMap<>(); List<CSARArchive.CSARError> errors = new ArrayList<>(); @@ -41,16 +43,17 @@ public class NonManoArtifactsParser { ManifestLine manifestLine = ManifestLine.of(line); if (manifestLine.startsWith(NON_MANO_ARTIFACT_SETS_TAG_SECTION)) { isNonManoArtifactsSectionAvailable = true; + } else if (manifestLine.contains(BEGIN_CMS_SECTION)) { + break; } else if (isNonManoArtifactsSectionAvailable) { Pair<String, String> data = manifestLine.parse(); if (isNewSection(data)) { attributeName = data.getKey(); nonManoArtifacts.put(attributeName, new HashMap<>()); - continue; - } - + } else { handleNonManoArtifactLine(nonManoArtifacts, attributeName, data); + } } } @@ -64,7 +67,7 @@ public class NonManoArtifactsParser { private boolean isNewSection(Pair<String, String> data) { String key = data.getKey().trim(); String value = data.getValue().trim(); - return key.matches("[a-zA-z_0-9]+") && (value.isEmpty() || ManifestLine.of(value).startsWith("#")); + return key.matches("[a-zA-Z_0-9]+") && (value.isEmpty() || ManifestLine.of(value).startsWith("#")); } private void handleNonManoArtifactLine( diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CertificateLoadingException.java b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CertificateLoadingException.java new file mode 100644 index 0000000..2be5be2 --- /dev/null +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CertificateLoadingException.java @@ -0,0 +1,25 @@ +/* + * Copyright 2020 Nokia + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.cvc.csar.security; + +public class CertificateLoadingException extends RuntimeException { + + public CertificateLoadingException(String s, Throwable t) { + super(s, t); + } +} diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureData.java b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureData.java new file mode 100644 index 0000000..456f365 --- /dev/null +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureData.java @@ -0,0 +1,75 @@ +/* + * Copyright 2020 Nokia + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.cvc.csar.security; + +import org.bouncycastle.cms.SignerInformation; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Optional; + +public class CmsSignatureData { + + private X509Certificate certificate; + private final SignerInformation signerInformation; + + public CmsSignatureData(X509Certificate certificate, SignerInformation signerInformation) { + this.certificate = certificate; + this.signerInformation = signerInformation; + } + + public CmsSignatureData(SignerInformation signerInformation) { + this.signerInformation = signerInformation; + } + + public Optional<X509Certificate> getCertificate() { + return Optional.ofNullable(certificate); + } + + public SignerInformation getSignerInformation() { + return signerInformation; + } + + public void loadCertificate(Path pathToCertificate) throws CertificateLoadingException { + try { + loadCertificate(Files.readAllBytes(pathToCertificate)); + } catch (IOException e) { + final String errorMessage = String.format( + "Error during loading Certificate from given path: %s !" + ,pathToCertificate + ); + throw new CertificateLoadingException(errorMessage, e); + } + } + + public void loadCertificate(final byte[] certificate) throws CertificateLoadingException { + try (InputStream in = new ByteArrayInputStream(certificate)) { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + this.certificate = (X509Certificate) factory.generateCertificate(in); + } catch (IOException | CertificateException e) { + throw new CertificateLoadingException("Error during loading Certificate from bytes!", e); + } + } + +} diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureDataFactory.java b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureDataFactory.java new file mode 100644 index 0000000..2744bc6 --- /dev/null +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureDataFactory.java @@ -0,0 +1,91 @@ +/* + * Copyright 2020 Nokia + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.cvc.csar.security; + +import org.bouncycastle.asn1.cms.ContentInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cms.CMSException; +import org.bouncycastle.cms.CMSProcessableByteArray; +import org.bouncycastle.cms.CMSSignedData; +import org.bouncycastle.cms.CMSTypedData; +import org.bouncycastle.cms.SignerInformation; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.util.Store; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.Optional; + +public class CmsSignatureDataFactory { + + public CmsSignatureData createForFirstSigner(final byte[] cmsSignature, final byte[] fileContent) + throws CmsSignatureLoadingException{ + + try (ByteArrayInputStream cmsSignatureStream = new ByteArrayInputStream(cmsSignature)) { + CMSSignedData signedData = getCMSSignedData(fileContent, cmsSignatureStream); + Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners(); + Store<X509CertificateHolder> certificates = signedData.getCertificates(); + SignerInformation firstSigner = getFirstSigner(signers); + CmsSignatureData signatureData = new CmsSignatureData(firstSigner); + getFirstSignerCertificate(certificates, firstSigner).ifPresent( + signatureData::loadCertificate + ); + return signatureData; + } catch (CertificateLoadingException | IOException | CMSException e) { + throw new CmsSignatureLoadingException("Unexpected error occurred during signature validation!", e); + } + } + + private SignerInformation getFirstSigner(Collection<SignerInformation> signers) { + return signers.iterator().next(); + } + + private Optional<byte[]> getFirstSignerCertificate( + Store<X509CertificateHolder> certificates, + SignerInformation firstSigner) + throws IOException { + Collection<X509CertificateHolder> firstSignerCertificates = certificates.getMatches(firstSigner.getSID()); + Optional<byte[]> cert; + if (!firstSignerCertificates.isEmpty()) { + X509CertificateHolder firstSignerFirstCertificate = firstSignerCertificates.iterator().next(); + cert = Optional.of(firstSignerFirstCertificate.getEncoded()); + } else { + cert = Optional.empty(); + } + return cert; + } + + + private CMSSignedData getCMSSignedData(byte[] innerPackageFileCSAR, ByteArrayInputStream signatureStream) throws IOException, CmsSignatureLoadingException, CMSException { + ContentInfo signature = produceSignature(signatureStream); + CMSTypedData signedContent = new CMSProcessableByteArray(innerPackageFileCSAR); + return new CMSSignedData(signedContent, signature); + } + + private ContentInfo produceSignature(ByteArrayInputStream signatureStream) throws IOException, CmsSignatureLoadingException { + Object parsedObject = new PEMParser(new InputStreamReader(signatureStream, Charset.defaultCharset())).readObject(); + if (!(parsedObject instanceof ContentInfo)) { + throw new CmsSignatureLoadingException("Signature is not recognized!"); + } + return ContentInfo.getInstance(parsedObject); + } + +} diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureLoadingException.java b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureLoadingException.java new file mode 100644 index 0000000..0e203b2 --- /dev/null +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureLoadingException.java @@ -0,0 +1,29 @@ +/* + * Copyright 2020 Nokia + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.cvc.csar.security; + +public class CmsSignatureLoadingException extends Exception { + + public CmsSignatureLoadingException(String s) { + super(s); + } + + public CmsSignatureLoadingException(String s, Throwable t) { + super(s, t); + } +} diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidator.java b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidator.java index b8b3714..5d7b879 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidator.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidator.java @@ -17,30 +17,14 @@ package org.onap.cvc.csar.security; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cms.CMSException; -import org.bouncycastle.cms.CMSProcessableByteArray; -import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.CMSSignerDigestMismatchException; -import org.bouncycastle.cms.CMSTypedData; -import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; -import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Store; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.util.Collection; import java.util.Optional; public class CmsSignatureValidator { @@ -52,63 +36,30 @@ public class CmsSignatureValidator { final Optional<byte[]> certificate, final byte[] fileContent) throws CmsSignatureValidatorException { - try (ByteArrayInputStream cmsSignatureStream = new ByteArrayInputStream(cmsSignature)) { - CMSSignedData signedData = getCMSSignedData(fileContent, cmsSignatureStream); - Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners(); - SignerInformation firstSigner = signers.iterator().next(); - - Store certificates = signedData.getCertificates(); - X509Certificate cert; - if (!certificate.isPresent()) { - X509CertificateHolder firstSignerFirstCertificate = getX509CertificateHolder(firstSigner, certificates); - cert = loadCertificate(firstSignerFirstCertificate.getEncoded()); - } else { - cert = loadCertificate(certificate.get()); + try { + CmsSignatureData signatureData = new CmsSignatureDataFactory().createForFirstSigner(cmsSignature, fileContent); + if( signatureData.getCertificate().isEmpty() ) { + signatureData.loadCertificate(certificate.orElseThrow(() -> new CmsSignatureValidatorException("No certificate found in cms signature and ETSI-Entry-Certificate doesn't exist"))); } + return verifySignedData(signatureData); + } catch ( CmsSignatureLoadingException e) { + throw new CmsSignatureValidatorException("Unexpected error occurred during signature validation!", e); + } + } - return firstSigner.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert)); + public boolean verifySignedData(final CmsSignatureData signatureData) throws CmsSignatureValidatorException { + try { + X509Certificate certificate = signatureData.getCertificate().orElseThrow(() -> new CMSException("No certificate found in signature data!")); + return signatureData.getSignerInformation().verify(new JcaSimpleSignerInfoVerifierBuilder().build(certificate)); } catch (CMSSignerDigestMismatchException e){ //message-digest attribute value does not match calculated value LOG.warn("CMS signer digest mismatch.", e); return false; } - catch (OperatorCreationException | IOException | CMSException e) { + catch (OperatorCreationException | CMSException e) { throw new CmsSignatureValidatorException("Unexpected error occurred during signature validation!", e); } } - private X509CertificateHolder getX509CertificateHolder(SignerInformation firstSigner, Store certificates) throws CmsSignatureValidatorException { - Collection<X509CertificateHolder> firstSignerCertificates = certificates.getMatches(firstSigner.getSID()); - if(!firstSignerCertificates.iterator().hasNext()){ - throw new CmsSignatureValidatorException("No certificate found in cms signature that should contain one!"); - } - return firstSignerCertificates.iterator().next(); - } - - private CMSSignedData getCMSSignedData(byte[] innerPackageFileCSAR, ByteArrayInputStream signatureStream) throws IOException, CmsSignatureValidatorException, CMSException { - ContentInfo signature = produceSignature(signatureStream); - CMSTypedData signedContent = new CMSProcessableByteArray(innerPackageFileCSAR); - return new CMSSignedData(signedContent, signature); - } - - private ContentInfo produceSignature(ByteArrayInputStream signatureStream) throws IOException, CmsSignatureValidatorException { - Object parsedObject = new PEMParser(new InputStreamReader(signatureStream, Charset.defaultCharset())).readObject(); - if (!(parsedObject instanceof ContentInfo)) { - throw new CmsSignatureValidatorException("Signature is not recognized!"); - } - return ContentInfo.getInstance(parsedObject); - } - - - private X509Certificate loadCertificate(byte[] certFile) throws CmsSignatureValidatorException { - try (InputStream in = new ByteArrayInputStream(certFile)) { - CertificateFactory factory = CertificateFactory.getInstance("X.509"); - return (X509Certificate) factory.generateCertificate(in); - } catch (CertificateException | IOException e) { - throw new CmsSignatureValidatorException("Error during loading Certificate from bytes!", e); - } - } - - } diff --git a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidatorException.java b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidatorException.java index 75cd8de..1f708fd 100644 --- a/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidatorException.java +++ b/csarvalidation/src/main/java/org/onap/cvc/csar/security/CmsSignatureValidatorException.java @@ -25,4 +25,5 @@ public class CmsSignatureValidatorException extends Exception { public CmsSignatureValidatorException(String s, Throwable t) { super(s, t); } + } diff --git a/csarvalidation/src/main/java/org/onap/validation/csar/CsarUtil.java b/csarvalidation/src/main/java/org/onap/validation/csar/CsarUtil.java index c498479..7d48b06 100644 --- a/csarvalidation/src/main/java/org/onap/validation/csar/CsarUtil.java +++ b/csarvalidation/src/main/java/org/onap/validation/csar/CsarUtil.java @@ -28,133 +28,135 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.Enumeration; - import java.util.zip.ZipEntry; import java.util.zip.ZipFile; - - -public class CsarUtil { - - private static final Logger logger = LoggerFactory.getLogger(CsarUtil.class); - - public static String getUnzipDir(String dirName) { - File tmpDir = new File(File.separator + dirName); - return tmpDir.getAbsolutePath().replace(".csar", ""); - } - - /** - * unzip zip file. - * - * @param zipFileName - * file name to zip - * @param extPlace - * extPlace - * @return unzip file names in zip - * @throws IOException - * e1 - * @throws ValidationException - */ - public static HashMap<String, String> unzip(String zipFileName, String extPlace) throws IOException { - HashMap<String, String> unzipFileNames = new HashMap<>(); - - try(ZipFile zipFile = new ZipFile(zipFileName)) { - - Enumeration<?> fileEn = zipFile.entries(); - byte[] buffer = new byte[CommonConstants.BUFFER_SIZE]; - - while (fileEn.hasMoreElements()) { - InputStream input = null; - BufferedOutputStream bos = null; - try { - ZipEntry entry = (ZipEntry) fileEn.nextElement(); - if (entry.isDirectory()) { - continue; - } - - input = zipFile.getInputStream(entry); - File file = new File(extPlace, entry.getName()); - - //Currently it does not support xml based VNF descriptors. - //So skip and proceed to YAML defined files validation only. - if (file.getAbsolutePath().contains("xml"+System.getProperty("file.separator"))) { - continue; - } - - if (!file.getParentFile().exists()) { - FileUtil.createDirectory(file.getParentFile().getAbsolutePath()); - } - - bos = new BufferedOutputStream(new FileOutputStream(file)); - while (true) { - int length = input.read(buffer); - if (length == -1) { - break; - } - bos.write(buffer, 0, length); - } - - unzipFileNames.put(file.getName(), file.getAbsolutePath()); - - } finally { - closeOutputStream(bos); - closeInputStream(input); - } - } - } - return unzipFileNames; - } - - /** - * close InputStream. - * - * @param inputStream - * the inputstream to close - * @throws ValidationException - */ - public static void closeInputStream(InputStream inputStream) { - try { - if (inputStream != null) { - inputStream.close(); - } - } catch (Exception e1) { - logger.error("FILE_IO" + ":" + "close InputStream error! " +ErrorCodes.FILE_IO+" "+ e1.getMessage(), e1); - throw new ValidationException(ErrorCodes.FILE_IO); - } - } - - /** - * close OutputStream. - * - * @param outputStream - * the output stream to close - * @throws ValidationException - */ - public static void closeOutputStream(OutputStream outputStream) { - try { - if (outputStream != null) { - outputStream.close(); - } - } catch (Exception e1) { - logger.error("FILE_IO" + ":" + "close OutputStream error! " +ErrorCodes.FILE_IO, e1); - throw new ValidationException(ErrorCodes.FILE_IO); - - } - } - /** - * - * @param filePath - * @return HashMap<String, String> - */ - public static HashMap<String, String> csarExtract(String filePath) { - - try { - String tempfolder = CsarUtil.getUnzipDir(filePath); - return CsarUtil.unzip(filePath, tempfolder); - - } catch (IOException e1) { - logger.error("CSAR_EXTRACTION" + ":" + "CSAR extraction error ! " +ErrorCodes.FILE_IO+" "+ e1.getMessage(), e1); - throw new ValidationException(ErrorCodes.FILE_IO); - } - } +import java.util.Map; + +public final class CsarUtil { + + private static final Logger logger = LoggerFactory.getLogger(CsarUtil.class); + + private CsarUtil(){ + //It is made private in order to resolve: Utility classes should not have public constructors + } + public static String getUnzipDir(String dirName) { + File tmpDir = new File(File.separator + dirName); + return tmpDir.getAbsolutePath().replace(".csar", ""); + } + + /** + * unzip zip file. + * + * @param zipFileName + * file name to zip + * @param extPlace + * extPlace + * @return unzip file names in zip + * @throws IOException + * e1 + * @throws ValidationException + */ + public static Map<String, String> unzip(String zipFileName, String extPlace) throws IOException { + HashMap<String, String> unzipFileNames = new HashMap<>(); + InputStream input = null; + try(ZipFile zipFile = new ZipFile(zipFileName)) { + + Enumeration<?> fileEn = zipFile.entries(); + byte[] buffer = new byte[CommonConstants.BUFFER_SIZE]; + + while (fileEn.hasMoreElements()) { + ZipEntry entry = (ZipEntry) fileEn.nextElement(); + if (entry.isDirectory()) { + continue; + } + + input = zipFile.getInputStream(entry); + File file = new File(extPlace, entry.getName()); + + //Currently it does not support xml based VNF descriptors. + //So skip and proceed to YAML defined files validation only. + if (file.getAbsolutePath().contains("xml"+System.getProperty("file.separator"))) { + continue; + } + + updateUnzipFileNames(input, buffer, unzipFileNames, file); + } + } finally { + closeInputStream(input); + } + return unzipFileNames; + } + + private static void updateUnzipFileNames(InputStream input, byte[] buffer, HashMap<String, String> unzipFileNames, File file) throws IOException { + if (!file.getParentFile().exists()) { + FileUtil.createDirectory(file.getParentFile().getAbsolutePath()); + } + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))){ + while (true) { + int length = input.read(buffer); + if (length == -1) { + break; + } + bos.write(buffer, 0, length); + } + + unzipFileNames.put(file.getName(), file.getAbsolutePath()); + } + } + + /** + * close InputStream. + * + * @param inputStream + * the inputstream to close + * @throws ValidationException + */ + public static void closeInputStream(InputStream inputStream) { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e1) { + String errCodeMessage = ErrorCodes.FILE_IO+" "+ e1.getMessage(); + logger.error("FILE_IO:close InputStream error! {} {}", errCodeMessage, e1); + throw new ValidationException(ErrorCodes.FILE_IO); + } + } + + /** + * close OutputStream. + * + * @param outputStream + * the output stream to close + * @throws ValidationException + */ + public static void closeOutputStream(OutputStream outputStream) { + try { + if (outputStream != null) { + outputStream.close(); + } + } catch (Exception e1) { + logger.error("FILE_IO:close OutputStream error! {} {}", ErrorCodes.FILE_IO, e1); + throw new ValidationException(ErrorCodes.FILE_IO); + + } + } + /** + * + * @param filePath + * @return HashMap<String, String> + */ + public static Map<String, String> csarExtract(String filePath) { + + try { + String tempfolder = CsarUtil.getUnzipDir(filePath); + return CsarUtil.unzip(filePath, tempfolder); + + } catch (IOException e1) { + String errCodeMessage = ErrorCodes.FILE_IO+" "+ e1.getMessage(); + logger.error("CSAR_EXTRACTION:CSAR extraction error ! {} {}", errCodeMessage, e1); + throw new ValidationException(ErrorCodes.FILE_IO); + } + } } diff --git a/csarvalidation/src/main/java/org/onap/validation/csar/CsarValidator.java b/csarvalidation/src/main/java/org/onap/validation/csar/CsarValidator.java index e92f2b2..bc18f8e 100644 --- a/csarvalidation/src/main/java/org/onap/validation/csar/CsarValidator.java +++ b/csarvalidation/src/main/java/org/onap/validation/csar/CsarValidator.java @@ -49,14 +49,14 @@ public class CsarValidator { private static ValidatorSchemaLoader vsl; // Map of CSAR file and un-zipped file indices - private static HashMap<String, String> csarFiles; + private static Map<String, String> csarFiles; // Map of packageId and CSAR files - private static HashMap<String, HashMap<String, String>> csar = new HashMap<>(); + private static Map<String, Map<String, String>> csar = new HashMap<>(); - private static String MAINSERV_TEMPLATE = CommonConstants.MAINSERV_TEMPLATE; + private static String mainServiceTemplate = CommonConstants.MAINSERV_TEMPLATE; - private static String MAINSERV_MANIFEST; + private static String mainServiceManifest; /** * @param packageId @@ -65,10 +65,8 @@ public class CsarValidator { */ public CsarValidator(String packageId, String csarWithPath) throws IOException { - try (FileInputStream is = new FileInputStream(csarWithPath)) { - - } catch(FileNotFoundException e2) { - LOG.error(csarWithPath + ":CSAR is not found! " + ErrorCodes.RESOURCE_MISSING, e2); + if (!isCsarExist(csarWithPath)) { + LOG.error(csarWithPath + ":CSAR is not found! " + ErrorCodes.RESOURCE_MISSING); throw new ValidationException(ErrorCodes.RESOURCE_MISSING, "RESOURCE MISSING" + csarWithPath + ":CSAR is not found!"); } @@ -80,8 +78,8 @@ public class CsarValidator { LOG.debug("CSAR extracted sucessfully."); } } catch(Exception e1) { - LOG.error("INVALID_CSAR_CONTENT" + ":" + csarWithPath + ": CSAR is not a valid CSAR/ZIP file! " - + ErrorCodes.INVALID_CSAR_CONTENT, e1); + LOG.error("INVALID_CSAR_CONTENT:{}: CSAR is not a valid CSAR/ZIP file! {} {}", + csarWithPath, ErrorCodes.INVALID_CSAR_CONTENT, e1); throw new ValidationException(ErrorCodes.INVALID_CSAR_CONTENT, "INVALID_CSAR_CONTENT" + ":" + csarWithPath + ": CSAR is not a valid CSAR/ZIP file! "); } @@ -89,40 +87,50 @@ public class CsarValidator { try { vsl = new ValidatorSchemaLoader(); } catch(Exception e) { - LOG.error( - "SCHEMA_LOAD_ERROR" + ":" + "CSAR schema is not loaded correctly! " + ErrorCodes.SCHEMA_LOAD_ERROR, - e); + LOG.error("SCHEMA_LOAD_ERROR:CSAR schema is not loaded correctly! {} {}", ErrorCodes.SCHEMA_LOAD_ERROR, e); throw new ValidationException(ErrorCodes.SCHEMA_LOAD_ERROR, "SCHEMA_LOAD_ERROR" + ":" + "CSAR schema is not loaded correctly! "); } } + static class CsarValidatorSeam { + public String validateCsarMeta() { + return CsarValidator.validateCsarMeta(); + } + + public String validateAndScanToscaMeta(){ + return CsarValidator.validateAndScanToscaMeta(); + } + + public String validateMainService() { + return CsarValidator.validateMainService(); + } + + } + /** * @return true if all validations are successful */ public static String validateCsar() { + return CsarValidator.validateCsarContent(new CsarValidatorSeam()); + } - String vsm = validateCsarMeta(); + static String validateCsarContent(CsarValidatorSeam csarValidatorSeam) { - String vtm = validateAndScanToscaMeta(); + String vsm = csarValidatorSeam.validateCsarMeta(); - String vms = validateMainService(); + String vtm = csarValidatorSeam.validateAndScanToscaMeta(); - //String r02454 = r02454(); + String vms = csarValidatorSeam.validateMainService(); - if((CommonConstants.SUCCESS_STR != vsm) && (CommonConstants.SUCCESS_STR != vms)) { + if((!CommonConstants.SUCCESS_STR.equals(vsm)) && (!CommonConstants.SUCCESS_STR.equals(vms))) { return vsm + " OR " + vms; } - if(CommonConstants.SUCCESS_STR != vtm) { + if(!CommonConstants.SUCCESS_STR.equals(vtm)) { return vtm; } -/* - if (CommonConstants.SUCCESS_STR != r02454) { - return r02454; - } -*/ return CommonConstants.SUCCESS_STR; } @@ -134,23 +142,32 @@ public class CsarValidator { try { RandomAccessFile raf = new RandomAccessFile(csarWithPath, "r"); - try { - long n = raf.readInt(); + return checkCsarIntegrity(raf); + } catch(IOException e1) { + LOG.error("CSAR %s is not a valid CSAR/ZIP file! ", e1); + return false; + } + } - // Check for the CSAR's integrity - if(n != 0x504B0304) { - LOG.error("CSAR %s contents are not a valid! "); - return false; - } - } catch(FileNotFoundException e1) { - LOG.error("CSAR %s is not a valid CSAR/ZIP file! ", e1); + /** + * @param raf + * @throws IOException + */ + private static boolean checkCsarIntegrity(RandomAccessFile raf) throws IOException { + + try { + long n = raf.readInt(); + + // Check for the CSAR's integrity + if (n != 0x504B0304) { + LOG.error("CSAR %s contents are not a valid! "); return false; - } finally { - raf.close(); } - } catch(IOException e1) { + } catch (FileNotFoundException e1) { LOG.error("CSAR %s is not a valid CSAR/ZIP file! ", e1); return false; + } finally { + raf.close(); } return true; } @@ -192,7 +209,6 @@ public class CsarValidator { } } } - reader.close(); return CommonConstants.SUCCESS_STR; } } catch(IOException e2) { @@ -220,14 +236,14 @@ public class CsarValidator { } try { - MAINSERV_MANIFEST = checkAndGetMRF(cfile, "Entry-Manifest"); - if(MAINSERV_MANIFEST == null) { - MAINSERV_MANIFEST = CommonConstants.MAINSERV_MANIFEST; + mainServiceManifest = checkAndGetMRF(cfile, "Entry-Manifest"); + if(mainServiceManifest == null) { + mainServiceManifest = CommonConstants.MAINSERV_MANIFEST; } - MAINSERV_TEMPLATE = checkAndGetMRF(cfile, "Entry-Definitions"); - if(MAINSERV_TEMPLATE == null) { - MAINSERV_TEMPLATE = CommonConstants.MAINSERV_TEMPLATE; + mainServiceTemplate = checkAndGetMRF(cfile, "Entry-Definitions"); + if(mainServiceTemplate == null) { + mainServiceTemplate = CommonConstants.MAINSERV_TEMPLATE; } return CommonConstants.SUCCESS_STR; @@ -256,8 +272,7 @@ public class CsarValidator { } } } catch(IOException | NullPointerException e) { - LOG.error("CSAR_TOSCA_VALIDATION" + ":" + "Could not read file %s ! " + ErrorCodes.FILE_IO + " " - + ErrorCodes.RESOURCE_MISSING, e); + LOG.error("CSAR_TOSCA_VALIDATION:Could not read file {} {} ! {}", ErrorCodes.FILE_IO, ErrorCodes.RESOURCE_MISSING, e); throw new ValidationException(ErrorCodes.RESOURCE_MISSING); } @@ -276,9 +291,9 @@ public class CsarValidator { Arrays.asList("vnf_product_name", "vnf_provider_id", "vnf_package_version", "vnf_release_data_time"); @SuppressWarnings("unused") - boolean mfResult = checkEntryFor(CommonConstants.MAINSERV_MANIFEST, mListMetadata, key); + boolean mfResult = checkEntryFor(CommonConstants.MAINSERV_MANIFEST, mListMetadata, key); //NOSONAR - String mainServManifest = MAINSERV_MANIFEST; + String mainServManifest = mainServiceManifest; if(!Paths.get(mainServManifest).isAbsolute()) { mainServManifest = csarFiles.get(FilenameUtils.getName(mainServManifest)); } @@ -287,8 +302,8 @@ public class CsarValidator { // Do nothing for Rel-1 } - String mainservTemplate = MAINSERV_TEMPLATE; - if(!Paths.get(MAINSERV_TEMPLATE).isAbsolute()) { + String mainservTemplate = mainServiceTemplate; + if(!Paths.get(mainServiceTemplate).isAbsolute()) { mainservTemplate = csarFiles.get(FilenameUtils.getName(mainservTemplate)); } @@ -306,10 +321,10 @@ public class CsarValidator { * @return: boolean **/ public static String r02454() { - String mainservTemplate = MAINSERV_TEMPLATE; + String mainservTemplate = mainServiceTemplate; mainservTemplate = csarFiles.get(FilenameUtils.getName(mainservTemplate)); - //TODO: Fixme R3 only check the existence of swImage filed inside VNFD. + //TODO: Fixme R3 only check the existence of swImage filed inside VNFD. //NOSONAR File file = new File(mainservTemplate); try (BufferedReader reader = new BufferedReader(new FileReader(file))) { String tempString = null; @@ -345,8 +360,6 @@ public class CsarValidator { @SuppressWarnings("unchecked") private static boolean checkEntryFor(String cFile, List<String> attributes, String key) { - @SuppressWarnings("unused") - String tFileWithPath; if(!Paths.get(cFile).isAbsolute()) { cFile = csarFiles.get(FilenameUtils.getName(cFile)); @@ -358,14 +371,16 @@ public class CsarValidator { Yaml yaml = new Yaml(); Map<String, ?> values; + String exceptionMessage; try (InputStream input = new FileInputStream(new File(cFile))) { values = (Map<String, ?>)yaml.load(input); } catch(FileNotFoundException e) { - LOG.error("FILE_NOT_FOUND" + ":" + "Exception caught while trying to find the file ! " + e.getMessage(), e); + exceptionMessage = e.getMessage(); + LOG.error("FILE_NOT_FOUND:Exception caught while trying to find the file ! {} {}", exceptionMessage, e); return false; } catch(IOException e1) { - LOG.error("FILE_NOT_FOUND" + ":" + "Exception caught while trying to open the file ! " + e1.getMessage(), - e1); + exceptionMessage = e1.getMessage(); + LOG.error("FILE_NOT_FOUND:Exception caught while trying to open the file ! {} {}", exceptionMessage, e1); return false; } @@ -403,7 +418,6 @@ public class CsarValidator { if(StringUtils.isEmpty(cfile)) { return false; } else { - File file = new File(cfile); Yaml yaml = new Yaml(); @@ -411,9 +425,9 @@ public class CsarValidator { try (InputStream input = new FileInputStream(new File(cfile))) { toscaMeta = (Map<String, ?>)yaml.load(input); } catch(FileNotFoundException e) { - LOG.error("CSAR_TOSCA_LOAD" + ":" + "TOSCA metadata is not loaded by Yaml! " + ErrorCodes.FILE_IO, e); + LOG.error("CSAR_TOSCA_LOAD:TOSCA metadata is not loaded by Yaml! {} {}", ErrorCodes.FILE_IO, e); } catch(IOException e1) { - LOG.error("CSAR_TOSCA_LOAD" + ":" + "TOSCA metadata is not loaded by Yaml! " + ErrorCodes.FILE_IO, e1); + LOG.error("CSAR_TOSCA_LOAD:TOSCA metadata is not loaded by Yaml! {} {}", ErrorCodes.FILE_IO, e1); } if(toscaMeta != null) { return toscaMeta.keySet().containsAll((vsl.getToscaMeta().keySet())); @@ -422,19 +436,23 @@ public class CsarValidator { } } - public static HashMap<String, HashMap<String, String>> getCsar() { + public static Map<String, Map<String, String>> getCsar() { return csar; } - public static void setCsar(HashMap<String, HashMap<String, String>> csar) { + public static void setCsar(Map<String, Map<String, String>> csar) { CsarValidator.csar = csar; } - public static HashMap<String, String> getCsarFiles() { + public static Map<String, String> getCsarFiles() { return csarFiles; } - public static void setCsarFiles(HashMap<String, String> csarFiles) { + public static void setCsarFiles(Map<String, String> csarFiles) { CsarValidator.csarFiles = csarFiles; } + + public static boolean isCsarExist(String csarWithPath){ + return new File(csarWithPath).exists(); + } } diff --git a/csarvalidation/src/main/java/org/onap/validation/csar/FileUtil.java b/csarvalidation/src/main/java/org/onap/validation/csar/FileUtil.java index f7471bd..ccf1c71 100644 --- a/csarvalidation/src/main/java/org/onap/validation/csar/FileUtil.java +++ b/csarvalidation/src/main/java/org/onap/validation/csar/FileUtil.java @@ -23,13 +23,15 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.ZipFile; - +import java.nio.file.Files; +import java.nio.file.Paths; public final class FileUtil { public static final Logger logger = LoggerFactory.getLogger(FileUtil.class); private static final int TRY_COUNT = 3; + public static final String FILE_IO_STR = "FILE_IO"; private FileUtil() { @@ -46,9 +48,7 @@ public final class FileUtil { int tryCount = 0; while (tryCount < TRY_COUNT) { tryCount++; - if (!folder.exists() && !folder.mkdirs()) { - continue; - } else { + if (folder.exists() || folder.mkdirs()) { return true; } } @@ -65,15 +65,16 @@ public final class FileUtil { String hintInfo = file.isDirectory() ? "dir " : "file "; boolean isFileDeleted = file.delete(); boolean isFileExist = file.exists(); + String fileAbsolutePath = file.getAbsolutePath(); if (!isFileExist) { if (isFileDeleted) { - logger.info("delete " + hintInfo + file.getAbsolutePath()); + logger.info("delete {}{}", hintInfo, fileAbsolutePath); } else { isFileDeleted = true; - logger.info("file not exist. no need delete " + hintInfo + file.getAbsolutePath()); + logger.info("file not exist. no need delete {}{}", hintInfo, fileAbsolutePath); } } else { - logger.info("fail to delete " + hintInfo + file.getAbsolutePath()); + logger.info("fail to delete {}{}", hintInfo, fileAbsolutePath); } return isFileDeleted; @@ -92,7 +93,8 @@ public final class FileUtil { inputStream.close(); } } catch (Exception e1) { - logger.error("FILE_IO" + ":" + "close InputStream error! "+ErrorCodes.FILE_IO+ " " + e1.getMessage(), e1); + String errCodeMessage = ErrorCodes.FILE_IO+ " " + e1.getMessage(); + logger.error("FILE_IO:close InputStream error! {}{}", errCodeMessage, e1); throw new ValidationException(ErrorCodes.FILE_IO); } } @@ -109,7 +111,8 @@ public final class FileUtil { outputStream.close(); } } catch (Exception e1) { - logger.error("FILE_IO" + ":" + "close OutputStream error! "+ErrorCodes.FILE_IO+ " " + e1.getMessage(), e1); + String errCodeMessage = ErrorCodes.FILE_IO+ " " + e1.getMessage(); + logger.error("FILE_IO:close OutputStream error! {}{}", errCodeMessage, e1); throw new ValidationException(ErrorCodes.FILE_IO); } } @@ -120,7 +123,8 @@ public final class FileUtil { ifs.close(); } } catch (Exception e1) { - logger.error("FILE_IO" + ":" + "close OutputStream error! "+ErrorCodes.FILE_IO+ " " + e1.getMessage(), e1); + String errCodeMessage = ErrorCodes.FILE_IO+ " " + e1.getMessage(); + logger.error("FILE_IO:close OutputStream error! {}{}", errCodeMessage, e1); throw new ValidationException(ErrorCodes.FILE_IO); } } @@ -137,7 +141,8 @@ public final class FileUtil { zipFile.close(); } } catch (IOException e1) { - logger.error("CLOSE_ZIPFILE" + ":" + "close ZipFile error! "+ErrorCodes.FILE_IO+ " " + e1.getMessage(), e1); + String errCodeMessage = ErrorCodes.FILE_IO+ " " + e1.getMessage(); + logger.error("CLOSE_ZIPFILE:close ZipFile error! {}{}", errCodeMessage, e1); throw new ValidationException(ErrorCodes.FILE_IO); } } @@ -172,6 +177,13 @@ public final class FileUtil { deleteDirectory(f); } } - return file.delete(); + boolean isFileDeleted=false; + try { + Files.delete(Paths.get(file.getPath())); + isFileDeleted=true; + } catch (IOException e) { + logger.error("fail to delete {} {} ", file.getAbsolutePath(), ", exception :: ", e); + } + return isFileDeleted; } } diff --git a/csarvalidation/src/main/java/org/onap/validation/csar/VTPValidateCSAR.java b/csarvalidation/src/main/java/org/onap/validation/csar/VTPValidateCSAR.java index b97b488..1624e46 100644 --- a/csarvalidation/src/main/java/org/onap/validation/csar/VTPValidateCSAR.java +++ b/csarvalidation/src/main/java/org/onap/validation/csar/VTPValidateCSAR.java @@ -30,7 +30,7 @@ import org.slf4j.LoggerFactory; */ @OnapCommandSchema(schema = "vtp-validate-csar-casablanca.yaml") public class VTPValidateCSAR extends OnapCommand { - private static final Logger LOG = LoggerFactory.getLogger(VTPValidateCSAR.class); + private static final Logger LOG = LoggerFactory.getLogger(VTPValidateCSAR.class); //NOSONAR @Override protected void run() throws OnapCommandException { diff --git a/csarvalidation/src/main/java/org/onap/validation/csar/ValidationException.java b/csarvalidation/src/main/java/org/onap/validation/csar/ValidationException.java index 7c124d7..ac4c1eb 100644 --- a/csarvalidation/src/main/java/org/onap/validation/csar/ValidationException.java +++ b/csarvalidation/src/main/java/org/onap/validation/csar/ValidationException.java @@ -36,7 +36,7 @@ public class ValidationException extends RuntimeException { return wrappedInfo(exception, null); } - public ValidationException(ErrorCodes errCode, String message) { + public ValidationException(ErrorCodes errCode, String message) { //NOSONAR super(message); } @@ -58,7 +58,8 @@ public class ValidationException extends RuntimeException { super(message, cause); this.errorCode = errorCode; } - + + @Override public String toString(){ return ("Exception Number = "+errorMessage) ; } diff --git a/csarvalidation/src/main/java/org/onap/validation/csar/ValidatorSchemaLoader.java b/csarvalidation/src/main/java/org/onap/validation/csar/ValidatorSchemaLoader.java index 0ed0bdc..b96275f 100644 --- a/csarvalidation/src/main/java/org/onap/validation/csar/ValidatorSchemaLoader.java +++ b/csarvalidation/src/main/java/org/onap/validation/csar/ValidatorSchemaLoader.java @@ -22,7 +22,6 @@ import java.io.*; import java.net.URISyntaxException; import java.util.*; import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.scanner.ScannerException; public class ValidatorSchemaLoader { @@ -31,13 +30,13 @@ public class ValidatorSchemaLoader { private static final Logger LOG = LoggerFactory.getLogger(ValidatorSchemaLoader.class); // Map of Schema files - private Map<String, ?> toscaMeta; + private Map<String, Object> toscaMeta; - private Map<String, ?> csarentryd; + private Map<String, Object> csarentryd; - private Map<String, ?> mrfYaml; + private Map<String, Object> mrfYaml; - private Map<String, ?> mrfManifest; + private Map<String, Object> mrfManifest; // List of configured schemas static List<String> schemaFileList = new ArrayList<>(); @@ -47,28 +46,18 @@ public class ValidatorSchemaLoader { static HashMap<String, String> optionTwoSchema; - private String schemaFolder; - public ValidatorSchemaLoader() { - try { loadResources(); - } catch(FileNotFoundException e1) { - LOG.error("Schema file not found or schema repository corrupted", e1); - - } catch(URISyntaxException e) { - // TODO Auto-generated catch block - LOG.error("Illegal character in query at index", e); - } } - private Map<String, ?> readYaml(String fileName) { + private Map<String, Object> readYaml(String fileName) { Yaml yaml = new Yaml(); - return (Map<String, ?>)yaml.load(this.getClass().getResourceAsStream(fileName)); + return (Map<String, Object>)yaml.load(this.getClass().getResourceAsStream(fileName)); } @SuppressWarnings("unchecked") - private boolean loadResources() throws FileNotFoundException, URISyntaxException { + private boolean loadResources() { for (String metaFile: new String []{"TOSCA.meta", "CSAR.meta", "MRF.mf" }) { switch(metaFile) { case "TOSCA.meta": @@ -88,19 +77,19 @@ public class ValidatorSchemaLoader { return true; } - public Map<String, ?> getToscaMeta() { + public Map<String, Object> getToscaMeta() { return toscaMeta; } - public Map<String, ?> getCsarentryd() { + public Map<String, Object> getCsarentryd() { return csarentryd; } - public Map<String, ?> getMrfYaml() { + public Map<String, Object> getMrfYaml() { return mrfYaml; } - public Map<String, ?> getMrfManifest() { + public Map<String, Object> getMrfManifest() { return mrfManifest; } } diff --git a/csarvalidation/src/main/java/org/onap/validation/yaml/YamlFileValidator.java b/csarvalidation/src/main/java/org/onap/validation/yaml/YamlFileValidator.java new file mode 100644 index 0000000..2de4f48 --- /dev/null +++ b/csarvalidation/src/main/java/org/onap/validation/yaml/YamlFileValidator.java @@ -0,0 +1,72 @@ +/* + * 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.schema.YamlSchema; +import org.onap.validation.yaml.schema.YamlSchemaFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class YamlFileValidator { + + private static final int FIRST_DOCUMENT_INDEX = 1; + + public List<YamlDocumentValidationError> validateYamlFileWithSchema(String pathToFile) + throws YamlProcessingException { + + List<YamlDocument> documents = new YamlLoader().loadMultiDocumentYamlFile(pathToFile); + if(!documents.isEmpty()) { + return validateDocuments(documents); + } else { + throw new YamlProcessingException("PM_Dictionary YAML file is empty"); + } + } + + 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/csarvalidation/src/main/java/org/onap/validation/yaml/YamlLoader.java b/csarvalidation/src/main/java/org/onap/validation/yaml/YamlLoader.java new file mode 100644 index 0000000..1a5eef9 --- /dev/null +++ b/csarvalidation/src/main/java/org/onap/validation/yaml/YamlLoader.java @@ -0,0 +1,61 @@ +/* + * 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.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); + + List<YamlDocument> loadMultiDocumentYamlFile(URL path) + throws YamlDocumentFactory.YamlDocumentParsingException { + List<YamlDocument> documentsFromFile = new ArrayList<>(); + try (InputStream yamlStream = path.openStream()) { + for (Object yamlDocument : new Yaml().loadAll(yamlStream)) { + documentsFromFile.add( + new YamlDocumentFactory().createYamlDocument(yamlDocument) + ); + } + } catch (IOException e) { + LOGGER.error("Failed to load multi document YAML file",e); + } + return documentsFromFile; + } + + 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); + } + } +} diff --git a/csarvalidation/src/main/java/org/onap/validation/yaml/YamlValidator.java b/csarvalidation/src/main/java/org/onap/validation/yaml/YamlValidator.java new file mode 100644 index 0000000..9430df4 --- /dev/null +++ b/csarvalidation/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.exception.YamlProcessingException; +import org.onap.validation.yaml.error.SchemaValidationError; +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/csarvalidation/src/main/java/org/onap/validation/yaml/error/SchemaValidationError.java b/csarvalidation/src/main/java/org/onap/validation/yaml/error/SchemaValidationError.java new file mode 100644 index 0000000..6ffe6d4 --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/error/YamlDocumentValidationError.java b/csarvalidation/src/main/java/org/onap/validation/yaml/error/YamlDocumentValidationError.java new file mode 100644 index 0000000..f04708f --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/exception/YamlProcessingException.java b/csarvalidation/src/main/java/org/onap/validation/yaml/exception/YamlProcessingException.java new file mode 100644 index 0000000..99c2437 --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocument.java b/csarvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocument.java new file mode 100644 index 0000000..557b6fd --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocumentFactory.java b/csarvalidation/src/main/java/org/onap/validation/yaml/model/YamlDocumentFactory.java new file mode 100644 index 0000000..b56422c --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/model/YamlParameterListFactory.java b/csarvalidation/src/main/java/org/onap/validation/yaml/model/YamlParameterListFactory.java new file mode 100644 index 0000000..5f41c5c --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/model/YamlParametersList.java b/csarvalidation/src/main/java/org/onap/validation/yaml/model/YamlParametersList.java new file mode 100644 index 0000000..2b93c74 --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationProcess.java b/csarvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationProcess.java new file mode 100644 index 0000000..273014b --- /dev/null +++ b/csarvalidation/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.exception.YamlProcessingException; +import org.onap.validation.yaml.error.SchemaValidationError; +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/csarvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationStep.java b/csarvalidation/src/main/java/org/onap/validation/yaml/process/YamlValidationStep.java new file mode 100644 index 0000000..eb5ab8e --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchema.java b/csarvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchema.java new file mode 100644 index 0000000..69bb6cd --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchemaFactory.java b/csarvalidation/src/main/java/org/onap/validation/yaml/schema/YamlSchemaFactory.java new file mode 100644 index 0000000..df7d673 --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaBranchNode.java b/csarvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaBranchNode.java new file mode 100644 index 0000000..0f5b480 --- /dev/null +++ b/csarvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaBranchNode.java @@ -0,0 +1,80 @@ +/* + * 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; +import java.util.Optional; + +public class YamlSchemaBranchNode extends YamlSchemaNode { + + private final YamlDocument nextNodesInLazyForm; + private Optional<List<YamlSchemaNode>> nextNodes; + + YamlSchemaBranchNode(String name, String path, boolean required, String comment, + YamlDocument nextNodesInLazyForm) { + super(name, path, required, comment); + this.nextNodesInLazyForm = nextNodesInLazyForm; + this.nextNodes = Optional.empty(); + } + + @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.orElseGet(this::loadNextNodes); + } 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 = Optional.of(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/csarvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaLeafNode.java b/csarvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaLeafNode.java new file mode 100644 index 0000000..c98f41e --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNode.java b/csarvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNode.java new file mode 100644 index 0000000..28913a2 --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNodeFactory.java b/csarvalidation/src/main/java/org/onap/validation/yaml/schema/node/YamlSchemaNodeFactory.java new file mode 100644 index 0000000..79a8f14 --- /dev/null +++ b/csarvalidation/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/csarvalidation/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand b/csarvalidation/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand index 0695555..b9ad72f 100644 --- a/csarvalidation/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand +++ b/csarvalidation/src/main/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand @@ -48,4 +48,5 @@ org.onap.cvc.csar.cc.sol004.VTPValidateCSARR77707 org.onap.cvc.csar.cc.sol004.VTPValidateCSARR77786 org.onap.cvc.csar.cc.sol004.VTPValidateCSARR787965 org.onap.cvc.csar.cc.sol004.VTPValidateCSARR87234 +org.onap.cvc.csar.cc.sol004.VTPValidateCSARR816745 org.onap.cvc.csar.cc.sol004.VTPValidateCSARR972082 diff --git a/csarvalidation/src/main/resources/open-cli-schema/sol004/vtp-validate-csar-r01123.yaml b/csarvalidation/src/main/resources/open-cli-schema/sol004/vtp-validate-csar-r01123.yaml index 59bb955..577b2ca 100644 --- a/csarvalidation/src/main/resources/open-cli-schema/sol004/vtp-validate-csar-r01123.yaml +++ b/csarvalidation/src/main/resources/open-cli-schema/sol004/vtp-validate-csar-r01123.yaml @@ -17,13 +17,13 @@ open_cli_schema_version: 1.0 name: csar-validate-r01123 description: | - The VNF package Manifest file MUST contain: VNF package meta-data, a list of all artifacts - (both internal and external) entry’s including their respected URI’s, an algorithm to calculate - a digest and a digest result calculated on the content of each artifacts, as specified in - ETSI GS NFV-SOL004. The VNF Package MUST include VNF Identification Data to uniquely - identify the resource for a given VNF provider. The identification data must include: - an identifier for the VNF, the name of the VNF as was given by the VNF provider, VNF - description, VNF provider, and version. + The VNF or PNF CSAR package Manifest file MUST contain: VNF or PNF package meta-data, + a list of all artifacts (both internal and external) entry’s including their respected URI’s, + an algorithm to calculate a digest and a digest result calculated on the content of each artifacts, + as specified in ETSI GS NFV-SOL004. The VNF or PNF Package MUST include VNF or PNF Identification Data to uniquely + identify the resource for a given provider. The identification data must include: + an identifier for the VNF or PNF, the name of the VNF or PNF as was given by the provider, + description, provider and version. info: product: onap-dublin @@ -38,6 +38,13 @@ parameters: short_option: b type: binary is_optional: false + - name: pnf + description: CSAR file contains PNF + long_option: pnf + short_option: p + type: bool + is_optional: true + default_value: false results: direction: landscape diff --git a/csarvalidation/src/main/resources/open-cli-schema/sol004/vtp-validate-csar-r816745.yaml b/csarvalidation/src/main/resources/open-cli-schema/sol004/vtp-validate-csar-r816745.yaml new file mode 100644 index 0000000..8ef80dd --- /dev/null +++ b/csarvalidation/src/main/resources/open-cli-schema/sol004/vtp-validate-csar-r816745.yaml @@ -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. + +open_cli_schema_version: 1.0 + +name: csar-validate-r816745 + +description: | + The VNF or PNF PROVIDER MUST provide the Service Provider with PM Meta Data (PM Dictionary) + to support the analysis of PM events delivered to DCAE. + The PM Dictionary is to be provided as a separate YAML artifact at onboarding and must follow + the VES Event Listener Specification and VES Event Registration Specification + which contain the format and content required. + + +info: + product: onap-dublin + version: 1.0 + service: vnf-compliance + author: ONAP VTP Team onap-discuss@lists.onap.org + +parameters: + - name: csar + description: CSAR file path + long_option: csar + short_option: b + type: binary + is_optional: false + - name: pnf + description: CSAR file contains PNF + long_option: pnf + short_option: p + type: bool + is_optional: true + default_value: false + +results: + direction: landscape + attributes: + - name: code + description: Error code + scope: short + type: string + - name: message + description: Error message + scope: short + type: string + - name: file + description: File in which error occured + scope: short + type: string + - name: line-no + description: Line no at which error occured + scope: short + type: string diff --git a/csarvalidation/src/main/resources/vnfreqs.properties b/csarvalidation/src/main/resources/vnfreqs.properties index abbdb73..2e0baaf 100644 --- a/csarvalidation/src/main/resources/vnfreqs.properties +++ b/csarvalidation/src/main/resources/vnfreqs.properties @@ -1,5 +1,5 @@ -vnfreqs.enabled=r02454,r04298,r07879,r09467,r13390,r23823,r26881,r27310,r35851,r40293,r43958,r66070,r77707,r77786,r87234,r10087,r21322,r26885,r40820,r35854,r65486,r17852,r46527,r15837,r54356,r67895,r95321,r32155,r01123,r51347,r787965,r130206 -pnfreqs.enabled=r10087,r87234,r35854,r15837,r17852,r293901,r146092,r57019,r787965,r130206 +vnfreqs.enabled=r01123,r02454,r04298,r07879,r09467,r10087,r13390,r15837,r17852,r21322,r23823,r26881,r26885,r27310,r32155,r35851,r35854,r40293,r40820,r43958,r46527,r51347,r54356,r65486,r67895,r66070,r77707,r77786,r87234,r95321,r130206,r787965 +pnfreqs.enabled=r01123,r10087,r15837,r17852,r35854,r57019,r87234,r130206,r146092,r293901,r787965,r816745,r972082 # ignored all chef and ansible related tests vnferrors.ignored=0x1005,0x1006,r07879-0x1000,r13390-0x1000,r27310-0x1000,r40293-0x1000,r77786-0x1000,r04298-0x1000,r07879-0x1000,r10087-0x1000,r13390-0x1000,r23823-0x1000,r26881-0x1000,r40820-0x1000,r35851-0x1000,r32155-0x1000,r54356-0x1000,r67895-0x1000,r95321-0x1000,r46527-0x1000,r02454-0x1000 -pnferrors.ignored= +pnferrors.ignored=0x1006,r130206-0x1006 diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/CSARArchiveTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/CSARArchiveTest.java index 2831532..3b18a1b 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/CSARArchiveTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/CSARArchiveTest.java @@ -20,8 +20,9 @@ import java.io.IOException; import java.util.Arrays; import org.junit.Test; - import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + public class CSARArchiveTest { @Test @@ -35,6 +36,7 @@ public class CSARArchiveTest { csar.init("./src/test/resources/" + csarFileName + ".csar"); csar.parse(); csar.cleanup(); + assertTrue(csar.getErrors().size() > 0); System.out.println(csar.getErrors()); } catch (Exception e) { // TODO Auto-generated catch block diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/CsarValidatorTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/CsarValidatorTest.java deleted file mode 100644 index 2969b42..0000000 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/CsarValidatorTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Copyright 2017 Huawei Technologies Co., Ltd. - * - * 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.cvc.csar; - -import org.junit.Test; -import org.onap.cli.main.OnapCli; - -import java.net.URISyntaxException; - -import static org.junit.Assert.assertEquals; -import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.absoluteFilePath; - - -public class CsarValidatorTest { - - - @Test - public void testAllTestCasesForVNF() throws URISyntaxException { - OnapCli cli = new OnapCli(new String [] { - "--product", "onap-dublin", - "csar-validate", - "--format", "json", - "--csar", absoluteFilePath("VoLTE.csar")}); - cli.handle(); - assertEquals(0, cli.getExitCode()); - } - - - @Test - public void testAllTestCasesForPNF_CsarCase() throws URISyntaxException { - OnapCli cli = new OnapCli(new String [] { - "--product", "onap-dublin", - "csar-validate", - "--format", "json", - "--pnf", - "--csar", absoluteFilePath("pnf/r57019/allMandatoryEntriesDefinedInMetadataManifest.csar")}); - cli.handle(); - assertEquals(0, cli.getExitCode()); - } - - - @Test - public void testAllTestCasesForPNF_ZipCase() throws URISyntaxException { - OnapCli cli = new OnapCli(new String [] { - "--product", "onap-dublin", - "csar-validate", - "--format", "json", - "--pnf", - "--csar", absoluteFilePath("pnf/signed-package-valid-signature.zip")}); - cli.handle(); - assertEquals(0, cli.getExitCode()); - } - -} diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/PnfCSARArchiveTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/PnfCSARArchiveTest.java index cf24e53..4f46b74 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/PnfCSARArchiveTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/PnfCSARArchiveTest.java @@ -19,11 +19,11 @@ package org.onap.cvc.csar; import com.google.common.collect.Lists; import org.junit.Test; import org.onap.cvc.csar.parser.SourcesParser; - import java.util.List; import java.util.Map; - import static org.assertj.core.api.Assertions.assertThat; +import java.util.Collections; +import java.util.HashMap; public class PnfCSARArchiveTest { @@ -45,7 +45,7 @@ public class PnfCSARArchiveTest { verifyThatCmsSectionWasSet(manifest); verifyThatSourcesSectionWasSet(manifest); verifyThatNonManoArtifactsWereSet(manifest); - assertThat(pnfCSARArchive.getErrors().size()).isEqualTo(0); + assertThat(pnfCSARArchive.getErrors().size()).isZero(); } } @@ -76,23 +76,27 @@ public class PnfCSARArchiveTest { private void verifyThatNonManoArtifactsWereSet(CSARArchive.Manifest manifest) { Map<String, Map<String, List<String>>> nonManoArtifacts = manifest.getNonMano(); - assertThat(nonManoArtifacts.get("onap_ves_events").get(SOURCE_TAG)) - .isEqualTo(Lists.newArrayList("Artifacts/Events/VES_registration.yml") - ); - assertThat(nonManoArtifacts.get("onap_pm_dictionary").get(SOURCE_TAG)) - .isEqualTo(Lists.newArrayList("Artifacts/Measurements/PM_Dictionary.yaml") - ); - assertThat(nonManoArtifacts.get("onap_yang_modules").get(SOURCE_TAG)) - .isEqualTo(Lists.newArrayList("Artifacts/Yang_module/Yang_module.yaml") - ); - assertThat(nonManoArtifacts.get("onap_others").get(SOURCE_TAG)) - .isEqualTo(Lists.newArrayList( - "Artifacts/scripts/install.sh", + Map<String, List<String>>mapValue1=new HashMap<>(); + Map<String, List<String>>mapValue2=new HashMap<>(); + Map<String, List<String>>mapValue3=new HashMap<>(); + Map<String, List<String>>mapValue4=new HashMap<>(); + + mapValue1.put("", Collections.singletonList("")); + mapValue1.put(SOURCE_TAG,Lists.newArrayList("Artifacts/Events/VES_registration.yml")); + mapValue2.put("", Collections.singletonList("")); + mapValue2.put(SOURCE_TAG,Lists.newArrayList("Artifacts/Measurements/PM_Dictionary.yaml")); + mapValue3.put("", Collections.singletonList("")); + mapValue3.put(SOURCE_TAG,Lists.newArrayList("Artifacts/Yang_module/Yang_module.yaml")); + mapValue4.put("", Collections.singletonList("")); + mapValue4.put(SOURCE_TAG,Lists.newArrayList + ("Artifacts/scripts/install.sh", "Artifacts/Informational/user_guide.txt", "Artifacts/Other/installation_guide.txt", - "Artifacts/Other/review_log.txt" - ) - ); + "Artifacts/Other/review_log.txt")); + assertThat(nonManoArtifacts).containsEntry("onap_ves_events",mapValue1); + assertThat(nonManoArtifacts).containsEntry("onap_pm_dictionary",mapValue2); + assertThat(nonManoArtifacts).containsEntry("onap_yang_modules",mapValue3); + assertThat(nonManoArtifacts).containsEntry("onap_others",mapValue4); } }
\ No newline at end of file diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/PnfManifestParserTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/PnfManifestParserTest.java index a708f47..5749a73 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/PnfManifestParserTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/PnfManifestParserTest.java @@ -25,6 +25,8 @@ import java.io.File; import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Collections; +import java.util.HashMap; import static org.assertj.core.api.Assertions.assertThat; @@ -48,7 +50,7 @@ public class PnfManifestParserTest { assertThat(metadata.getProviderId()).isEqualTo("Ericsson"); assertThat(metadata.getPackageVersion()).isEqualTo("1.0"); assertThat(metadata.getReleaseDateTime()).isEqualTo("2019-01-14T11:25:00+00:00"); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @@ -64,7 +66,7 @@ public class PnfManifestParserTest { new SourcesParser.Source("scripts/install.sh", "SHA-256", "d0e7828293355a07c2dccaaa765c80b507e60e6167067c950dc2e6b0da0dbd8b"), new SourcesParser.Source("https://www.vendor_org.com/MRF/v4.1/scripts/scale/scale.sh", "SHA-256", "36f945953929812aca2701b114b068c71bd8c95ceb3609711428c26325649165") ); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @@ -81,7 +83,7 @@ public class PnfManifestParserTest { new SourcesParser.Source("some_file.sh", "", ""), new SourcesParser.Source("scripts/install.sh", "", "d0e7828293355a07c2dccaaa765c80b507e60e6167067c950dc2e6b0da0dbd8b"), new SourcesParser.Source("https://www.vendor_org.com/MRF/v4.1/scripts/scale/scale.sh", "SHA-256", "")); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @@ -90,25 +92,28 @@ public class PnfManifestParserTest { Pair<Map<String, Map<String, List<String>>>, List<CSARArchive.CSARError>> mapListPair = pnfManifestParser.fetchNonManoArtifacts().get(); Map<String, Map<String, List<String>>> nonManoArtifacts = mapListPair.getKey(); List<CSARArchive.CSARError> errors = mapListPair.getValue(); - - assertThat(nonManoArtifacts.get("onap_ves_events").get("source")) - .isEqualTo(Lists.newArrayList("Artifacts/Events/VES_registration.yml") - ); - assertThat(nonManoArtifacts.get("onap_pm_dictionary").get("source")) - .isEqualTo(Lists.newArrayList("Artifacts/Measurements/PM_Dictionary.yaml") - ); - assertThat(nonManoArtifacts.get("onap_yang_module").get("source")) - .isEqualTo(Lists.newArrayList("Artifacts/Yang_module/Yang_module.yaml") - ); - assertThat(nonManoArtifacts.get("onap_others").get("source")) - .isEqualTo(Lists.newArrayList( - "Artifacts/scripts/install.sh", + Map<String, List<String>>mapValue1=new HashMap<>(); + Map<String, List<String>>mapValue2=new HashMap<>(); + Map<String, List<String>>mapValue3=new HashMap<>(); + Map<String, List<String>>mapValue4=new HashMap<>(); + + mapValue1.put("", Collections.singletonList("")); + mapValue1.put("source",Lists.newArrayList("Artifacts/Events/VES_registration.yml")); + mapValue2.put("", Collections.singletonList("")); + mapValue2.put("source",Lists.newArrayList("Artifacts/Measurements/PM_Dictionary.yaml")); + mapValue3.put("", Collections.singletonList("")); + mapValue3.put("source",Lists.newArrayList("Artifacts/Yang_module/Yang_module.yaml")); + mapValue4.put("", Collections.singletonList("")); + mapValue4.put("source",Lists.newArrayList + ("Artifacts/scripts/install.sh", "Artifacts/Informational/user_guide.txt", "Artifacts/Other/installation_guide.txt", - "Artifacts/Other/review_log.txt" - ) - ); - assertThat(errors.size()).isEqualTo(0); + "Artifacts/Other/review_log.txt")); + assertThat(nonManoArtifacts).containsEntry("onap_ves_events",mapValue1); + assertThat(nonManoArtifacts).containsEntry("onap_pm_dictionary",mapValue2); + assertThat(nonManoArtifacts).containsEntry("onap_yang_module",mapValue3); + assertThat(nonManoArtifacts).containsEntry("onap_others",mapValue4); + assertThat(errors.size()).isZero(); } @@ -154,7 +159,7 @@ public class PnfManifestParserTest { "HhE7UbSCHDlDDgrOosJkbuI4UCX/njXrU2ukXbrWz/FjH84Mek039z+w4M6fBnl5"+ "4xuyO1o65LlKHoxwnRH9lQ==" ); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @Test @@ -214,6 +219,6 @@ public class PnfManifestParserTest { new SourcesParser.Source("Artifacts/Other/review_log.txt", "SHA-256", "36f945953929812aca2701b114b068c71bd8c95ceb3609711428c26325649165") ); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/PnfMetadataParserTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/PnfMetadataParserTest.java index c409efc..4a08a5d 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/PnfMetadataParserTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/PnfMetadataParserTest.java @@ -122,7 +122,7 @@ public class PnfMetadataParserTest { //then List<CSARArchive.CSARError> errors = data.getRight(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/PnfNonManoArtifactsParserTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/PnfNonManoArtifactsParserTest.java index 388a98f..2cd648a 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/PnfNonManoArtifactsParserTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/PnfNonManoArtifactsParserTest.java @@ -56,7 +56,7 @@ public class PnfNonManoArtifactsParserTest { pnfManifestParser.fetchNonManoArtifacts(); //then - assertThat(nonManoArtifacts.isPresent()).isFalse(); + assertThat(nonManoArtifacts).isNotPresent(); } @Test @@ -88,7 +88,7 @@ public class PnfNonManoArtifactsParserTest { //then List<CSARArchive.CSARError> errors = data.getRight(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/VnfManifestParserTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/VnfManifestParserTest.java index 91bb6b1..7fa73a7 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/VnfManifestParserTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/VnfManifestParserTest.java @@ -43,7 +43,7 @@ public class VnfManifestParserTest { CSARArchive.Manifest.Metadata metadata = metadataListPair.getKey(); List<CSARArchive.CSARError> errors = metadataListPair.getValue(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); assertThat(metadata.getProductName()).isEqualTo(" vCSCF"); assertThat(metadata.getProviderId()).isEqualTo(" ZTE"); assertThat(metadata.getPackageVersion()).isEqualTo(" 1.0"); @@ -64,7 +64,7 @@ public class VnfManifestParserTest { new SourcesParser.Source("scripts/install.sh", "SHA-256", "d0e7828293355a07c2dccaaa765c80b507e60e6167067c950dc2e6b0da0dbd8b"), new SourcesParser.Source("https://www.vendor_org.com/MRF/v4.1/scripts/scale/scale.sh", "SHA-256", "36f945953929812aca2701b114b068c71bd8c95ceb3609711428c26325649165") ); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @Test @@ -79,6 +79,6 @@ public class VnfManifestParserTest { "AQcBoFEET3icc87PK0nNK9ENqSxItVIoSa0o0S/ISczMs1ZIzkgsKk4tsQ0N1nUM" + "dvb05OXi5XLPLEtViMwvLVLwSE0sKlFIVHAqSk3MBkkBAJv0Fx0=" ); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/IntegrationTestUtils.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/IntegrationTestUtils.java index 6f183d7..6d90b23 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/IntegrationTestUtils.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/IntegrationTestUtils.java @@ -87,4 +87,8 @@ public class IntegrationTestUtils { public static List<String> convertToMessagesList(List<CSARArchive.CSARError> errors) { return errors.stream().map(CSARArchive.CSARError::getMessage).collect(Collectors.toList()); } + + public static List<String> convertToFilesList(List<CSARArchive.CSARError> errors) { + return errors.stream().map(CSARArchive.CSARError::getFile).collect(Collectors.toList()); + } } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR01123IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR01123IntegrationTest.java new file mode 100644 index 0000000..a3112ce --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR01123IntegrationTest.java @@ -0,0 +1,176 @@ +/* + * 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.cvc.csar.cc.sol004; + +import org.assertj.core.api.Condition; +import org.assertj.core.api.HamcrestCondition; +import org.junit.Before; +import org.junit.Test; +import org.onap.cvc.csar.CSARArchive; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.configureTestCase; +import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.convertToMessagesList; + +public class VTPValidateCSARR01123IntegrationTest { + + private static final boolean IS_PNF = true; + private static final String TEST_CSAR_DIRECTORY = "pnf/r01123/"; + + private VTPValidateCSARR01123 testCase; + + @Before + public void setUp() { + testCase = new VTPValidateCSARR01123(); + } + + @Test + public void shouldReturnProperRequestNumber() { + assertThat(testCase.getVnfReqsNo()).isEqualTo("R01123"); + } + + @Test + public void shouldReportThatVendorNameAndVersionAreMissing() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-option1-invalid-noVendor.csar", "vtp-validate-csar-r01123.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(3); + assertThat(convertToMessagesList(errors)).contains( + "Missing. Entry [TOSCA-Meta-File-Version]", + "Missing. Entry [VNF Vendor details]", + "Missing. Entry [Created-by]" + ); + } + + @Test + public void shouldReportThatFileAvailableInCsarIsNotPresentInManifestSources() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-option1-invalid-noFileInManifest.csar", "vtp-validate-csar-r01123.yaml", IS_PNF); + + // when + testCase.execute(); + + Condition<String> containingMissingFiles = new HamcrestCondition<>(allOf( + containsString("TOSCA-Metadata/TOSCA.meta"), + containsString("Artifacts/Deployment/Yang_module/yang-module2.yang"), + containsString("Artifacts/Deployment/Yang_module/yang-module1.yang"), + containsString("Artifacts/Informational/user_guide.txt"), + containsString("Artifacts/sample-pnf.cert") + )); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).haveExactly(1, containingMissingFiles); + } + + @Test + public void shouldReportThatFilePresentInManifestIsNotPresentInCsarFile() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-option1-invalid-missing-files.csar", "vtp-validate-csar-r01123.yaml", IS_PNF); + + // when + testCase.execute(); + + Condition<String> containingMissingFiles = new HamcrestCondition<>(allOf( + containsString("Definitions/a.yaml"), + containsString("Definitions/b.yaml") + )); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).haveExactly(1, containingMissingFiles); + } + + @Test + public void shouldReportThatVendorNameIsMissingAndThatFileIsNotPresentInSource() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-option1-invalid-noVendor-noFileInManifest.csar", "vtp-validate-csar-r01123.yaml", IS_PNF); + + // when + testCase.execute(); + + Condition<String> containingMissingFiles = new HamcrestCondition<>(allOf( + containsString("Artifacts/Informational/user_guide.txt") + )); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(3); + assertThat(convertToMessagesList(errors)).contains( + "Missing. Entry [VNF Vendor details]", + "Missing. Entry [Created-by]" + ); + assertThat(convertToMessagesList(errors)).haveExactly(1, containingMissingFiles); + } + + @Test + public void shouldNotReportAnyErrorWhenAllFilesPresentInCsarArePresentInSources() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-option1-valid.csar", "vtp-validate-csar-r01123.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isZero(); + } + + @Test + public void shouldNotReportAnyErrorWhenValidCsarIsZippedWithCmsFile() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-option2-valid-with-cms.zip", "vtp-validate-csar-r01123.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isZero(); + } + + @Test + public void shouldReportThatFileIsNotPresentInSourcesWhenInvalidCsarFileIsZippedWithCmsFile() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-option2-invalid-with-cms.zip", "vtp-validate-csar-r01123.yaml", IS_PNF); + + // when + testCase.execute(); + + Condition<String> containingMissingFiles = new HamcrestCondition<>( + containsString("Artifacts/Informational/user_guide.txt") + ); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).haveExactly(1, containingMissingFiles); + } + +} diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR10087IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR10087IntegrationTest.java index 921e903..2cc739c 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR10087IntegrationTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR10087IntegrationTest.java @@ -63,6 +63,19 @@ public class VTPValidateCSARR10087IntegrationTest { } @Test + public void testWithoutTOSCAMetaDir() throws Exception { + // given + configureTestCase(testCase, "pnf/toscaMetaFile.csar", "vtp-validate-csar-r10087.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(7); + } + + @Test public void shouldReportThatDefinitionYAMLDoesNotExist() throws Exception { // given configureTestCase(testCase, "pnf/r10087/invalidEntryDefinitionsInToscaMeta.csar", "vtp-validate-csar-r10087.yaml", IS_PNF); diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206IntegrationTest.java index 036e169..2d6d058 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206IntegrationTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR130206IntegrationTest.java @@ -20,8 +20,10 @@ package org.onap.cvc.csar.cc.sol004; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import org.onap.cli.fw.error.OnapCommandException; import org.onap.cvc.csar.CSARArchive; +import java.net.URISyntaxException; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -49,24 +51,110 @@ public class VTPValidateCSARR130206IntegrationTest { "To verify signed package please please follow instructions from test/resources/README.txt file and comment @Ignore tag. " + "Use instructions for option 1. Test was created for manual verification." ) - public void manual_shouldValidateProperCsar() throws Exception { + public void manual_shouldValidateProperCsarWithCms() throws Exception { // given - configureTestCase(testCase, "pnf/r130206/csar-option1-valid.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + configureTestCase(testCase, "pnf/r130206/csar-cert-in-cms-valid.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); // when testCase.execute(); // then List<CSARArchive.CSARError> errors = testCase.getErrors(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @Test - public void shouldReportThatOnlySignatureIsInvalid() throws Exception { + @Ignore("It is impossible to write test which will always pass, because certificate used to sign the file has time validity." + + "To verify signed package please please follow instructions from test/resources/README.txt file and comment @Ignore tag. " + + "Use instructions for option 1. Test was created for manual verification." + ) + public void manual_shouldValidateCsarWithCertificateInToscaEtsiWithValidSignature() throws Exception { + + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-tosca-valid.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isZero(); + } + + @Test + public void shouldReportWarningForMissingCertInCmsToscaMetaAndRootCatalogAndMissingHashCodesInManifest() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-not-secure-warning.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains( + "Warning. Consider adding package integrity and authenticity assurance according to ETSI NFV-SOL 004 Security Option 1" + ); + } + + @Test + public void shouldReturnNoErrorWhenCertIsOnlyInCmsAndAlgorithmAndHashesAreCorrect() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-cms.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains( + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnNoErrorWhenCertIsOnlyInToscaAndAlgorithmAndHashesAreCorrect() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-tosca.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains( + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnErrorWhenCsarContainsToscaFileHoweverToscaDoesNotContainsCertEntryAndAlgorithmAndHashesAreCorrect() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-with-tosca-no-cert-entry.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains( + "Unable to find ETSI-Entry-Certificate in Tosca file" + ); + } + @Test + public void shouldReturnErrorWhenCertIsOnlyInCmsHoweverHashesAreIncorrect() + throws Exception{ // given - configureTestCase(testCase, "pnf/r130206/csar-option1-validSection.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + configureTestCase(testCase, "pnf/r130206/csar-cert-in-cms-incorrect-hash.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); // when testCase.execute(); @@ -75,52 +163,307 @@ public class VTPValidateCSARR130206IntegrationTest { List<CSARArchive.CSARError> errors = testCase.getErrors(); assertThat(errors.size()).isEqualTo(2); assertThat(convertToMessagesList(errors)).contains( - "File has invalid CMS signature!", - "Mismatch between contents of non-mano-artifact-sets and source files of the package" + "Source 'Artifacts/Other/my_script.csh' has wrong hash!", + "File has invalid signature!" ); } @Test - public void shouldReportErrorsForInvalidCsar() throws Exception { + public void shouldReturnErrorWhenCertIsOnlyInToscaHoweverHashesAreIncorrect() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-tosca-incorrect-hash.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(2); + assertThat(convertToMessagesList(errors)).contains( + "Source 'Artifacts/Deployment/Measurements/PM_Dictionary.yml' has wrong hash!", + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnErrorWhenCertIsOnlyInRootDirectoryHoweverHashesAreIncorrect() + throws Exception{ // given - configureTestCase(testCase, "pnf/r130206/csar-option1-invalid.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + configureTestCase(testCase, "pnf/r130206/csar-cert-in-root-incorrect-hash.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); // when testCase.execute(); // then List<CSARArchive.CSARError> errors = testCase.getErrors(); - assertThat(errors.size()).isEqualTo(6); + assertThat(errors.size()).isEqualTo(3); assertThat(convertToMessagesList(errors)).contains( - "Unable to find CMS section in manifest!", - "Source 'Definitions/MainServiceTemplate.yaml' has wrong hash!", - "Source 'Artifacts/Other/my_script.csh' has hash, but unable to find algorithm tag!", - "Unable to calculate digest - file missing: Artifacts/NonExisting2.txt", - "Mismatch between contents of non-mano-artifact-sets and source files of the package", - "File has invalid CMS signature!" + "Source 'Artifacts/Deployment/Events/RadioNode_Pnf_v1.yaml' has wrong hash!", + "Unable to find ETSI-Entry-Certificate in Tosca file", + "Certificate present in root catalog despite the TOSCA.meta file" ); } + @Test + public void shouldReturnErrorWhenToscaEtsiEntryCertificatePointToNotExistingFile() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-with-tosca-cert-pointing-non-existing-cert.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(2); + assertThat(convertToMessagesList(errors)).contains( + "Unable to find cert file defined by ETSI-Entry-Certificate!", + "Invalid value. Entry [Entry-Certificate]. Artifacts/sample-pnf.cert does not exist" + ); + } + + @Test + public void shouldReturnErrorWhenCertificateIsLocatedInCmsAndInTosca() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-cms-and-tosca.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(3); + assertThat(convertToMessagesList(errors)).contains( + "ETSI-Entry-Certificate entry in Tosca.meta is defined despite the certificate is included in the signature container", + "ETSI-Entry-Certificate certificate present despite the certificate is included in the signature container", + "File has invalid signature!" + ); + } @Test - public void shouldReportThanInVnfPackageCertFileWasNotDefined() throws Exception { + public void shouldReturnErrorWhenCertificateIsLocatedInCmsAndInToscaAndHashIsIncorrect() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-cms-and-tosca-incorrect-hash.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(4); + assertThat(convertToMessagesList(errors)).contains( + "ETSI-Entry-Certificate entry in Tosca.meta is defined despite the certificate is included in the signature container", + "ETSI-Entry-Certificate certificate present despite the certificate is included in the signature container", + "Source 'Artifacts/Informational/user_guide.txt' has wrong hash!", + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnErrorWhenCertificateIsLocatedInCmsAndInToscaAndInRootDirectory() + throws Exception{ // given - configureTestCase(testCase, "sample2.csar", "vtp-validate-csar-r130206.yaml", false); + configureTestCase(testCase, "pnf/r130206/csar-cert-in-cms-and-root-and-tosca.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); // when testCase.execute(); // then List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(4); assertThat(convertToMessagesList(errors)).contains( - "Unable to find cert file defined by Entry-Certificate!", - "Unable to find CMS section in manifest!", - "Missing. Entry [tosca_definitions_version]" + "ETSI-Entry-Certificate entry in Tosca.meta is defined despite the certificate is included in the signature container", + "ETSI-Entry-Certificate certificate present despite the certificate is included in the signature container", + "Certificate present in root catalog despite the certificate is included in the signature container", + "File has invalid signature!" ); } + @Test + public void shouldReturnErrorWhenCertificateIsLocatedInCmsAndInToscaAndInRootDirectoryAndHashIsIncorrect() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-cms-and-root-and-tosca-incorrect-hash.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(5); + assertThat(convertToMessagesList(errors)).contains( + "ETSI-Entry-Certificate entry in Tosca.meta is defined despite the certificate is included in the signature container", + "ETSI-Entry-Certificate certificate present despite the certificate is included in the signature container", + "Certificate present in root catalog despite the certificate is included in the signature container", + "Source 'Artifacts/Informational/user_guide.txt' has wrong hash!", + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnErrorWhenCertificateIsLocatedInCmsAndInRootDirectory() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-cms-and-root.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(2); + assertThat(convertToMessagesList(errors)).contains( + "Certificate present in root catalog despite the certificate is included in the signature container", + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnErrorWhenCertificateIsLocatedInCmsAndInRootDirectoryAndHashIsIncorrect() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-cms-and-root-incorrect-hash.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(3); + assertThat(convertToMessagesList(errors)).contains( + "Certificate present in root catalog despite the certificate is included in the signature container", + "Source 'Artifacts/Informational/user_guide.txt' has wrong hash!", + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnErrorWhenCertificateIsLocatedInToscaAndInRootDirectory() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-root-and-tosca.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(2); + assertThat(convertToMessagesList(errors)).contains( + "Certificate present in root catalog despite the TOSCA.meta file", + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnErrorWhenCertificateIsLocatedInToscaAndInRootDirectoryAdnHashIsIncorrect() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-root-and-tosca-incorrect-hash.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(3); + assertThat(convertToMessagesList(errors)).contains( + "Certificate present in root catalog despite the TOSCA.meta file", + "Source 'Artifacts/Deployment/Yang_module/yang-module1.yang' has wrong hash!", + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnNoErrorWhenCertificateIsLocatedInToscaAndInRootDirectoryHoweverEtsiEntryIsPointingCertificateInRoot() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-root-pointed-by-tosca.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains( + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnErrorWhenCertificateIsLocatedInToscaHoweverManifestDoesNotContainsCms() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-tosca-no-cms.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains( + "Unable to find cms signature!" + ); + } + + @Test + public void shouldReturnErrorWhenCsarDoesNotContainsCmsAndCertsHoweverManifestContainsHash() + throws Exception{ + // given + configureTestCase(testCase, "pnf/r130206/csar-no-cms-no-cert-with-hash.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains( + "Unable to find cms signature!" + ); + } + + @Test + public void shouldReturnNoCertificationErrorWhenCertIsOnlyInRoot() throws Exception { + + // given + configureTestCase(testCase, "pnf/r130206/csar-cert-in-root.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + + // This test returns other errors that are connected with missing tosca entry, + // in order to simplify testing, assertion only checks if certificate in root was found and used to validate CMS + assertThat(convertToMessagesList(errors)).contains( + "File has invalid signature!" + ); + } + + @Test + public void shouldReturnCertificateNotFoundErrorWhenCertIsNotPresentInCmsInRootAndTocsaDirectoryIsMissing() throws Exception { + + // given + configureTestCase(testCase, "pnf/r130206/csar-no-cert-no-tosca-dir.csar", "vtp-validate-csar-r130206.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + + // This test returns other errors that are connected with missing tosca entry, + // in order to simplify testing, assertion only checks if "certificate not found" error was reported + assertThat(convertToMessagesList(errors)).contains( + "Unable to find cert file!" + ); + } } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR146092IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR146092IntegrationTest.java index bf9b094..a10aa91 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR146092IntegrationTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR146092IntegrationTest.java @@ -19,10 +19,9 @@ package org.onap.cvc.csar.cc.sol004; import org.junit.Before; import org.junit.Test; -import org.onap.cvc.csar.CSARArchive; +import org.onap.cvc.csar.CSARArchive.CSARError; import java.util.List; -import org.onap.cvc.csar.CSARArchive.CSARError; import static org.assertj.core.api.Assertions.assertThat; import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.configureTestCase; @@ -45,24 +44,38 @@ public class VTPValidateCSARR146092IntegrationTest { } @Test - public void shouldDoNotReportErrorWhenNonManoArtifactIsNotAvailable() throws Exception { + public void shouldNotReportErrorWhenCSARValid() throws Exception { + //given + configureTestCase(testCase, "pnf/r146092/validFile.csar", + "vtp-validate-csar-r146092.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + final List<CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isZero(); + } + + @Test + public void shouldNotReportErrorWhenNonManoArtifactIsNotAvailable() throws Exception { // given configureTestCase(testCase, "pnf/r146092/missingNonManoArtifactInManifest.csar", - "vtp-validate-csar-r146092.yaml", IS_PNF); + "vtp-validate-csar-r146092.yaml", IS_PNF); // when testCase.execute(); // then final List<CSARError> errors = testCase.getErrors(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @Test public void shouldReportThatMandatoryNonManoArtifactSetEntryHasNotAllFields() throws Exception { // given configureTestCase(testCase, "pnf/r146092/missingFieldsInNonManoArtifactManifest.csar", - "vtp-validate-csar-r146092.yaml", IS_PNF); + "vtp-validate-csar-r146092.yaml", IS_PNF); // when testCase.execute(); @@ -71,7 +84,7 @@ public class VTPValidateCSARR146092IntegrationTest { final List<CSARError> errors = testCase.getErrors(); assertThat(errors.size()).isEqualTo(1); assertThat(convertToMessagesList(errors)).contains( - "Missing. Entry [[onap_ansible_playbooks, onap_others, onap_pm_dictionary, onap_pnf_sw_information, onap_scripts, onap_ves_events, onap_yang_modules]]" + "Missing. Entry [[onap_ansible_playbooks, onap_others, onap_pm_dictionary, onap_pnf_sw_information, onap_scripts, onap_ves_events, onap_yang_modules]]" ); } @@ -79,7 +92,7 @@ public class VTPValidateCSARR146092IntegrationTest { public void shouldReportThatNonManoArtifactEntryHasAnySource() throws Exception { // given configureTestCase(testCase, "pnf/r146092/noSourceElementInNonManoArtifactEntryManifest.csar", - "vtp-validate-csar-r146092.yaml", IS_PNF); + "vtp-validate-csar-r146092.yaml", IS_PNF); // when testCase.execute(); @@ -88,7 +101,7 @@ public class VTPValidateCSARR146092IntegrationTest { final List<CSARError> errors = testCase.getErrors(); assertThat(errors.size()).isEqualTo(1); assertThat(convertToMessagesList(errors)).contains( - "Missing. Entry [Source under onap_ves_events]" + "Missing. Entry [Source under onap_ves_events]" ); } @@ -104,7 +117,7 @@ public class VTPValidateCSARR146092IntegrationTest { final List<CSARError> errors = testCase.getErrors(); assertThat(errors.size()).isEqualTo(1); assertThat(convertToMessagesList(errors)).contains( - "Invalid. Entry [Source under onap_ves_events has invalid 'Artifacts/Deployment/Events/RadioNode.yml' path]" + "Invalid. Entry [Source under onap_ves_events has invalid 'Artifacts/Deployment/Events/RadioNode.yml' path]" ); } @@ -120,7 +133,7 @@ public class VTPValidateCSARR146092IntegrationTest { final List<CSARError> errors = testCase.getErrors(); assertThat(errors.size()).isEqualTo(4); assertThat(convertToMessagesList(errors)).contains( - "Missing. Entry [Definition YAML]" + "Missing. Entry [Definition YAML]" ); } @@ -128,7 +141,7 @@ public class VTPValidateCSARR146092IntegrationTest { public void shouldReportThatEntryHasInvalidPathWhenYamlFileIsNotPresent() throws Exception { // given configureTestCase(testCase, "pnf/r146092/missingYamlFileReferedInSourceSessionOfManifest.csar", "vtp-validate-csar-r146092.yaml", - IS_PNF); + IS_PNF); // when testCase.execute(); @@ -137,7 +150,7 @@ public class VTPValidateCSARR146092IntegrationTest { final List<CSARError> errors = testCase.getErrors(); assertThat(errors.size()).isEqualTo(1); assertThat(convertToMessagesList(errors)).contains( - "Invalid. Entry [Source under onap_pnf_sw_information has invalid 'Files/pnf-sw-information/pnf-sw-information.yaml' path]" + "Invalid. Entry [Source under onap_pnf_sw_information has invalid 'Files/pnf-sw-information/pnf-sw-information.yaml' path]" ); } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR293901IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR293901IntegrationTest.java index 2835772..2b9b4f4 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR293901IntegrationTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR293901IntegrationTest.java @@ -71,7 +71,7 @@ public class VTPValidateCSARR293901IntegrationTest { // then List<CSARArchive.CSARError> errors = testCase.getErrors(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @Test diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR57019IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR57019IntegrationTest.java index 088eab7..d6d06b3 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR57019IntegrationTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR57019IntegrationTest.java @@ -73,7 +73,7 @@ public class VTPValidateCSARR57019IntegrationTest { // then List<CSARArchive.CSARError> errors = testCase.getErrors(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @Test diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR787965IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR787965IntegrationTest.java index 49696e6..33a1754 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR787965IntegrationTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR787965IntegrationTest.java @@ -76,7 +76,7 @@ public class VTPValidateCSARR787965IntegrationTest { // then List<CSARArchive.CSARError> errors = testCase.getErrors(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } @Test @@ -111,7 +111,7 @@ public class VTPValidateCSARR787965IntegrationTest { // then List<CSARArchive.CSARError> errors = testCase.getErrors(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); } } diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR816745IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR816745IntegrationTest.java new file mode 100644 index 0000000..17e9de3 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR816745IntegrationTest.java @@ -0,0 +1,229 @@ +/* + * 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.cvc.csar.cc.sol004; + +import org.assertj.core.api.Condition; +import org.assertj.core.api.HamcrestCondition; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.onap.cvc.csar.CSARArchive; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.configureTestCase; +import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.convertToMessagesList; +import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.convertToFilesList; + +public class VTPValidateCSARR816745IntegrationTest { + + private static final boolean IS_PNF = true; + private static final String TEST_CSAR_DIRECTORY = "pnf/r816745/"; + private static final int NUMBER_OF_EXPECTED_ERRORS = 4; + private static final String LETTER_S_WITH_ASCII_CODE = "s(115)"; + + private VTPValidateCSARR816745 testCase; + + @Rule + public ExpectedException exceptionRule = ExpectedException.none(); + + @Before + public void setUp() { + testCase = new VTPValidateCSARR816745(); + } + + @Test + public void shouldAddPmDictionaryLoadingErrorWhenPmDictionaryHaveNoSourceInManifest() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-with-missing-source-value-for-pm-dictionary-in-manifest.csar", "vtp-validate-csar-r816745.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains("Fail to load PM_Dictionary With error: onap_pm_dictionary in manifest does not contains key 'Source'"); + } + + @Test + public void shouldNotReportAnyErrorWhenCsarIsNotContainingPmDictionary() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-with-no-pm-dictionary.csar", "vtp-validate-csar-r816745.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isZero(); + } + + @Test + public void shouldReturnNoErrorsWhenCsarContainsValidPmDictionary() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-with-valid-pm-dictionary.csar", "vtp-validate-csar-r816745.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(0); + } + + @Test + public void shouldReturnNoErrorsWhenZipContainsCsarWithValidPmDictionary() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "zip-with-valid-pm-dictionary.zip", "vtp-validate-csar-r816745.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(0); + } + + @Test + public void shouldReturnListOfErrorsWhenCsarContainsInvalidPmDictionary() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-with-invalid-pm-dictionary.csar", "vtp-validate-csar-r816745.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + assertThatReturnedErrorsAreCorrect(testCase.getErrors()); + } + + @Test + public void shouldReturnListOfErrorsWhenZipContainsCsarWithInvalidPmDictionary() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "zip-with-invalid-pm-dictionary.zip", "vtp-validate-csar-r816745.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + assertThatReturnedErrorsAreCorrect(testCase.getErrors()); + } + + @Test + public void shouldAddPmDictionaryLoadingErrorWhenGivenInvalidPath() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-with-empty-pm-dictionary.csar", "vtp-validate-csar-r816745.yaml", IS_PNF); + + // when then + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains("Fail to load PM_Dictionary With error: PM_Dictionary YAML file is empty"); + } + + @Test + public void shouldReturnListContainingOneErrorsWhenCsarContainsPmDictionaryWithInvalidKeyMapping() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-with-invalid-pm-dictionary-invalid-mapping.csar", "vtp-validate-csar-r816745.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors).get(0)).contains( + "Fail to load PM_Dictionary With error: mapping values are not allowed here" + ); + } + + @Test + public void shouldReturnListContainingOneErrorsWhenCsarContainsPmDictionaryWithIncorrectEscapeCharacter() throws Exception { + // given + configureTestCase(testCase, TEST_CSAR_DIRECTORY + "csar-with-invalid-pm-dictionary-unknown-escape-character.csar", "vtp-validate-csar-r816745.yaml", IS_PNF); + + // when + testCase.execute(); + + // then + List<CSARArchive.CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors).get(0)).contains( + "Fail to load PM_Dictionary With error: while scanning a double-quoted scalar", + "found unknown escape character " + LETTER_S_WITH_ASCII_CODE + ); + } + + @Test + public void shouldReturnProperRequestNumber() { + assertThat(testCase.getVnfReqsNo()).isEqualTo("R816745"); + } + + private void assertThatReturnedErrorsAreCorrect(List<CSARArchive.CSARError> errors) { + assertThat(errors.size()).isEqualTo(NUMBER_OF_EXPECTED_ERRORS); + + Condition<String> containingSameFileForAllErrors = new HamcrestCondition<>( + containsString("Artifacts/Deployment/Measurements/PM_Dictionary.yml") + ); + assertThat(convertToFilesList(errors)) + .haveExactly(NUMBER_OF_EXPECTED_ERRORS, containingSameFileForAllErrors); + + Condition<String> containingErrorForMissingValueInFirstDocument = new HamcrestCondition<>(allOf( + containsString("Invalid YAML document in PM_Dictionary file."), + containsString("In document number 1"), + containsString("Path: /pmMetaData/pmFields/"), + containsString("Key not found: measChangeType") + )); + assertThat(convertToMessagesList(errors)).haveExactly(1, containingErrorForMissingValueInFirstDocument); + + Condition<String> containingErrorForWrongValueInFirstDocument = new HamcrestCondition<>(allOf( + containsString("Invalid YAML document in PM_Dictionary file."), + containsString("In document number 1"), + containsString("Path: /pmMetaData/pmFields/measResultType"), + containsString("Value(s) is/are not in array of accepted values."), + containsString("value(s): integer"), + containsString("accepted value(s): [float, uint32, uint64]") + )); + assertThat(convertToMessagesList(errors)).haveExactly(1, containingErrorForWrongValueInFirstDocument); + + Condition<String> containingErrorForMissingValueInSecondDocument = new HamcrestCondition<>(allOf( + containsString("Invalid YAML document in PM_Dictionary file."), + containsString("In document number 2"), + containsString("Path: /pmMetaData/pmFields/"), + containsString("Key not found: measChangeType") + )); + assertThat(convertToMessagesList(errors)).haveExactly(1, containingErrorForMissingValueInSecondDocument); + + Condition<String> containingErrorForWrongValueInArrayInThirdDocument = new HamcrestCondition<>(allOf( + containsString("Invalid YAML document in PM_Dictionary file."), + containsString("In document number 3"), + containsString("Path: /pmMetaData/pmFields/measAdditionalFields/vendorField1"), + containsString("Value(s) is/are not in array of accepted values."), + containsString("value(s): [Z, A]"), + containsString("accepted value(s): [X, Y, Z]") + )); + assertThat(convertToMessagesList(errors)).haveExactly(1, containingErrorForWrongValueInArrayInThirdDocument); + } + +} diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082IntegrationTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082IntegrationTest.java index fb9e431..868fad2 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082IntegrationTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/cc/sol004/VTPValidateCSARR972082IntegrationTest.java @@ -21,10 +21,12 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.configureTestCase; import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.convertToMessagesList; +import java.net.URISyntaxException; import java.util.List; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import org.onap.cli.fw.error.OnapCommandException; import org.onap.cvc.csar.CSARArchive; import org.onap.cvc.csar.CSARArchive.CSARError; @@ -55,7 +57,37 @@ public class VTPValidateCSARR972082IntegrationTest { // then final List<CSARError> errors = testCase.getErrors(); - assertThat(errors.size()).isEqualTo(0); + assertThat(errors.size()).isZero(); + } + + @Test + public void shouldReturnErrorWhenFileExtensionIsNotYaml() throws Exception { + // given + configureTestCase(testCase, PNF_R_972082 + "fileExtensionOfArtifactIsNotYaml.csar", VTP_VALIDATE_CSAR_R_972082_YAML, IS_PNF); + + // when + testCase.execute(); + + // then + final List<CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains( + "Invalid. File extension Files/pnf-sw-information/pnf-sw-information.json is invalid" + ); + } + + @Test + public void shouldReturnNoErrorWhenOptionalNonManoArtifactSetEntryIsNotPresent() throws Exception { + // given + configureTestCase(testCase, PNF_R_972082 + "missingOnapPnfSwInformationArtifactSetEntry.csar", + VTP_VALIDATE_CSAR_R_972082_YAML, IS_PNF); + + // when + testCase.execute(); + + // then + final List<CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isZero(); } @Test @@ -77,9 +109,9 @@ public class VTPValidateCSARR972082IntegrationTest { } @Test - public void shouldReportThatMandatoryNonManoArtifactSetEntryHasNotAllFields_() throws Exception { + public void shouldReportMissingPnfSoftwareVersionInYamlFile() throws Exception { // given - configureTestCase(testCase, PNF_R_972082 + "missingFieldsInNonManoArtifactManifest.csar", + configureTestCase(testCase, PNF_R_972082 + "missingPnfSoftwareVersionInYamlFile.csar", VTP_VALIDATE_CSAR_R_972082_YAML, IS_PNF); // when @@ -89,15 +121,15 @@ public class VTPValidateCSARR972082IntegrationTest { final List<CSARError> errors = testCase.getErrors(); assertThat(errors.size()).isEqualTo(1); assertThat(convertToMessagesList(errors)).contains( - "Missing. Entry [[onap_pnf_sw_information]]" + "Missing. Entry [pnf_software_version in Files/pnf-sw-information/pnf-sw-information.yaml]" ); } @Test - public void shouldReportMissingPnfSoftwareVersionInYamlFile() throws Exception { + public void shouldReportMissingSourceElementUnderAttribute() throws OnapCommandException, URISyntaxException { // given - configureTestCase(testCase, PNF_R_972082 + "missingPnfSoftwareVersionInYamlFile.csar", - VTP_VALIDATE_CSAR_R_972082_YAML, IS_PNF); + configureTestCase(testCase, PNF_R_972082 + "missingSourceElementUnderAttributeError.csar", + VTP_VALIDATE_CSAR_R_972082_YAML, IS_PNF); // when testCase.execute(); @@ -106,8 +138,24 @@ public class VTPValidateCSARR972082IntegrationTest { final List<CSARError> errors = testCase.getErrors(); assertThat(errors.size()).isEqualTo(1); assertThat(convertToMessagesList(errors)).contains( - "Missing. Entry [pnf_software_version in Files/pnf-sw-information/pnf-sw-information.yaml]" + "Missing. Entry [Source under onap_pnf_sw_information]" ); } + @Test + public void shouldReportInvalidYamlStructure() throws OnapCommandException, URISyntaxException { + // given + configureTestCase(testCase, PNF_R_972082 + "invalidYamlStructure.csar", + VTP_VALIDATE_CSAR_R_972082_YAML, IS_PNF); + + // when + testCase.execute(); + + // then + final List<CSARError> errors = testCase.getErrors(); + assertThat(errors.size()).isEqualTo(1); + assertThat(convertToMessagesList(errors)).contains( + "Invalid. Yaml file Files/pnf-sw-information/pnf-sw-information.yaml is invalid" + ); + } }
\ No newline at end of file diff --git a/csarvalidation/src/test/java/org/onap/cvc/csar/security/ShaHashCodeGeneratorTest.java b/csarvalidation/src/test/java/org/onap/cvc/csar/security/ShaHashCodeGeneratorTest.java index 1ea5dd5..b5c4efa 100644 --- a/csarvalidation/src/test/java/org/onap/cvc/csar/security/ShaHashCodeGeneratorTest.java +++ b/csarvalidation/src/test/java/org/onap/cvc/csar/security/ShaHashCodeGeneratorTest.java @@ -39,8 +39,9 @@ public class ShaHashCodeGeneratorTest { final String hashCode = shaHashCodeGenerator.generateSha256("test".getBytes()); - assertThat(hashCode).isEqualTo(shaHashCodeGenerator.generateSha256("test".getBytes())); - assertThat(hashCode).isNotEqualTo(shaHashCodeGenerator.generateSha256("Test".getBytes())); + assertThat(hashCode) + .isEqualTo(shaHashCodeGenerator.generateSha256("test".getBytes())) + .isNotEqualTo(shaHashCodeGenerator.generateSha256("Test".getBytes())); } @Test @@ -48,7 +49,8 @@ public class ShaHashCodeGeneratorTest { final String hashCode = shaHashCodeGenerator.generateSha512("test".getBytes()); - assertThat(hashCode).isEqualTo(shaHashCodeGenerator.generateSha512("test".getBytes())); - assertThat(hashCode).isNotEqualTo(shaHashCodeGenerator.generateSha512("Test".getBytes())); + assertThat(hashCode) + .isEqualTo(shaHashCodeGenerator.generateSha512("test".getBytes())) + .isNotEqualTo(shaHashCodeGenerator.generateSha512("Test".getBytes())); } }
\ No newline at end of file diff --git a/csarvalidation/src/test/java/org/onap/functional/CsarValidationUtility.java b/csarvalidation/src/test/java/org/onap/functional/CsarValidationUtility.java new file mode 100644 index 0000000..24ef778 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/functional/CsarValidationUtility.java @@ -0,0 +1,65 @@ +/** + * Copyright 2020 Nokia + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.functional; + +import com.google.gson.Gson; +import org.onap.cli.fw.output.OnapCommandResult; +import org.onap.functional.cli.OnapCliValidationResponseWrapper; +import org.onap.functional.cli.OnapCliWrapper; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +public final class CsarValidationUtility { + + private static final int NOR_ERROR_CODE = 0; + private static final String UNKNOWN_LINE_NUMBER = "-1"; + private static final String UNKNOWN_FILE = ""; + + private CsarValidationUtility(){} + + public static final String CERTIFICATION_RULE = "r130206"; + public static final String OPERATION_STATUS_FAILED = "FAILED"; + public static final String OPERATION_STATUS_PASS = "PASS"; + + public static OnapCliValidationResponseWrapper getCliCommandValidationResult(OnapCliWrapper cli) { + final OnapCommandResult onapCommandResult = cli.getCommandResult(); + return new Gson().fromJson(onapCommandResult.getOutput().toString(), OnapCliValidationResponseWrapper.class); + } + + public static OnapCliValidationResponseWrapper.ValidationResultWrapper.ValidationErrorWrapper createExpectedError( + String rule, String errorCode, String errorMessage + ) { + return new OnapCliValidationResponseWrapper.ValidationResultWrapper.ValidationErrorWrapper( + rule.toUpperCase(), errorCode, + errorMessage, + UNKNOWN_FILE, UNKNOWN_LINE_NUMBER + ); + } + + public static boolean ruleHaveOneOfCodes(String ruleCode, String... codes ) { + return Arrays.asList(codes).contains(ruleCode); + } + + public static void verifyThatOperationFinishedWithoutAnyError(OnapCliWrapper cli) { + assertThat(cli.getExitCode()).isEqualTo(NOR_ERROR_CODE); + } + + + +} diff --git a/csarvalidation/src/test/java/org/onap/functional/PnfValidationFunctionalTest.java b/csarvalidation/src/test/java/org/onap/functional/PnfValidationFunctionalTest.java new file mode 100644 index 0000000..903691e --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/functional/PnfValidationFunctionalTest.java @@ -0,0 +1,132 @@ +/** + * Copyright 2020 Nokia + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.functional; + +import org.junit.Test; +import org.onap.functional.cli.OnapCliValidationResponseWrapper; +import org.onap.functional.cli.OnapCliWrapper; + +import java.net.URISyntaxException; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.absoluteFilePath; +import static org.onap.functional.CsarValidationUtility.CERTIFICATION_RULE; +import static org.onap.functional.CsarValidationUtility.OPERATION_STATUS_FAILED; +import static org.onap.functional.CsarValidationUtility.OPERATION_STATUS_PASS; +import static org.onap.functional.CsarValidationUtility.createExpectedError; +import static org.onap.functional.CsarValidationUtility.getCliCommandValidationResult; +import static org.onap.functional.CsarValidationUtility.verifyThatOperationFinishedWithoutAnyError; + + +public class PnfValidationFunctionalTest { + + @Test + public void shouldReportOnlyWarningWhenCsarDoNotHaveCertificateAndHashesInManifest() throws URISyntaxException { + // given + OnapCliValidationResponseWrapper.ValidationResultWrapper.ValidationErrorWrapper expectedWarning = + createExpectedError(CERTIFICATION_RULE, "0x1006", + "Warning. Consider adding package integrity and authenticity assurance according to ETSI NFV-SOL 004 Security Option 1"); + + OnapCliWrapper cli = new OnapCliWrapper(createPnfValidationRequestInfo( "pnf/validFile.csar")); + + // when + cli.handle(); + + // then + final OnapCliValidationResponseWrapper result = getCliCommandValidationResult(cli); + + assertThat(result.criteria).isEqualTo(OPERATION_STATUS_PASS); + result.results.forEach((ruleValidationResult)->{ + assertThat(ruleValidationResult.errors).hasSize(0); + if (ruleValidationResult.vnfreqName.equals(CERTIFICATION_RULE)) { + assertThat(ruleValidationResult.warnings) + .hasSize(1) + .containsOnly(expectedWarning); + } else { + assertThat(ruleValidationResult.warnings).hasSize(0); + } + }); + verifyThatOperationFinishedWithoutAnyError(cli); + } + + @Test + public void shouldNotReportThatPnfValidationFailedWhenZipDoNotHaveCertificatesAndHashesInManifest() throws URISyntaxException { + // given + OnapCliWrapper cli = new OnapCliWrapper(createPnfValidationRequestInfo( "pnf/signed-package-valid-signature.zip")); + + // when + cli.handle(); + + // then + final OnapCliValidationResponseWrapper result = getCliCommandValidationResult(cli); + + assertThat(result.criteria).isEqualTo(OPERATION_STATUS_PASS); + verifyThatOperationFinishedWithoutAnyError(cli); + } + + @Test + public void shouldReportThatPnfValidationFailedWhenCsarContainsCertificateInCmsAndInToscaAndInRootAndHashIsIncorrect_allOtherRulesShouldPass() throws URISyntaxException { + // given + + List<OnapCliValidationResponseWrapper.ValidationResultWrapper.ValidationErrorWrapper> expectedErrors = + List.of( + createExpectedError(CERTIFICATION_RULE, "0x4007", + "File has invalid signature!"), + createExpectedError(CERTIFICATION_RULE, "0x4004", + "Source 'Files/pnf-sw-information/pnf-sw-information.yaml' has wrong hash!"), + createExpectedError(CERTIFICATION_RULE, "0x4011", + "ETSI-Entry-Certificate entry in Tosca.meta is defined despite the certificate is included in the signature container"), + createExpectedError(CERTIFICATION_RULE, "0x4012", + "ETSI-Entry-Certificate certificate present despite the certificate is included in the signature container"), + createExpectedError(CERTIFICATION_RULE, "0x4013", + "Certificate present in root catalog despite the certificate is included in the signature container") + ); + OnapCliWrapper cli = new OnapCliWrapper(createPnfValidationRequestInfo( "pnf/r130206/cert-in-cms-and-root-and-tosca-incorrect-hash.csar")); + + // when + cli.handle(); + + // then + final OnapCliValidationResponseWrapper result = getCliCommandValidationResult(cli); + + assertThat(result.criteria).isEqualTo(OPERATION_STATUS_FAILED); + result.results.forEach((ruleValidationResult)->{ + assertThat(ruleValidationResult.warnings).hasSize(0); + if (ruleValidationResult.vnfreqName.equals(CERTIFICATION_RULE)) { + assertThat(ruleValidationResult.errors) + .hasSize(5) + .containsAll(expectedErrors); + } else { + assertThat(ruleValidationResult.errors).hasSize(0); + } + }); + verifyThatOperationFinishedWithoutAnyError(cli); + } + + private String[] createPnfValidationRequestInfo(String csarPath) throws URISyntaxException { + return new String[]{ + "--product", "onap-dublin", + "csar-validate", + "--format", "json", + "--pnf", + "--csar", absoluteFilePath(csarPath) + }; + } + + +} diff --git a/csarvalidation/src/test/java/org/onap/functional/VnfValidationFunctionalTest.java b/csarvalidation/src/test/java/org/onap/functional/VnfValidationFunctionalTest.java new file mode 100644 index 0000000..adaea59 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/functional/VnfValidationFunctionalTest.java @@ -0,0 +1,75 @@ +/** + * Copyright 2017 Huawei Technologies Co., Ltd. + * Copyright 2020 Nokia + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.functional; + +import org.junit.Test; +import org.onap.functional.cli.OnapCliValidationResponseWrapper; +import org.onap.functional.cli.OnapCliWrapper; + +import java.net.URISyntaxException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.onap.cvc.csar.cc.sol004.IntegrationTestUtils.absoluteFilePath; +import static org.onap.functional.CsarValidationUtility.OPERATION_STATUS_FAILED; +import static org.onap.functional.CsarValidationUtility.getCliCommandValidationResult; +import static org.onap.functional.CsarValidationUtility.ruleHaveOneOfCodes; +import static org.onap.functional.CsarValidationUtility.verifyThatOperationFinishedWithoutAnyError; + +public class VnfValidationFunctionalTest { + + + @Test + public void shouldReportThanVnfValidationFailed() throws URISyntaxException { + // given + OnapCliWrapper cli = new OnapCliWrapper(createVnfValidationRequestInfo("VoLTE.csar")); + + // when + cli.handle(); + + // then + final OnapCliValidationResponseWrapper result = getCliCommandValidationResult(cli); + assertThat(result.criteria).isEqualTo(OPERATION_STATUS_FAILED); + result.results.forEach((ruleValidationResult)->{ + if ( ruleHaveOneOfCodes(ruleValidationResult.vnfreqName, + "r01123", "r09467") + ) { + assertThat(ruleValidationResult.errors) + .hasSize(2); + } else if ( ruleHaveOneOfCodes(ruleValidationResult.vnfreqName, + "r21322","r26885","r43958" ,"r66070","r130206") + ) { + assertThat(ruleValidationResult.errors) + .hasSize(1); + } else { + assertThat(ruleValidationResult.errors).hasSize(0); + } + }); + + verifyThatOperationFinishedWithoutAnyError(cli); + } + + private String[] createVnfValidationRequestInfo(String csarPath) throws URISyntaxException { + return new String[]{ + "--product", "onap-dublin", + "csar-validate", + "--format", "json", + "--csar", absoluteFilePath(csarPath) + }; + } + +} diff --git a/csarvalidation/src/test/java/org/onap/functional/cli/OnapCliValidationResponseWrapper.java b/csarvalidation/src/test/java/org/onap/functional/cli/OnapCliValidationResponseWrapper.java new file mode 100644 index 0000000..d011a6e --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/functional/cli/OnapCliValidationResponseWrapper.java @@ -0,0 +1,84 @@ +/** + * Copyright 2020 Nokia + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.functional.cli; + + +import java.util.List; +import java.util.Objects; + +public class OnapCliValidationResponseWrapper { + + public final VnfDataWrapper vnf; + public final String data; + public final String criteria; + public final List<ValidationResultWrapper> results; + public final String contact; + public final String platform; + + public OnapCliValidationResponseWrapper(VnfDataWrapper vnf, String data, String criteria, List<ValidationResultWrapper> results, String contact, String platform) { + this.vnf = vnf; + this.data = data; + this.criteria = criteria; + this.results = results; + this.contact = contact; + this.platform = platform; + } + + public static class VnfDataWrapper { + public String name; + public String vendor; + public String version; + public String type; + public String mode; + } + + public static class ValidationResultWrapper { + public Boolean passed; + public String vnfreqName; + public String description; + public List<ValidationErrorWrapper> errors; + public List<ValidationErrorWrapper> warnings; + + public static class ValidationErrorWrapper { + public String vnfreqNo; + public String code; + public String message; + public String file; + public String lineNumber; + + public ValidationErrorWrapper(String vnfreqNo, String code, String message, String file, String lineNumber) { + this.vnfreqNo = vnfreqNo; + this.code = code; + this.message = message; + this.file = file; + this.lineNumber = lineNumber; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + return o.hashCode() == this.hashCode(); + } + + @Override + public int hashCode() { + return Objects.hash(vnfreqNo, code, message, file, lineNumber); + } + } + } +} diff --git a/csarvalidation/src/test/java/org/onap/functional/cli/OnapCliWrapper.java b/csarvalidation/src/test/java/org/onap/functional/cli/OnapCliWrapper.java new file mode 100644 index 0000000..b5cf589 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/functional/cli/OnapCliWrapper.java @@ -0,0 +1,42 @@ +/** + * Copyright 2020 Nokia + * <p> + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.functional.cli; + + +import org.onap.cli.fw.cmd.OnapCommand; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.output.OnapCommandResult; +import org.onap.cli.main.OnapCli; + +public class OnapCliWrapper extends OnapCli { + + private OnapCommandResult commandResult; + + public OnapCliWrapper(String[] args) { + super(args); + } + + @Override + public void handleTracking(OnapCommand cmd) throws OnapCommandException { + super.handleTracking(cmd); + this.commandResult = cmd.getResult(); + } + + public OnapCommandResult getCommandResult() { + return this.commandResult; + } +} diff --git a/csarvalidation/src/test/java/org/onap/validation/csarvalidationtest/CsarValidatorTest.java b/csarvalidation/src/test/java/org/onap/validation/csar/CsarValidatorTest.java index f9a8d8a..bd363fc 100644 --- a/csarvalidation/src/test/java/org/onap/validation/csarvalidationtest/CsarValidatorTest.java +++ b/csarvalidation/src/test/java/org/onap/validation/csar/CsarValidatorTest.java @@ -1,27 +1,30 @@ -/** +/* * Copyright 2017 Huawei Technologies Co., Ltd. - * + * Copyright 2020 Nokia + * <p> * 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 - * + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> * 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.csarvalidationtest; +package org.onap.validation.csar; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -31,11 +34,12 @@ import java.util.regex.Pattern; import java.util.zip.ZipException; import java.util.zip.ZipFile; -import org.junit.Test; -import org.onap.validation.csar.CommonConstants; -import org.onap.validation.csar.CsarValidator; -import org.onap.validation.csar.FileUtil; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +@RunWith(MockitoJUnitRunner.class) public class CsarValidatorTest { String regex = "^\\/[a-zA-Z]\\:\\/"; @@ -156,12 +160,20 @@ public class CsarValidatorTest { } @Test - public void testCloseInputStream() { + public void testCloseInputStreamForNonExistingDirectory() { InputStream dir = null; FileUtil.closeInputStream(dir); assertTrue(true); } + @Test(expected = ValidationException.class) + public void testCloseInputStream() throws IOException { + InputStream inputStream = mock(InputStream.class); + Mockito.doThrow(new IOException()).when(inputStream).close(); + FileUtil.closeInputStream(inputStream); + assertTrue(true); + } + @Test public void testCloseZipFile() throws ZipException, IOException { File file = new File(sample1); @@ -170,10 +182,19 @@ public class CsarValidatorTest { assertTrue(true); } - @Test - public void testCloseFileStream() throws FileNotFoundException { + @Test(expected = IOException.class) + public void testCloseFileStream() throws IOException { FileInputStream dir3 = new FileInputStream(sample1); FileUtil.closeFileStream(dir3); + dir3.available(); + + } + + @Test(expected = ValidationException.class) + public void testCloseFileStream_reportErrorWhenIOExceptionOccurs() throws IOException { + FileInputStream fileInputStream = mock(FileInputStream.class); + Mockito.doThrow(new IOException()).when(fileInputStream).close(); + FileUtil.closeFileStream(fileInputStream); } @Test @@ -186,6 +207,14 @@ public class CsarValidatorTest { } }; FileUtil.closeOutputStream(dir4); + assertTrue(true); + } + + @Test(expected = ValidationException.class) + public void testCloseOutptutStream_reportErrorWhenIOExceptionOccurs() throws IOException { + OutputStream outputStream = mock(OutputStream.class); + Mockito.doThrow(new IOException()).when(outputStream).close(); + FileUtil.closeOutputStream(outputStream); } private void testValidateCsarMeta(CsarValidator cv) { @@ -219,4 +248,44 @@ public class CsarValidatorTest { String result = CsarValidator.r02454(); assertEquals(true, result == CommonConstants.SUCCESS_STR); } + + @Test + public void testValidateCsar_csarMetaFailed() { + CsarValidator.CsarValidatorSeam csarValidatorSeam = mock(CsarValidator.CsarValidatorSeam.class); + Mockito.when(csarValidatorSeam.validateCsarMeta()).thenReturn("FAIL"); + Mockito.when(csarValidatorSeam.validateAndScanToscaMeta()).thenReturn("SUCCESS"); + Mockito.when(csarValidatorSeam.validateMainService()).thenReturn("FAIL"); + + + String res=CsarValidator.validateCsarContent(csarValidatorSeam); + assertEquals("FAIL OR FAIL",res); + + } + + @Test + public void testValidateCsar_toscaMetaFailed() { + CsarValidator.CsarValidatorSeam csarValidatorSeam = mock(CsarValidator.CsarValidatorSeam.class); + Mockito.when(csarValidatorSeam.validateCsarMeta()).thenReturn("SUCCESS"); + Mockito.when(csarValidatorSeam.validateAndScanToscaMeta()).thenReturn("FAIL"); + Mockito.when(csarValidatorSeam.validateMainService()).thenReturn("SUCCESS"); + + + String res=CsarValidator.validateCsarContent(csarValidatorSeam); + assertEquals("FAIL",res); + } + + @Test + public void testDeleteDir(){ + String dstPath = "./dstPathForTest1"; + File dst = new File(dstPath); + dst.mkdir(); + assertTrue(FileUtil.deleteFile(dstPath)); + } + + @Test + public void testCreateDirectory() { + String dirPath = "src//test//resources//TestDirectory"; + boolean res = FileUtil.createDirectory(dirPath); + assertTrue(res); + } } diff --git a/csarvalidation/src/test/java/org/onap/validation/csarvalidationtest/ValidationExceptionTest.java b/csarvalidation/src/test/java/org/onap/validation/csar/ValidationExceptionTest.java index 8ab498e..fcbc439 100644 --- a/csarvalidation/src/test/java/org/onap/validation/csarvalidationtest/ValidationExceptionTest.java +++ b/csarvalidation/src/test/java/org/onap/validation/csar/ValidationExceptionTest.java @@ -1,20 +1,21 @@ -/** - * Copyright 2017 Huawei Technologies Co., Ltd. +/* + * Copyright 2020 Nokia * <p> * 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 * <p> - * http://www.apache.org/licenses/LICENSE-2.0 - * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> * 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.csarvalidationtest; +package org.onap.validation.csar; import static org.junit.Assert.assertTrue; diff --git a/csarvalidation/src/test/java/org/onap/validation/yaml/YamlFileValidatorTest.java b/csarvalidation/src/test/java/org/onap/validation/yaml/YamlFileValidatorTest.java new file mode 100644 index 0000000..f89cc68 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/validation/yaml/YamlFileValidatorTest.java @@ -0,0 +1,117 @@ +/* + * 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.assertj.core.util.Lists; +import org.junit.Test; +import org.onap.validation.yaml.error.YamlDocumentValidationError; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.yaml.snakeyaml.parser.ParserException; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class YamlFileValidatorTest { + + @Test + public void shouldReturnCorrectErrorsWhenGivenPathToValidPmDictionaryFile() throws YamlProcessingException { + // given + String path = getFullPathForGivenResources(YamlLoadingUtils.PATH_TO_VALID_YAML); + + // when + List<YamlDocumentValidationError> validationErrors = + new YamlFileValidator().validateYamlFileWithSchema(path); + + // then + assertValidationReturnedExpectedErrors(validationErrors); + + } + + @Test + public void shouldReturnCorrecErrorsWhenGivenPathToValidJsonStylePmDictionaryFile() throws YamlProcessingException { + // given + String path = getFullPathForGivenResources(YamlLoadingUtils.PATH_TO_VALID_JSON_STYLE_YAML); + + // when + List<YamlDocumentValidationError> validationErrors = + new YamlFileValidator().validateYamlFileWithSchema(path); + + // then + assertValidationReturnedExpectedErrors(validationErrors); + } + + + private void assertValidationReturnedExpectedErrors(List<YamlDocumentValidationError> validationErrors) { + assertThat(validationErrors).isNotNull(); + assertThat(validationErrors).hasSize(4); + assertThat(validationErrors).usingRecursiveFieldByFieldElementComparator().containsAll( + Lists.list( + new YamlDocumentValidationError(1, + "/pmMetaData/pmFields/measResultType", + "Value(s) is/are not in array of accepted values.\n" + + " value(s): integer\n" + + " accepted value(s): [float, uint32, uint64]"), + new YamlDocumentValidationError(1, + "/pmMetaData/pmFields/", + "Key not found: measChangeType"), + new YamlDocumentValidationError(2, + "/pmMetaData/pmFields/", + "Key not found: measChangeType"), + new YamlDocumentValidationError(3, + "/pmMetaData/pmFields/measAdditionalFields/vendorField1", + "Value(s) is/are not in array of accepted values.\n" + + " value(s): [Z, A]\n" + + " accepted value(s): [X, Y, Z]") + ) + ); + } + @Test + public void shouldThrowErrorWhenGivenPathToInvalidPmDictionaryFile() { + // given + String path = getFullPathForGivenResources(YamlLoadingUtils.PATH_TO_MULTI_DOCUMENT_INVALID_YAML); + // when then + assertThatThrownBy(() -> + new YamlFileValidator().validateYamlFileWithSchema(path) + ).isInstanceOf(ParserException.class) + .hasMessageContaining( + "expected the node content, but found '<document end>'" + ); + } + + @Test + public void shouldThrowErrorWhenGivenInvalidPath() { + // given + String path ="invalid/path/to/pm_dictionary"; + + // when then + assertThatThrownBy(() -> + new YamlFileValidator().validateYamlFileWithSchema(path) + ).isInstanceOf(YamlProcessingException.class) + .hasMessageContaining( + "PM_Dictionary YAML file is empty" + ); + } + + private String getFullPathForGivenResources(String pathToValidYaml) { + return this.getClass().getClassLoader().getResource( + pathToValidYaml + ).getPath(); + } +} diff --git a/csarvalidation/src/test/java/org/onap/validation/yaml/YamlLoaderTest.java b/csarvalidation/src/test/java/org/onap/validation/yaml/YamlLoaderTest.java new file mode 100644 index 0000000..4c68d60 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/validation/yaml/YamlLoaderTest.java @@ -0,0 +1,99 @@ +/* + * 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.junit.Test; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.model.YamlDocumentFactory; +import org.yaml.snakeyaml.parser.ParserException; +import org.yaml.snakeyaml.scanner.ScannerException; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + + +public class YamlLoaderTest { + + private static final int EXPECTED_NUMBER_OF_DOCUMENTS = 5; + private static final String LETTER_S_WITH_ASCII_CODE = "s(115)"; + + @Test + public void shouldLoadAllDocumentsFromYamlFile() throws YamlDocumentFactory.YamlDocumentParsingException { + // when + List<YamlDocument> documents = YamlLoadingUtils.loadValidMultiDocumentYamlFile(); + + // then + assertThat(documents).hasSize(EXPECTED_NUMBER_OF_DOCUMENTS); + } + + @Test + public void shouldLoadAllDocumentsFromJsonStyleYamlFile() throws YamlDocumentFactory.YamlDocumentParsingException { + // when + List<YamlDocument> documents = YamlLoadingUtils.loadValidJsonStyleMultiDocumentYamlFile(); + + // then + assertThat(documents).hasSize(EXPECTED_NUMBER_OF_DOCUMENTS); + } + + @Test + public void shouldLoadAllDocumentsFromYamlFileUsingPathInString() throws YamlProcessingException { + // when + List<YamlDocument> documents = YamlLoadingUtils.loadValidMultiDocumentYamlFileUsingStringPath(); + + // then + assertThat(documents).hasSize(EXPECTED_NUMBER_OF_DOCUMENTS); + } + + @Test + public void shouldThrowExceptionWhenLoadingDocumentsFromInvalidYamlFile() { + // when then + assertThatThrownBy(YamlLoadingUtils::tryToLoadMultiDocumentInvalidYamlFile + ).isInstanceOf(ParserException.class) + .hasMessageContaining("expected the node content, but found '<document end>'"); + } + + @Test + public void shouldThrowExceptionWhenLoadingDocumentsFromInvalidYamlFileUsingPathInString() { + // when then + assertThatThrownBy(YamlLoadingUtils::tryToLoadMultiDocumentInvalidYamlFileUsingStringPath + ).isInstanceOf(ParserException.class) + .hasMessageContaining("expected the node content, but found '<document end>'"); + } + + + @Test + public void shouldThrowExceptionWhenLoadingInvalidYamlFileWithIncorrectKeyMapping() { + // when then + assertThatThrownBy(YamlLoadingUtils::tryToLoadInvalidYamlFileWithIncorrectKeyMapping + ).isInstanceOf(ScannerException.class) + .hasMessageContaining("mapping values are not allowed here"); + } + + + @Test + public void shouldThrowExceptionWhenLoadingInvalidYamlFileWithUnknownEscapeCharacter() { + // when then + assertThatThrownBy(YamlLoadingUtils::tryToLoadInvalidYamlFileWithUnknownEscapeCharacter + ).isInstanceOf(ScannerException.class) + .hasMessageContaining("found unknown escape character " + LETTER_S_WITH_ASCII_CODE); + } + +} diff --git a/csarvalidation/src/test/java/org/onap/validation/yaml/YamlLoadingUtils.java b/csarvalidation/src/test/java/org/onap/validation/yaml/YamlLoadingUtils.java new file mode 100644 index 0000000..8d03910 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/validation/yaml/YamlLoadingUtils.java @@ -0,0 +1,94 @@ +/* + * 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 java.net.URL; +import java.util.List; + +import static org.onap.validation.yaml.model.YamlDocumentFactory.YamlDocumentParsingException; + +public final class YamlLoadingUtils { + + private YamlLoadingUtils() {} + + public static final int VALID_YAML_DOCUMENT_INDEX = 4; + public static final int YAML_DOCUMENT_WITH_WRONG_VALUE_IN_ARRAY_INDEX = 3; + public static final int YAML_DOCUMENT_WITH_MISSING_FIELD_INDEX = 2; + public static final int YAML_DOCUMENT_WITH_MISSING_FIELD_AND_WRONG_VALUE_INDEX = 1; + + static final String PATH_TO_VALID_YAML = "yaml_schema/PM_Dictionary.yaml"; + static final String PATH_TO_VALID_JSON_STYLE_YAML = "yaml_schema/PM_Dictionary_JSON_Style.yaml"; + private static final String PATH_TO_SIMPLE_VALID_SCHEMA = "yaml_schema/Simple_Valid_Schema.yaml"; + private static final String PATH_TO_SIMPLE_VALID_SCHEMA_MULTI_ROOT = "yaml_schema/Simple_Valid_Schema_Multi_Root.yaml"; + private static final String PATH_TO_SIMPLE_INVALID_SCHEMA = "yaml_schema/Simple_Invalid_Schema_Construction.yaml"; + private static final String PATH_TO_SIMPLE_INVALID_SCHEMA_FOR_LAZY_LOADING = "yaml_schema/Simple_Invalid_Schema_LazyLoading.yaml"; + static final String PATH_TO_MULTI_DOCUMENT_INVALID_YAML = "yaml_schema/Multi_Document_Invalid.yaml"; + private static final String PATH_TO_INVALID_YAML_WITH_INCORRECT_KEY_MAPPING = "yaml_schema/Simple_Invalid_Mapping_Value.yaml"; + private static final String PATH_TO_INVALID_YAML_WITH_UNKNOWN_ESCAPE_CHARACTER = "yaml_schema/Simple_Unknown_Escape_Character.yaml"; + + public static List<YamlDocument> loadValidMultiDocumentYamlFile() throws YamlDocumentParsingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_VALID_YAML)); + } + + public static List<YamlDocument> loadValidJsonStyleMultiDocumentYamlFile() throws YamlDocumentParsingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_VALID_JSON_STYLE_YAML)); + } + + public static List<YamlDocument> loadValidMultiDocumentYamlFileUsingStringPath() throws YamlProcessingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_VALID_YAML).getPath()); + } + + public static YamlDocument loadSimpleValidYamlSchemaFile() throws YamlDocumentParsingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_SIMPLE_VALID_SCHEMA)).get(0); + } + + public static YamlDocument loadSimpleInvalidYamlSchemaFile() throws YamlDocumentParsingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_SIMPLE_INVALID_SCHEMA)).get(0); + } + + public static YamlDocument loadSimpleInvalidYamlSchemaForLazyLoadingFile() throws YamlDocumentParsingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_SIMPLE_INVALID_SCHEMA_FOR_LAZY_LOADING)).get(0); + } + + public static YamlDocument loadSimpleValidYamlSchemaWithMultiRootFile() throws YamlDocumentParsingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_SIMPLE_VALID_SCHEMA_MULTI_ROOT)).get(0); + } + + public static List<YamlDocument> tryToLoadMultiDocumentInvalidYamlFile() throws YamlDocumentParsingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_MULTI_DOCUMENT_INVALID_YAML)); + } + + public static List<YamlDocument> tryToLoadMultiDocumentInvalidYamlFileUsingStringPath() throws YamlProcessingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_MULTI_DOCUMENT_INVALID_YAML).getPath()); + } + + public static List<YamlDocument> tryToLoadInvalidYamlFileWithIncorrectKeyMapping() throws YamlDocumentParsingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_INVALID_YAML_WITH_INCORRECT_KEY_MAPPING)); + } + + public static List<YamlDocument> tryToLoadInvalidYamlFileWithUnknownEscapeCharacter() throws YamlDocumentParsingException { + return new YamlLoader().loadMultiDocumentYamlFile(getUrlForGivenPath(PATH_TO_INVALID_YAML_WITH_UNKNOWN_ESCAPE_CHARACTER)); + } + + private static URL getUrlForGivenPath(String path) { + return YamlLoadingUtils.class.getClassLoader().getResource(path); + } +} diff --git a/csarvalidation/src/test/java/org/onap/validation/yaml/YamlValidatorTest.java b/csarvalidation/src/test/java/org/onap/validation/yaml/YamlValidatorTest.java new file mode 100644 index 0000000..efe9d69 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/validation/yaml/YamlValidatorTest.java @@ -0,0 +1,123 @@ +/* + * 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.assertj.core.util.Lists; +import org.junit.Test; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.error.SchemaValidationError; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.schema.YamlSchemaFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.onap.validation.yaml.YamlLoadingUtils.VALID_YAML_DOCUMENT_INDEX; +import static org.onap.validation.yaml.YamlLoadingUtils.YAML_DOCUMENT_WITH_MISSING_FIELD_INDEX; +import static org.onap.validation.yaml.YamlLoadingUtils.YAML_DOCUMENT_WITH_MISSING_FIELD_AND_WRONG_VALUE_INDEX; +import static org.onap.validation.yaml.YamlLoadingUtils.YAML_DOCUMENT_WITH_WRONG_VALUE_IN_ARRAY_INDEX; + +public class YamlValidatorTest { + + + @Test + public void shouldCreateValidatorUsingSchemaLoadedFromYamlFileAndValidatedJsonStyleDocumentsFromThatFile() + throws YamlProcessingException { + + // given + List<YamlDocument> documents = YamlLoadingUtils.loadValidJsonStyleMultiDocumentYamlFile(); + YamlValidator validator = new YamlValidator(new YamlSchemaFactory().createTreeStructuredYamlSchema(documents.get(0))); + Map<Integer,List<SchemaValidationError>> validationErrors = new HashMap<>(); + + // when + for (int documentIndex = 1 ; documentIndex < documents.size() ; documentIndex++) { + validationErrors.put(documentIndex, validator.validate(documents.get(documentIndex))); + } + + // then + assertValidatorReturnedCorrectErrors(validationErrors); + } + + @Test + public void shouldCreateValidatorUsingSchemaLoadedFromYamlFileAndValidatedDocumentsFromThatFile() + throws YamlProcessingException { + + // given + List<YamlDocument> documents = YamlLoadingUtils.loadValidMultiDocumentYamlFile(); + YamlValidator validator = new YamlValidator(new YamlSchemaFactory().createTreeStructuredYamlSchema(documents.get(0))); + Map<Integer,List<SchemaValidationError>> validationErrors = new HashMap<>(); + + // when + for (int documentIndex = 1 ; documentIndex < documents.size() ; documentIndex++) { + validationErrors.put(documentIndex, validator.validate(documents.get(documentIndex))); + } + + // then + assertValidatorReturnedCorrectErrors(validationErrors); + } + + private void assertValidatorReturnedCorrectErrors(Map<Integer, List<SchemaValidationError>> validationErrors) { + + SchemaValidationError expectedValidationValueError = + new SchemaValidationError( + "/pmMetaData/pmFields/measResultType", + "Value(s) is/are not in array of accepted values.\n" + + " value(s): integer\n" + + " accepted value(s): [float, uint32, uint64]" + ); + SchemaValidationError expectedValidationKeyError = + new SchemaValidationError( + "/pmMetaData/pmFields/", + "Key not found: measChangeType" + ); + SchemaValidationError expectedValidationValuesInArrayError = + new SchemaValidationError( + "/pmMetaData/pmFields/measAdditionalFields/vendorField1", + "Value(s) is/are not in array of accepted values.\n" + + " value(s): [Z, A]\n" + + " accepted value(s): [X, Y, Z]" + ); + + assertThat(validationErrors.size()).isEqualTo(4); + assertThat(validationErrors).containsKeys(1,2,3); + assertThat(validationErrors.get(YAML_DOCUMENT_WITH_MISSING_FIELD_AND_WRONG_VALUE_INDEX)).hasSize(2); + assertThat(validationErrors.get(YAML_DOCUMENT_WITH_MISSING_FIELD_AND_WRONG_VALUE_INDEX)) + .usingFieldByFieldElementComparator() + .containsAll( + Lists.list( + expectedValidationValueError, + expectedValidationKeyError + )); + assertThat(validationErrors.get(YAML_DOCUMENT_WITH_MISSING_FIELD_INDEX)).hasSize(1); + assertThat(validationErrors.get(YAML_DOCUMENT_WITH_MISSING_FIELD_INDEX)) + .usingFieldByFieldElementComparator() + .contains( + expectedValidationKeyError + ); + assertThat(validationErrors.get(YAML_DOCUMENT_WITH_WRONG_VALUE_IN_ARRAY_INDEX)).hasSize(1); + assertThat(validationErrors.get(YAML_DOCUMENT_WITH_WRONG_VALUE_IN_ARRAY_INDEX)) + .usingFieldByFieldElementComparator() + .contains( + expectedValidationValuesInArrayError + ); + assertThat(validationErrors.get(VALID_YAML_DOCUMENT_INDEX)).hasSize(0); + } + +} diff --git a/csarvalidation/src/test/java/org/onap/validation/yaml/model/YamlDocumentFactoryTest.java b/csarvalidation/src/test/java/org/onap/validation/yaml/model/YamlDocumentFactoryTest.java new file mode 100644 index 0000000..7879d4e --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/validation/yaml/model/YamlDocumentFactoryTest.java @@ -0,0 +1,154 @@ +/* + * 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.assertj.core.util.Lists; +import org.junit.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.onap.validation.yaml.model.YamlDocumentFactory.YamlDocumentParsingException; + +public class YamlDocumentFactoryTest { + + @Test + public void shouldTurnMapOfUnknownKeyTypeToMapWithStringKeysAndBeAbleToReturnStringifyValues() + throws YamlDocumentParsingException { + // given + Map<Object, Object> inputMap = new HashMap<>(); + List<String> testList = Lists.list("element1", "element11"); + Map<Object, Object> testEmptyMap = Collections.emptyMap(); + + inputMap.put("test", testList); + inputMap.put(345, "element2"); + inputMap.put("test2", "element3"); + inputMap.put(2.67, testEmptyMap); + + // when + YamlDocument document = new YamlDocumentFactory().createYamlDocument(inputMap); + + // then + assertThat(document).isNotNull(); + assertThat(document.getYaml()).containsKeys("test", "345", "test2", "2.67"); + + assertThat(document.getYaml()).containsEntry("test", testList); + assertThat(document.getValue("test")).isEqualTo("[element1, element11]"); + + assertThat(document.getValue("345")).isEqualTo("element2"); + assertThat(document.getValue("test2")).isEqualTo("element3"); + + assertThat(document.getYaml()).containsEntry("2.67", testEmptyMap); + assertThat(document.getValue("2.67")).isEqualTo("{}"); + } + + @Test + public void shouldTurnMapOfUnknownKeyTypeToMapWithStringKeysAndBeAbleToExtractSubStructure() + throws YamlDocumentParsingException { + // given + Map<Object, Object> inputMap = new HashMap<>(); + Map<Object, Object> subStructureMap = new HashMap<>(); + + inputMap.put("test", "element1"); + inputMap.put("structure", subStructureMap); + + subStructureMap.put("subTest1", "subElement1"); + subStructureMap.put("subTest2", "subElement2"); + + // when + YamlDocument document = new YamlDocumentFactory().createYamlDocument(inputMap); + + // then + assertThat(document).isNotNull(); + assertThat(document.getYaml()).containsKeys("test", "structure"); + assertThat(document.getValue("test")).isEqualTo("element1"); + + assertThat(document.getSubStructure("structure")).isNotNull(); + assertThat(document.getSubStructure("structure").getValue("subTest1")).isEqualTo("subElement1"); + assertThat(document.getSubStructure("structure").getValue("subTest2")).isEqualTo("subElement2"); + } + + @Test + public void shouldTurnMapOfUnknownKeyTypeToMapWithStringKeysAndBeAbleToExtractParametersList() + throws YamlDocumentParsingException { + // given + Map<Object, Object> inputMap = new HashMap<>(); + List<String> parametersList = new LinkedList<>(); + + inputMap.put("test", "element1"); + inputMap.put("parameters", parametersList); + + parametersList.add("parameter1"); + parametersList.add("parameter2"); + + // when + YamlDocument document = new YamlDocumentFactory().createYamlDocument(inputMap); + + // then + assertThat(document).isNotNull(); + assertThat(document.getYaml()).containsKeys("test", "parameters"); + assertThat(document.getValue("test")).isEqualTo("element1"); + + assertThat(document.getListOfValues("parameters")).isNotNull(); + assertThat(document.getListOfValues("parameters").getParameters()).contains("parameter1","parameter2"); + } + + @Test + public void shouldThrowExceptionIfGetSubStructureIsCalledOnList() + throws YamlDocumentParsingException { + // given + Map<Object, Object> inputMap = new HashMap<>(); + List<String> testList = Lists.list("element1", "element2"); + + inputMap.put("test", testList); + + YamlDocument document = new YamlDocumentFactory().createYamlDocument(inputMap); + + // when then + assertThatThrownBy(() -> + document.getSubStructure("test") + ).isInstanceOf(YamlDocumentParsingException.class) + .hasMessageContaining( + String.format("Fail to parse given objects: %s as yaml document", testList) + ); + } + + @Test + public void shouldThrowExceptionIfGetSubStructureIsCalledOnString() + throws YamlDocumentParsingException { + // given + Map<Object, Object> inputMap = new HashMap<>(); + + inputMap.put("test", "testElement"); + + YamlDocument document = new YamlDocumentFactory().createYamlDocument(inputMap); + + // when then + assertThatThrownBy(() -> + document.getSubStructure("test") + ).isInstanceOf(YamlDocumentParsingException.class) + .hasMessageContaining( + String.format("Fail to parse given objects: %s as yaml document.", "testElement") + ); + } +} diff --git a/csarvalidation/src/test/java/org/onap/validation/yaml/model/YamlParameterListFactoryTest.java b/csarvalidation/src/test/java/org/onap/validation/yaml/model/YamlParameterListFactoryTest.java new file mode 100644 index 0000000..34e61c5 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/validation/yaml/model/YamlParameterListFactoryTest.java @@ -0,0 +1,81 @@ +/* + * 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.assertj.core.util.Lists; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class YamlParameterListFactoryTest { + + @Test + public void shouldCreateEmptyParametersList() { + // when + YamlParametersList parametersList = new YamlParameterListFactory().createEmptyYamlParameterList(); + + // then + assertThat(parametersList).isNotNull(); + assertThat(parametersList.getParameters()).isEmpty(); + } + + @Test + public void shouldCreateParametersListContainingStringsFromListContainingSimpleTypes() { + // given + List<Object> testList = Lists.list("test1",3,23.45,'a',"test2"); + + // when + YamlParametersList parametersList = new YamlParameterListFactory().createYamlParameterList(testList); + + // then + assertThat(parametersList).isNotNull(); + assertThat(parametersList.getParameters()).hasSize(5); + assertThat(parametersList.getParameters()).contains("test1","test2","3","23.45","a"); + } + + @Test + public void shouldCreateParametersListContainingStringsFromListContainingVariousTypes() { + // given + List<Object> testList = Lists.list("test1",3,Lists.list(2,3,4),"test2"); + + // when + YamlParametersList parametersList = new YamlParameterListFactory().createYamlParameterList(testList); + + // then + assertThat(parametersList).isNotNull(); + assertThat(parametersList.getParameters()).hasSize(4); + assertThat(parametersList.getParameters()).contains("test1","test2","3","[2, 3, 4]"); + } + + @Test + public void shouldCreateListWithOneStringWhenGivenObjectIsNotList() { + // given + Object testObject = "test"; + + // when + YamlParametersList parametersList = new YamlParameterListFactory().createYamlParameterList(testObject); + + // then + assertThat(parametersList).isNotNull(); + assertThat(parametersList.getParameters()).hasSize(1); + assertThat(parametersList.getParameters()).contains("test"); + } + +} diff --git a/csarvalidation/src/test/java/org/onap/validation/yaml/process/YamlValidationProcessTest.java b/csarvalidation/src/test/java/org/onap/validation/yaml/process/YamlValidationProcessTest.java new file mode 100644 index 0000000..12fe9ec --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/validation/yaml/process/YamlValidationProcessTest.java @@ -0,0 +1,101 @@ +/* + * 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.junit.Test; +import org.onap.validation.yaml.YamlLoadingUtils; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.error.SchemaValidationError; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.schema.YamlSchema; +import org.onap.validation.yaml.schema.YamlSchemaFactory; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.onap.validation.yaml.YamlLoadingUtils.VALID_YAML_DOCUMENT_INDEX; +import static org.onap.validation.yaml.YamlLoadingUtils.YAML_DOCUMENT_WITH_MISSING_FIELD_INDEX; +import static org.onap.validation.yaml.YamlLoadingUtils.YAML_DOCUMENT_WITH_MISSING_FIELD_AND_WRONG_VALUE_INDEX; + + +public class YamlValidationProcessTest { + + @Test + public void shouldReturnNoErrorWhenProcessingValidPmDictionaryYaml() + throws YamlProcessingException { + // given + List<YamlDocument> documents = YamlLoadingUtils.loadValidMultiDocumentYamlFile(); + YamlSchema schema = new YamlSchemaFactory().createTreeStructuredYamlSchema(documents.get(0)); + YamlDocument document = documents.get(VALID_YAML_DOCUMENT_INDEX); + + // when + List<SchemaValidationError> errors = new YamlValidationProcess(schema,document).validate(); + + // then + assertThat(errors).isEmpty(); + } + + @Test + public void shouldReturnOneErrorWhenProcessingPmDictionaryYamlWithMissingField() + throws YamlProcessingException { + // given + List<YamlDocument> documents = YamlLoadingUtils.loadValidMultiDocumentYamlFile(); + YamlSchema schema = new YamlSchemaFactory().createTreeStructuredYamlSchema(documents.get(0)); + YamlDocument document = documents.get(YAML_DOCUMENT_WITH_MISSING_FIELD_INDEX); + + // when + List<SchemaValidationError> errors = new YamlValidationProcess(schema,document).validate(); + + // then + assertThat(errors).hasSize(1); + } + + @Test + public void shouldReturnTwoErrorsWhenProcessingPmDictionaryYamlWithMissingFieldAndIncorrectValue() + throws YamlProcessingException { + // given + List<YamlDocument> documents = YamlLoadingUtils.loadValidMultiDocumentYamlFile(); + YamlSchema schema = new YamlSchemaFactory().createTreeStructuredYamlSchema(documents.get(0)); + YamlDocument document = documents.get(YAML_DOCUMENT_WITH_MISSING_FIELD_AND_WRONG_VALUE_INDEX); + + // when + List<SchemaValidationError> errors = new YamlValidationProcess(schema,document).validate(); + + // then + assertThat(errors).hasSize(2); + } + + @Test + public void shouldThrowExceptionWhenProcessingPmDictionaryIsNotValidYaml() + throws YamlProcessingException { + // given + List<YamlDocument> documents = YamlLoadingUtils.loadValidMultiDocumentYamlFile(); + YamlDocument schemaInYaml = YamlLoadingUtils.loadSimpleInvalidYamlSchemaForLazyLoadingFile(); + YamlSchema schema = new YamlSchemaFactory().createTreeStructuredYamlSchema(schemaInYaml); + YamlDocument document = documents.get(VALID_YAML_DOCUMENT_INDEX); + + // when then + assertThatThrownBy(() -> + new YamlValidationProcess(schema,document).validate() + ).isInstanceOf(YamlProcessingException.class) + .hasMessageContaining( + String.format("Lazy loading failed, due to yaml parsing exception.") + ); + } +} diff --git a/csarvalidation/src/test/java/org/onap/validation/yaml/schema/YamlSchemaFactoryTest.java b/csarvalidation/src/test/java/org/onap/validation/yaml/schema/YamlSchemaFactoryTest.java new file mode 100644 index 0000000..4c05d71 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/validation/yaml/schema/YamlSchemaFactoryTest.java @@ -0,0 +1,122 @@ +/* + * 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.junit.Test; +import org.onap.validation.yaml.YamlLoadingUtils; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.schema.node.YamlSchemaNode; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.onap.validation.yaml.model.YamlDocumentFactory.YamlDocumentParsingException; +import static org.onap.validation.yaml.schema.node.YamlSchemaNodeFactory.EMPTY_COMMENT; +import static org.onap.validation.yaml.schema.node.YamlSchemaNodeFactoryTest.assertThatBranchNodeIsValid; +import static org.onap.validation.yaml.schema.node.YamlSchemaNodeFactoryTest.assertThatLeafNodeIsValid; + + +public class YamlSchemaFactoryTest { + + @Test + public void shouldCreateYamlSchemaFromYamlDocumentWithMultipleRoots() + throws YamlProcessingException { + + // given + YamlDocument documents = YamlLoadingUtils.loadSimpleValidYamlSchemaWithMultiRootFile(); + + // when + YamlSchema schema = new YamlSchemaFactory().createTreeStructuredYamlSchema(documents); + + // then + assertThat(schema).isNotNull(); + assertThat(schema.getRootNodes()).hasSize(3); + assertThat(schema.getRootNodes().get(0).getName()).isEqualTo("root1"); + assertThat(schema.getRootNodes().get(1).getName()).isEqualTo("root2"); + assertThat(schema.getRootNodes().get(2).getName()).isEqualTo("root3"); + } + + + @Test + public void shouldCreateYamlSchemaFromYamlDocument() + throws YamlProcessingException { + + // given + YamlDocument documents = YamlLoadingUtils.loadSimpleValidYamlSchemaFile(); + + // when + YamlSchema schema = new YamlSchemaFactory().createTreeStructuredYamlSchema(documents); + + // then + assertThat(schema).isNotNull(); + assertThat(schema.getRootNodes()).hasSize(1); + YamlSchemaNode pmMetaData = schema.getRootNodes().get(0); + assertThatBranchNodeIsValid(pmMetaData, "pmMetaData","/", true, EMPTY_COMMENT, + 2); + + YamlSchemaNode pmHeader = pmMetaData.getNextNodes().get(1); + assertThatBranchNodeIsValid(pmHeader, "pmHeader","/pmMetaData/", true, EMPTY_COMMENT, + 1); + + YamlSchemaNode nfType = pmHeader.getNextNodes().get(0); + assertThatLeafNodeIsValid(nfType, "nfType", "/pmMetaData/pmHeader/", true, "nfType comment"); + + YamlSchemaNode pmFields = pmMetaData.getNextNodes().get(0); + assertThatBranchNodeIsValid(pmFields, "pmFields", "/pmMetaData/", true, EMPTY_COMMENT, + 2); + + YamlSchemaNode measChangeType = pmFields.getNextNodes().get(1); + assertThatLeafNodeIsValid(measChangeType, "measChangeType", "/pmMetaData/pmFields/", + true, "measChangeType comment", + "added", "modified", "deleted"); + + YamlSchemaNode measAdditionalFields = pmFields.getNextNodes().get(0); + assertThatBranchNodeIsValid(measAdditionalFields, "measAdditionalFields", "/pmMetaData/pmFields/", + true, "measAdditionalFields comment", + 2); + + YamlSchemaNode vendorField1 = measAdditionalFields.getNextNodes().get(0); + assertThatLeafNodeIsValid(vendorField1, "vendorField1", "/pmMetaData/pmFields/measAdditionalFields/", + true, "vendorField1 comment", + "X", "Y", "Z"); + YamlSchemaNode vendorField2 = measAdditionalFields.getNextNodes().get(1); + assertThatLeafNodeIsValid(vendorField2, "vendorField2", "/pmMetaData/pmFields/measAdditionalFields/", + false, "vendorField2 comment", + "A", "B"); + } + + @Test + public void shouldThrowYamlParsingExceptionWhenLoadedSchemaIsInvalid() + throws YamlDocumentParsingException { + + // given + YamlDocument documents = YamlLoadingUtils.loadSimpleInvalidYamlSchemaFile(); + + // when/then + assertThatThrownBy(() -> + new YamlSchemaFactory().createTreeStructuredYamlSchema(documents) + ).isInstanceOf(YamlDocumentParsingException.class) + .hasMessageContaining( + String.format( + "Fail to parse given objects: %s as yaml document", + documents.getSubStructure("pmMetaData").getYaml().get("structure") + ) + ); + } + +} diff --git a/csarvalidation/src/test/java/org/onap/validation/yaml/schema/node/YamlSchemaNodeFactoryTest.java b/csarvalidation/src/test/java/org/onap/validation/yaml/schema/node/YamlSchemaNodeFactoryTest.java new file mode 100644 index 0000000..d35e3b2 --- /dev/null +++ b/csarvalidation/src/test/java/org/onap/validation/yaml/schema/node/YamlSchemaNodeFactoryTest.java @@ -0,0 +1,153 @@ +/* + * 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.assertj.core.util.Lists; +import org.junit.Test; +import org.onap.validation.yaml.YamlLoadingUtils; +import org.onap.validation.yaml.exception.YamlProcessingException; +import org.onap.validation.yaml.model.YamlDocument; +import org.onap.validation.yaml.model.YamlDocumentFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.onap.validation.yaml.schema.node.YamlSchemaNodeFactory.EMPTY_COMMENT; + +public class YamlSchemaNodeFactoryTest { + + private static final String ROOT_PATH = "/"; + + @Test + public void shouldThrowExceptionDuringLazyLoadingWhenLoadedSchemaHaveInvalidSubStructure() + throws YamlProcessingException { + // given + String nodeName = "pmMetaData"; + + YamlDocument document = YamlLoadingUtils.loadSimpleInvalidYamlSchemaForLazyLoadingFile(); + YamlSchemaNode node = new YamlSchemaNodeFactory() + .createNode(nodeName, ROOT_PATH, document.getSubStructure(nodeName)); + + // when/then + assertThatThrownBy(node::getNextNodes + ).isInstanceOf(YamlSchemaNode.YamlSchemaProcessingException.class) + .hasMessageContaining( + "Lazy loading failed, due to yaml parsing exception." + ); + } + + @Test + public void shouldCreateLeafNodeIfGivenYamlDocumentHaveNoSubStructure() + throws YamlProcessingException { + // given + String nodeName = "leaf_test"; + String comment = "test leaf node"; + List<String> acceptedValues = Lists.list("val1", "val2"); + Map<Object, Object> nodeInYamlFormat = new HashMap<>(); + nodeInYamlFormat.put(YamlSchemaNodeFactory.PRESENCE_KEY, YamlSchemaNodeFactory.PRESENCE_REQUIRED_KEY); + nodeInYamlFormat.put(YamlSchemaNodeFactory.COMMENT_KEY, comment); + nodeInYamlFormat.put(YamlSchemaNodeFactory.VALUE_KET, acceptedValues); + YamlDocument document = new YamlDocumentFactory().createYamlDocument( + nodeInYamlFormat + ); + + // when + YamlSchemaNode yamlSchemaNode = new YamlSchemaNodeFactory().createNode(nodeName, ROOT_PATH, document); + + // then + assertThatLeafNodeIsValid( + yamlSchemaNode, nodeName, ROOT_PATH, true, comment, + acceptedValues.toArray(new String[acceptedValues.size()]) + ); + } + + @Test + public void shouldCreateBranchNodeIfGivenYamlDocumentHaveSubStructure() + throws YamlProcessingException { + // given + String nodeName = "branch_test"; + String comment = "test branch node"; + + Map<Object, Object> subStructure = new HashMap<>(); + String subNode1Name = "branch_test_node1"; + String subNode2Name = "branch_test_node2"; + subStructure.put(subNode1Name, new HashMap<>()); + subStructure.put(subNode2Name, new HashMap<>()); + + Map<Object, Object> nodeInYamlFormat = new HashMap<>(); + nodeInYamlFormat.put(YamlSchemaNodeFactory.PRESENCE_KEY, YamlSchemaNodeFactory.PRESENCE_REQUIRED_KEY); + nodeInYamlFormat.put(YamlSchemaNodeFactory.COMMENT_KEY, comment); + nodeInYamlFormat.put(YamlSchemaNodeFactory.STRUCTURE_KEY, subStructure); + YamlDocument document = new YamlDocumentFactory().createYamlDocument( + nodeInYamlFormat + ); + + // when + YamlSchemaNode yamlSchemaNode = new YamlSchemaNodeFactory().createNode(nodeName, ROOT_PATH, document); + + // then + assertThatBranchNodeIsValid( + yamlSchemaNode, nodeName, ROOT_PATH, true, comment, 2); + + List<YamlSchemaNode> subNodes = yamlSchemaNode.getNextNodes(); + assertThat(subNodes).hasSize(2); + assertThatLeafNodeIsValid( + subNodes.get(1), subNode1Name, ROOT_PATH + nodeName + "/", false, EMPTY_COMMENT); + assertThatLeafNodeIsValid( + subNodes.get(0), subNode2Name, ROOT_PATH + nodeName + "/", false, EMPTY_COMMENT); + } + + public static void assertThatBranchNodeIsValid( + YamlSchemaNode yamlSchemaNode, String name, String path, boolean isRequired, String comment, + int numberOfSubNodes + ) throws YamlSchemaNode.YamlSchemaProcessingException { + assertThatNodeIsValid(yamlSchemaNode, name, path, isRequired, comment); + + assertThat(yamlSchemaNode.getClass()).isEqualTo(YamlSchemaBranchNode.class); + assertThat(yamlSchemaNode.isContainingSubStructure()).isTrue(); + assertThat(yamlSchemaNode.getNextNodes()).hasSize(numberOfSubNodes); + assertThat(yamlSchemaNode.getAcceptedValues()).isEmpty(); + } + + public static void assertThatLeafNodeIsValid( + YamlSchemaNode yamlSchemaNode, String name, String path, boolean isRequired, String comment, + String... acceptedValues + ) throws YamlSchemaNode.YamlSchemaProcessingException { + assertThatNodeIsValid(yamlSchemaNode, name, path, isRequired, comment); + + assertThat(yamlSchemaNode.getClass()).isEqualTo(YamlSchemaLeafNode.class); + assertThat(yamlSchemaNode.isContainingSubStructure()).isFalse(); + assertThat(yamlSchemaNode.getAcceptedValues()).containsExactly(acceptedValues); + assertThat(yamlSchemaNode.getNextNodes()).isEmpty(); + } + + private static void assertThatNodeIsValid(YamlSchemaNode yamlSchemaNode, String name, String path, boolean isRequired, String comment) { + assertThat(yamlSchemaNode).isNotNull(); + assertThat(yamlSchemaNode.getName()).isEqualTo(name); + assertThat(yamlSchemaNode.getPath()).isEqualTo(path); + if (comment.isEmpty()) { + assertThat(yamlSchemaNode.getComment()).isNotEmpty(); + } else { + assertThat(yamlSchemaNode.getComment()).isEqualTo(comment); + } + assertThat(yamlSchemaNode.isRequired()).isEqualTo(isRequired); + } +} diff --git a/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-missing-files.csar b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-missing-files.csar Binary files differnew file mode 100644 index 0000000..bab095d --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-missing-files.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-option1-invalid.csar b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-noFileInManifest.csar Binary files differindex 187c008..26e3971 100644 --- a/csarvalidation/src/test/resources/pnf/r130206/csar-option1-invalid.csar +++ b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-noFileInManifest.csar diff --git a/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-noVendor-noFileInManifest.csar b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-noVendor-noFileInManifest.csar Binary files differnew file mode 100644 index 0000000..b9136c8 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-noVendor-noFileInManifest.csar diff --git a/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-noVendor.csar b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-noVendor.csar Binary files differnew file mode 100644 index 0000000..11bddbb --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-invalid-noVendor.csar diff --git a/csarvalidation/src/test/resources/pnf/r01123/csar-option1-valid.csar b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-valid.csar Binary files differnew file mode 100644 index 0000000..62b18eb --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r01123/csar-option1-valid.csar diff --git a/csarvalidation/src/test/resources/pnf/r01123/csar-option2-invalid-with-cms.zip b/csarvalidation/src/test/resources/pnf/r01123/csar-option2-invalid-with-cms.zip Binary files differnew file mode 100644 index 0000000..8c30c68 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r01123/csar-option2-invalid-with-cms.zip diff --git a/csarvalidation/src/test/resources/pnf/r01123/csar-option2-valid-with-cms.zip b/csarvalidation/src/test/resources/pnf/r01123/csar-option2-valid-with-cms.zip Binary files differnew file mode 100644 index 0000000..6965b95 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r01123/csar-option2-valid-with-cms.zip diff --git a/csarvalidation/src/test/resources/pnf/r130206/cert-in-cms-and-root-and-tosca-incorrect-hash.csar b/csarvalidation/src/test/resources/pnf/r130206/cert-in-cms-and-root-and-tosca-incorrect-hash.csar Binary files differnew file mode 100644 index 0000000..bf19010 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/cert-in-cms-and-root-and-tosca-incorrect-hash.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root-and-tosca-incorrect-hash.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root-and-tosca-incorrect-hash.csar Binary files differnew file mode 100644 index 0000000..c8a4c39 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root-and-tosca-incorrect-hash.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root-and-tosca.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root-and-tosca.csar Binary files differnew file mode 100644 index 0000000..b47f565 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root-and-tosca.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root-incorrect-hash.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root-incorrect-hash.csar Binary files differnew file mode 100644 index 0000000..392d41e --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root-incorrect-hash.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root.csar Binary files differnew file mode 100644 index 0000000..f9112c7 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-root.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-tosca-incorrect-hash.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-tosca-incorrect-hash.csar Binary files differnew file mode 100644 index 0000000..f331233 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-tosca-incorrect-hash.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-tosca.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-tosca.csar Binary files differnew file mode 100644 index 0000000..0854291 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-and-tosca.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-incorrect-hash.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-incorrect-hash.csar Binary files differnew file mode 100644 index 0000000..12c90a2 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-incorrect-hash.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-valid.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-valid.csar Binary files differnew file mode 100644 index 0000000..ece4064 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms-valid.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms.csar Binary files differnew file mode 100644 index 0000000..5ddbe1a --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-cms.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-and-tosca-incorrect-hash.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-and-tosca-incorrect-hash.csar Binary files differnew file mode 100644 index 0000000..be19521 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-and-tosca-incorrect-hash.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-and-tosca.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-and-tosca.csar Binary files differnew file mode 100644 index 0000000..e4dbef9 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-and-tosca.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-incorrect-hash.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-incorrect-hash.csar Binary files differnew file mode 100644 index 0000000..b926aac --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-incorrect-hash.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-pointed-by-tosca.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-pointed-by-tosca.csar Binary files differnew file mode 100644 index 0000000..0d9c3f3 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root-pointed-by-tosca.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root.csar Binary files differnew file mode 100644 index 0000000..66c1a71 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-root.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca-incorrect-hash.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca-incorrect-hash.csar Binary files differnew file mode 100644 index 0000000..9b651d0 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca-incorrect-hash.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca-no-cms.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca-no-cms.csar Binary files differnew file mode 100644 index 0000000..fe34a61 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca-no-cms.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca-valid.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca-valid.csar Binary files differnew file mode 100644 index 0000000..3446aaf --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca-valid.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca.csar Binary files differnew file mode 100644 index 0000000..c4168dc --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-cert-in-tosca.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-no-cert-no-tosca-dir.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-no-cert-no-tosca-dir.csar Binary files differnew file mode 100644 index 0000000..0b00af1 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-no-cert-no-tosca-dir.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-no-cms-no-cert-with-hash.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-no-cms-no-cert-with-hash.csar Binary files differnew file mode 100644 index 0000000..826425e --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-no-cms-no-cert-with-hash.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-not-secure-warning.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-not-secure-warning.csar Binary files differnew file mode 100644 index 0000000..6520a61 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-not-secure-warning.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-option1-valid.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-option1-valid.csar Binary files differdeleted file mode 100644 index 08c3605..0000000 --- a/csarvalidation/src/test/resources/pnf/r130206/csar-option1-valid.csar +++ /dev/null diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-option1-validSection.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-option1-validSection.csar Binary files differdeleted file mode 100644 index bc90a75..0000000 --- a/csarvalidation/src/test/resources/pnf/r130206/csar-option1-validSection.csar +++ /dev/null diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-with-tosca-cert-pointing-non-existing-cert.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-with-tosca-cert-pointing-non-existing-cert.csar Binary files differnew file mode 100644 index 0000000..b392fac --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-with-tosca-cert-pointing-non-existing-cert.csar diff --git a/csarvalidation/src/test/resources/pnf/r130206/csar-with-tosca-no-cert-entry.csar b/csarvalidation/src/test/resources/pnf/r130206/csar-with-tosca-no-cert-entry.csar Binary files differnew file mode 100644 index 0000000..d5c27e1 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r130206/csar-with-tosca-no-cert-entry.csar diff --git a/csarvalidation/src/test/resources/pnf/r146092/validFile.csar b/csarvalidation/src/test/resources/pnf/r146092/validFile.csar Binary files differnew file mode 100644 index 0000000..e805765 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r146092/validFile.csar diff --git a/csarvalidation/src/test/resources/pnf/r816745/csar-with-empty-pm-dictionary.csar b/csarvalidation/src/test/resources/pnf/r816745/csar-with-empty-pm-dictionary.csar Binary files differnew file mode 100644 index 0000000..d0dbdf0 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r816745/csar-with-empty-pm-dictionary.csar diff --git a/csarvalidation/src/test/resources/pnf/r816745/csar-with-invalid-pm-dictionary-invalid-mapping.csar b/csarvalidation/src/test/resources/pnf/r816745/csar-with-invalid-pm-dictionary-invalid-mapping.csar Binary files differnew file mode 100644 index 0000000..b69b79a --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r816745/csar-with-invalid-pm-dictionary-invalid-mapping.csar diff --git a/csarvalidation/src/test/resources/pnf/r816745/csar-with-invalid-pm-dictionary-unknown-escape-character.csar b/csarvalidation/src/test/resources/pnf/r816745/csar-with-invalid-pm-dictionary-unknown-escape-character.csar Binary files differnew file mode 100644 index 0000000..9ed6270 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r816745/csar-with-invalid-pm-dictionary-unknown-escape-character.csar diff --git a/csarvalidation/src/test/resources/pnf/r816745/csar-with-invalid-pm-dictionary.csar b/csarvalidation/src/test/resources/pnf/r816745/csar-with-invalid-pm-dictionary.csar Binary files differnew file mode 100644 index 0000000..81a0e23 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r816745/csar-with-invalid-pm-dictionary.csar diff --git a/csarvalidation/src/test/resources/pnf/r816745/csar-with-missing-source-value-for-pm-dictionary-in-manifest.csar b/csarvalidation/src/test/resources/pnf/r816745/csar-with-missing-source-value-for-pm-dictionary-in-manifest.csar Binary files differnew file mode 100644 index 0000000..cd35d37 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r816745/csar-with-missing-source-value-for-pm-dictionary-in-manifest.csar diff --git a/csarvalidation/src/test/resources/pnf/r816745/csar-with-no-pm-dictionary.csar b/csarvalidation/src/test/resources/pnf/r816745/csar-with-no-pm-dictionary.csar Binary files differnew file mode 100644 index 0000000..f0d4216 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r816745/csar-with-no-pm-dictionary.csar diff --git a/csarvalidation/src/test/resources/pnf/r816745/csar-with-valid-pm-dictionary.csar b/csarvalidation/src/test/resources/pnf/r816745/csar-with-valid-pm-dictionary.csar Binary files differnew file mode 100644 index 0000000..528a002 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r816745/csar-with-valid-pm-dictionary.csar diff --git a/csarvalidation/src/test/resources/pnf/r816745/zip-with-invalid-pm-dictionary.zip b/csarvalidation/src/test/resources/pnf/r816745/zip-with-invalid-pm-dictionary.zip Binary files differnew file mode 100644 index 0000000..032dc78 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r816745/zip-with-invalid-pm-dictionary.zip diff --git a/csarvalidation/src/test/resources/pnf/r816745/zip-with-valid-pm-dictionary.zip b/csarvalidation/src/test/resources/pnf/r816745/zip-with-valid-pm-dictionary.zip Binary files differnew file mode 100644 index 0000000..b8c26d3 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r816745/zip-with-valid-pm-dictionary.zip diff --git a/csarvalidation/src/test/resources/pnf/r972082/fileExtensionOfArtifactIsNotYaml.csar b/csarvalidation/src/test/resources/pnf/r972082/fileExtensionOfArtifactIsNotYaml.csar Binary files differnew file mode 100644 index 0000000..f485172 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r972082/fileExtensionOfArtifactIsNotYaml.csar diff --git a/csarvalidation/src/test/resources/pnf/r972082/invalidYamlStructure.csar b/csarvalidation/src/test/resources/pnf/r972082/invalidYamlStructure.csar Binary files differnew file mode 100644 index 0000000..3360ce4 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r972082/invalidYamlStructure.csar diff --git a/csarvalidation/src/test/resources/pnf/r972082/missingOnapPnfSwInformationArtifactSetEntry.csar b/csarvalidation/src/test/resources/pnf/r972082/missingOnapPnfSwInformationArtifactSetEntry.csar Binary files differnew file mode 100644 index 0000000..518aaa8 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r972082/missingOnapPnfSwInformationArtifactSetEntry.csar diff --git a/csarvalidation/src/test/resources/pnf/r972082/missingSourceElementUnderAttributeError.csar b/csarvalidation/src/test/resources/pnf/r972082/missingSourceElementUnderAttributeError.csar Binary files differnew file mode 100644 index 0000000..e11093c --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/r972082/missingSourceElementUnderAttributeError.csar diff --git a/csarvalidation/src/test/resources/pnf/toscaMetaFile.csar b/csarvalidation/src/test/resources/pnf/toscaMetaFile.csar Binary files differnew file mode 100644 index 0000000..9370df9 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/toscaMetaFile.csar diff --git a/csarvalidation/src/test/resources/pnf/validFile.csar b/csarvalidation/src/test/resources/pnf/validFile.csar Binary files differnew file mode 100644 index 0000000..11d1945 --- /dev/null +++ b/csarvalidation/src/test/resources/pnf/validFile.csar diff --git a/csarvalidation/src/test/resources/yaml_schema/Multi_Document_Invalid.yaml b/csarvalidation/src/test/resources/yaml_schema/Multi_Document_Invalid.yaml new file mode 100644 index 0000000..aab34fa --- /dev/null +++ b/csarvalidation/src/test/resources/yaml_schema/Multi_Document_Invalid.yaml @@ -0,0 +1,86 @@ +... +# PM Dictionary perf3gpp measurements for the gnb-Nokia NF (bracket style yaml) +--- +pmMetaData: { + pmHeader: { + nfType: gnb-Nokia, + pmDefSchemaVsn: 2.0, + pmDefVsn: 5G19_1906_002 + }, + pmFields: { + iMeasInfoId: 2204, + iMeasType: 1, + + measCollectionMethod: CC, + measCondition: "This measurement is updated when X2AP: SgNB Modification Required message is sent to MeNB + with the SCG Change Indication set as PSCellChange.", + measDescription: "This counter indicates the number of intra gNB intra frequency PSCell change attempts.", + measFamily: NINFC, + measInfoId: "NR Intra Frequency PSCell Change", + measLastChange: 5G18A_1807_003, + measObjClass: NGCELL, + measResultRange: 0-4096, + measResultType: integer, + measResultUnits: number, + measType: VS.NINFC.IntraFrPscelChAttempt, + measAdditionalFields: { + vendorField1: X, + vendorField2: B + } + } +} +--- +pmMetaData: { + pmHeader: { + nfType: gnb-Nokia, + pmDefSchemaVsn: 2.0, + pmDefVsn: 5G19_1906_002 + }, + pmFields: { + iMeasInfoId: 2204, + iMeasType: 2, + measCollectionMethod: CC, + measCondition: "This measurement is updated when the TDCoverall timer has elapsed before gNB receives the X2AP: SgNB Modification Confirm message.", + measDescription: "This measurement the number of intra gNB intra frequency PSCell change failures due to TDCoverall timer expiry.", + measFamily: NINFC, + measInfoId: "NR Intra Frequency PSCell Change", + measLastChange: 5G18A_1807_003, + measObjClass: NGCELL, + measResultRange: 0-4096, + measResultType: float, + measResultUnits: number, + measType: VS.NINFC.IntraFrPscelChFailTdcExp, + measAdditionalFields: { + vendorField1: Y + } + } +} +... +--- +pmMetaData: { + pmHeader: { + nfType: gnb-Nokia, + pmDefSchemaVsn: 2.0, + pmDefVsn: 5G19_1906_002 + }, + pmFields: { + iMeasInfoId: 2206, + iMeasType: 1, + measCondition: "This measurement is updated when MeNB replies to X2AP: SgNB Modification Required message with the X2AP: SgNB Modification Refuse message.", + measCollectionMethod: CC, + measDescription: "This counter indicates the number of intra gNB intra frequency PSCell change failures due to MeNB refusal.", + measFamily: NINFC, + measInfoId: "NR Intra Frequency PSCell Change", + measLastChange: 5G19_1906_002, + measObjClass: NGCELL, + measResultRange: 0-4096, + measResultType: float, + measChangeType: added, + measResultUnits: number, + measType: VS.NINFC.IntraFrPscelChFailMenbRef, + measAdditionalFields: { + vendorField1: Z, + vendorField2: A + } + } +... diff --git a/csarvalidation/src/test/resources/yaml_schema/PM_Dictionary.yaml b/csarvalidation/src/test/resources/yaml_schema/PM_Dictionary.yaml new file mode 100644 index 0000000..12a4af9 --- /dev/null +++ b/csarvalidation/src/test/resources/yaml_schema/PM_Dictionary.yaml @@ -0,0 +1,228 @@ +--- +# PM Dictionary schema specifying and describing the meta information +# used to define perf3gpp measurements in the PM Dictionary +pmMetaData: { presence: required, structure: { + pmHeader: { + presence: required, + structure: { + nfType: { + presence: required, + comment: "NF type; should match the nfName-vendor string used in + the fileReady or perf3gpp eventName" + }, + pmDefSchemaVsn: { + presence: required, + value: 2.0, + comment: "PM Dictionary Schema Version from the VES Event + Registration specification" + }, + pmDefVsn: { + presence: required, + comment: "vendor-defined PM Dictionary version" + } + } + }, + pmFields: { + presence: required, + structure: { + iMeasInfoId: { + presence: required, + comment: "vendor-defined integer measurement group identifier" + }, + iMeasType: { + presence: required, + comment: "vendor-defined integer identifier for the measType; + must be combined with measInfoId to identify a + specific measurement." + }, + measChangeType: { + presence: required, + value: [added, modified, deleted], + comment: "indicates the type of change that occurred during + measLastChange" + }, + measCollectionMethod: { + presence: required, + value: [CC, SI, DER, Gauge, Average], + comment: "the measurement collection method; CC, SI, DER and + Gauge are as defined in 3GPP; average contains the + average value of the measurement during the + granularity period" + }, + measCondition: { + presence: required, + comment: "description of the condition causing the measurement" + }, + measDescription: { + presence: required, + comment: "description of the measurement information + and purpose" + }, + measFamily: { + presence: required, + comment: "abbreviation for a family of measurements, in + 3GPP format, or vendor defined" + }, + measInfoId: { + presence: required, + comment: "name for a group of related measurements in + 3GPP format or vendor defined" + }, + measLastChange: { + presence: required, + comment: "version of the PM Dictionary the last time this + measurement was added, modified or deleted" + }, + measObjClass: { + presence: required, + value: [NGBTS, NGCELL, IPNO, IPSEC, ETHIF], + comment: "measurement object class" + }, + measResultRange: { + presence: optional, + comment: "range of the measurement result; only necessary when + the range is smaller than the full range of the + data type" + }, + measResultType: { + presence: required, + value: [float, uint32, uint64], + comment: "data type of the measurement result" + }, + measResultUnits: { + presence: required, + value: [seconds, minutes, nanoseconds, microseconds, dB, + number, kilobytes, bytes, ethernetFrames, + packets, users], + comment: "units of measure for the measurement result" + }, + measType: { + presence: required, + comment: "measurement name in 3GPP or vendor-specific format; + vendor specific names are preceded with VS" + }, + measAdditionalFields: { + presence: required, + comment: "vendor-specific PM Dictionary fields", + structure: { + vendorField1: { + presence: required, + value: [X, Y, Z], + comment: "vendor field 1 description" + }, + vendorField2: { + presence: optional, + value: [A, B], + comment: "vendor field 2 description." + } + } + } + } + } +}} +... +# PM Dictionary perf3gpp measurements for the gnb-Nokia NF (bracket style yaml) +--- +pmMetaData: + pmHeader: + nfType: gnb-Nokia + pmDefSchemaVsn: 2.0 + pmDefVsn: 5G19_1906_002 + pmFields: + iMeasInfoId: 2204 + iMeasType: 1 + measCollectionMethod: CC + measCondition: "This measurement is updated when X2AP: SgNB Modification Required message is sent to MeNB + with the SCG Change Indication set as PSCellChange." + measDescription: "This counter indicates the number of intra gNB intra frequency PSCell change attempts." + measFamily: NINFC + measInfoId: "NR Intra Frequency PSCell Change" + measLastChange: 5G18A_1807_003 + measObjClass: NGCELL + measResultRange: 0-4096 + measResultType: integer + measResultUnits: number + measType: VS.NINFC.IntraFrPscelChAttempt + measAdditionalFields: + vendorField1: X + vendorField2: B +... +--- +pmMetaData: + pmHeader: + nfType: gnb-Nokia + pmDefSchemaVsn: 2.0 + pmDefVsn: 5G19_1906_002 + pmFields: + iMeasInfoId: 2204 + iMeasType: 2 + measCollectionMethod: CC + measCondition: "This measurement is updated when the TDCoverall timer has elapsed before gNB receives the X2AP: SgNB Modification Confirm message." + measDescription: "This measurement the number of intra gNB intra frequency PSCell change failures due to TDCoverall timer expiry." + measFamily: NINFC + measInfoId: "NR Intra Frequency PSCell Change" + measLastChange: 5G18A_1807_003 + measObjClass: NGCELL + measResultRange: 0-4096 + measResultType: float + measResultUnits: number + measType: VS.NINFC.IntraFrPscelChFailTdcExp + measAdditionalFields: + vendorField1: + - Y + - X +... +--- +pmMetaData: + pmHeader: + nfType: gnb-Nokia + pmDefSchemaVsn: 2.0 + pmDefVsn: 5G19_1906_002 + pmFields: + iMeasInfoId: 2206 + iMeasType: 1 + measCondition: "This measurement is updated when MeNB replies to X2AP: SgNB Modification Required message with the X2AP: SgNB Modification Refuse message." + measCollectionMethod: CC + measDescription: "This counter indicates the number of intra gNB intra frequency PSCell change failures due to MeNB refusal." + measFamily: NINFC + measInfoId: "NR Intra Frequency PSCell Change" + measLastChange: 5G19_1906_002 + measObjClass: NGCELL + measResultRange: 0-4096 + measResultType: float + measChangeType: added + measResultUnits: number + measType: VS.NINFC.IntraFrPscelChFailMenbRef + measAdditionalFields: + vendorField1: + - Z + - A + vendorField2: A +... +--- +pmMetaData: + pmHeader: + nfType: gnb-Nokia + pmDefSchemaVsn: 2.0 + pmDefVsn: 5G19_1906_002 + pmFields: + iMeasInfoId: 2206 + iMeasType: 1 + measCondition: "This measurement is updated when MeNB replies to X2AP: SgNB Modification Required message with the X2AP: SgNB Modification Refuse message." + measCollectionMethod: CC + measDescription: "This counter indicates the number of intra gNB intra frequency PSCell change failures due to MeNB refusal." + measFamily: NINFC + measInfoId: "NR Intra Frequency PSCell Change" + measLastChange: 5G19_1906_002 + measObjClass: NGCELL + measResultRange: 0-4096 + measResultType: float + measChangeType: added + measResultUnits: number + measType: VS.NINFC.IntraFrPscelChFailMenbRef + measAdditionalFields: + vendorField1: + - X + - Y + vendorField2: A +... diff --git a/csarvalidation/src/test/resources/yaml_schema/PM_Dictionary_JSON_Style.yaml b/csarvalidation/src/test/resources/yaml_schema/PM_Dictionary_JSON_Style.yaml new file mode 100644 index 0000000..f4cbddf --- /dev/null +++ b/csarvalidation/src/test/resources/yaml_schema/PM_Dictionary_JSON_Style.yaml @@ -0,0 +1,239 @@ +--- +# PM Dictionary schema specifying and describing the meta information +# used to define perf3gpp measurements in the PM Dictionary +pmMetaData: { presence: required, structure: { + pmHeader: { + presence: required, + structure: { + nfType: { + presence: required, + comment: "NF type; should match the nfName-vendor string used in + the fileReady or perf3gpp eventName" + }, + pmDefSchemaVsn: { + presence: required, + value: 2.0, + comment: "PM Dictionary Schema Version from the VES Event + Registration specification" + }, + pmDefVsn: { + presence: required, + comment: "vendor-defined PM Dictionary version" + } + } + }, + pmFields: { + presence: required, + structure: { + iMeasInfoId: { + presence: required, + comment: "vendor-defined integer measurement group identifier" + }, + iMeasType: { + presence: required, + comment: "vendor-defined integer identifier for the measType; + must be combined with measInfoId to identify a + specific measurement." + }, + measChangeType: { + presence: required, + value: [added, modified, deleted], + comment: "indicates the type of change that occurred during + measLastChange" + }, + measCollectionMethod: { + presence: required, + value: [CC, SI, DER, Gauge, Average], + comment: "the measurement collection method; CC, SI, DER and + Gauge are as defined in 3GPP; average contains the + average value of the measurement during the + granularity period" + }, + measCondition: { + presence: required, + comment: "description of the condition causing the measurement" + }, + measDescription: { + presence: required, + comment: "description of the measurement information + and purpose" + }, + measFamily: { + presence: required, + comment: "abbreviation for a family of measurements, in + 3GPP format, or vendor defined" + }, + measInfoId: { + presence: required, + comment: "name for a group of related measurements in + 3GPP format or vendor defined" + }, + measLastChange: { + presence: required, + comment: "version of the PM Dictionary the last time this + measurement was added, modified or deleted" + }, + measObjClass: { + presence: required, + value: [NGBTS, NGCELL, IPNO, IPSEC, ETHIF], + comment: "measurement object class" + }, + measResultRange: { + presence: optional, + comment: "range of the measurement result; only necessary when + the range is smaller than the full range of the + data type" + }, + measResultType: { + presence: required, + value: [float, uint32, uint64], + comment: "data type of the measurement result" + }, + measResultUnits: { + presence: required, + value: [seconds, minutes, nanoseconds, microseconds, dB, + number, kilobytes, bytes, ethernetFrames, + packets, users], + comment: "units of measure for the measurement result" + }, + measType: { + presence: required, + comment: "measurement name in 3GPP or vendor-specific format; + vendor specific names are preceded with VS" + }, + measAdditionalFields: { + presence: required, + comment: "vendor-specific PM Dictionary fields", + structure: { + vendorField1: { + presence: required, + value: [X, Y, Z], + comment: "vendor field 1 description" + }, + vendorField2: { + presence: optional, + value: [A, B], + comment: "vendor field 2 description." + } + } + } + } + } +}} +... +# PM Dictionary perf3gpp measurements for the gnb-Nokia NF (bracket style yaml) +--- +pmMetaData: { + pmHeader: { + nfType: gnb-Nokia, + pmDefSchemaVsn: 2.0, + pmDefVsn: 5G19_1906_002 + }, + pmFields: { + iMeasInfoId: 2204, + iMeasType: 1, + + measCollectionMethod: CC, + measCondition: "This measurement is updated when X2AP: SgNB Modification Required message is sent to MeNB + with the SCG Change Indication set as PSCellChange.", + measDescription: "This counter indicates the number of intra gNB intra frequency PSCell change attempts.", + measFamily: NINFC, + measInfoId: "NR Intra Frequency PSCell Change", + measLastChange: 5G18A_1807_003, + measObjClass: NGCELL, + measResultRange: 0-4096, + measResultType: integer, + measResultUnits: number, + measType: VS.NINFC.IntraFrPscelChAttempt, + measAdditionalFields: { + vendorField1: X, + vendorField2: B + } + } +} +... +--- +pmMetaData: { + pmHeader: { + nfType: gnb-Nokia, + pmDefSchemaVsn: 2.0, + pmDefVsn: 5G19_1906_002 + }, + pmFields: { + iMeasInfoId: 2204, + iMeasType: 2, + measCollectionMethod: CC, + measCondition: "This measurement is updated when the TDCoverall timer has elapsed before gNB receives the X2AP: SgNB Modification Confirm message.", + measDescription: "This measurement the number of intra gNB intra frequency PSCell change failures due to TDCoverall timer expiry.", + measFamily: NINFC, + measInfoId: "NR Intra Frequency PSCell Change", + measLastChange: 5G18A_1807_003, + measObjClass: NGCELL, + measResultRange: 0-4096, + measResultType: float, + measResultUnits: number, + measType: VS.NINFC.IntraFrPscelChFailTdcExp, + measAdditionalFields: { + vendorField1: [Y,Z] + } + } +} +... +--- +pmMetaData: { + pmHeader: { + nfType: gnb-Nokia, + pmDefSchemaVsn: 2.0, + pmDefVsn: 5G19_1906_002 + }, + pmFields: { + iMeasInfoId: 2206, + iMeasType: 1, + measCondition: "This measurement is updated when MeNB replies to X2AP: SgNB Modification Required message with the X2AP: SgNB Modification Refuse message.", + measCollectionMethod: CC, + measDescription: "This counter indicates the number of intra gNB intra frequency PSCell change failures due to MeNB refusal.", + measFamily: NINFC, + measInfoId: "NR Intra Frequency PSCell Change", + measLastChange: 5G19_1906_002, + measObjClass: NGCELL, + measResultRange: 0-4096, + measResultType: float, + measChangeType: added, + measResultUnits: number, + measType: VS.NINFC.IntraFrPscelChFailMenbRef, + measAdditionalFields: { + vendorField1: [Z,A], + vendorField2: A + } + } +} +... +--- +pmMetaData: { + pmHeader: { + nfType: gnb-Nokia, + pmDefSchemaVsn: 2.0, + pmDefVsn: 5G19_1906_002 + }, + pmFields: { + iMeasInfoId: 2206, + iMeasType: 1, + measCondition: "This measurement is updated when MeNB replies to X2AP: SgNB Modification Required message with the X2AP: SgNB Modification Refuse message.", + measCollectionMethod: CC, + measDescription: "This counter indicates the number of intra gNB intra frequency PSCell change failures due to MeNB refusal.", + measFamily: NINFC, + measInfoId: "NR Intra Frequency PSCell Change", + measLastChange: 5G19_1906_002, + measObjClass: NGCELL, + measResultRange: 0-4096, + measResultType: float, + measChangeType: added, + measResultUnits: number, + measType: VS.NINFC.IntraFrPscelChFailMenbRef, + measAdditionalFields: { + vendorField1: [X,Y], + vendorField2: A + } + } +} +... diff --git a/csarvalidation/src/test/resources/yaml_schema/Simple_Invalid_Mapping_Value.yaml b/csarvalidation/src/test/resources/yaml_schema/Simple_Invalid_Mapping_Value.yaml new file mode 100644 index 0000000..25c72cd --- /dev/null +++ b/csarvalidation/src/test/resources/yaml_schema/Simple_Invalid_Mapping_Value.yaml @@ -0,0 +1,149 @@ +--- +# PM Dictionary schema specifying and describing the meta information +# used to define perf3gpp measurements in the PM Dictionary +pmMetaData: { presence: required, structure: { + pmHeader: { + presence: required, + structure: { + nfType: { + presence: required, + comment: "NF type; should match the nfName-vendor string used in + the fileReady or perf3gpp eventName" + }, + pmDefSchemaVsn: { + presence: required, + value: 2.0, + comment: "PM Dictionary Schema Version from the VES Event + Registration specification" + }, + pmDefVsn: { + presence: required, + comment: "vendor-defined PM Dictionary version" + } + } + }, + pmFields: { + presence: required, + structure: { + iMeasInfoId: { + presence: required, + comment: "vendor-defined integer measurement group identifier" + }, + iMeasType: { + presence: required, + comment: "vendor-defined integer identifier for the measType; + must be combined with measInfoId to identify a + specific measurement." + }, + measChangeType: { + presence: required, + value: [added, modified, deleted], + comment: "indicates the type of change that occurred during + measLastChange" + }, + measCollectionMethod: { + presence: required, + value: [CC, SI, DER, Gauge, Average], + comment: "the measurement collection method; CC, SI, DER and + Gauge are as defined in 3GPP; average contains the + average value of the measurement during the + granularity period" + }, + measCondition: { + presence: required, + comment: "description of the condition causing the measurement" + }, + measDescription: { + presence: required, + comment: "description of the measurement information + and purpose" + }, + measFamily: { + presence: required, + comment: "abbreviation for a family of measurements, in + 3GPP format, or vendor defined" + }, + measInfoId: { + presence: required, + comment: "name for a group of related measurements in + 3GPP format or vendor defined" + }, + measLastChange: { + presence: required, + comment: "version of the PM Dictionary the last time this + measurement was added, modified or deleted" + }, + measObjClass: { + presence: required, + value: [NGBTS, NGCELL, IPNO, IPSEC, ETHIF], + comment: "measurement object class" + }, + measResultRange: { + presence: optional, + comment: "range of the measurement result; only necessary when + the range is smaller than the full range of the + data type" + }, + measResultType: { + presence: required, + value: [float, uint32, uint64], + comment: "data type of the measurement result" + }, + measResultUnits: { + presence: required, + value: [seconds, minutes, nanoseconds, microseconds, dB, + number, kilobytes, bytes, ethernetFrames, + packets, users], + comment: "units of measure for the measurement result" + }, + measType: { + presence: required, + comment: "measurement name in 3GPP or vendor-specific format; + vendor specific names are preceded with VS" + }, + measAdditionalFields: { + presence: required, + comment: "vendor-specific PM Dictionary fields", + structure: { + vendorField1: { + presence: required, + value: [X, Y, Z], + comment: "vendor field 1 description" + }, + vendorField2: { + presence: optional, + value: [A, B], + comment: "vendor field 2 description." + } + } + } + } + } +}} +... +# PM Dictionary perf3gpp measurements for the gnb-Nokia NF (bracket style yaml) +--- +pmMetaData: + pmHeader: + nfType: gnb-Nokia + pmDefSchemaVsn: 2.0 + pmDefVsn: 5G19_1906_002 + pmFields: + iMeasInfoId: 2204 + iMeasType: 1 + measCollectionMethod: CC + measCondition: This measurement is updated when X2AP: SgNB Modification Required message is sent to MeNB + with the SCG Change Indication set as PSCellChange. + measDescription: This counter indicates the number of intra gNB intra frequency PSCell change attempts. + measFamily: NINFC + measInfoId: "NR Intra Frequency PSCell Change" + measLastChange: 5G18A_1807_003 + measObjClass: NGCELL + measResultRange: 0-4096 + measResultType: integer + measResultUnits: number + measType: VS.NINFC.IntraFrPscelChAttempt + measAdditionalFields: + vendorField1: X + vendorField2: B +... diff --git a/csarvalidation/src/test/resources/yaml_schema/Simple_Invalid_Schema_Construction.yaml b/csarvalidation/src/test/resources/yaml_schema/Simple_Invalid_Schema_Construction.yaml new file mode 100644 index 0000000..c5e7b7c --- /dev/null +++ b/csarvalidation/src/test/resources/yaml_schema/Simple_Invalid_Schema_Construction.yaml @@ -0,0 +1,39 @@ +--- +pmMetaData: { presence: required, structure: [ + -pmHeader: { + presence: required, + structure: { + nfType: { + presence: required, + comment: "nfType comment" + } + } + }, + -pmFields: { + presence: required, + structure: { + measChangeType: { + presence: required, + value: [added, modified, deleted], + comment: "measChangeType comment" + }, + measAdditionalFields: { + presence: required, + comment: "measAdditionalFields comment", + structure: { + vendorField1: { + presence: required, + value: [X, Y, Z], + comment: "vendorField1 comment" + }, + vendorField2: { + presence: optional, + value: [A, B], + comment: "vendorField2 comment" + } + } + } + } + } +]} +... diff --git a/csarvalidation/src/test/resources/yaml_schema/Simple_Invalid_Schema_LazyLoading.yaml b/csarvalidation/src/test/resources/yaml_schema/Simple_Invalid_Schema_LazyLoading.yaml new file mode 100644 index 0000000..7f9f946 --- /dev/null +++ b/csarvalidation/src/test/resources/yaml_schema/Simple_Invalid_Schema_LazyLoading.yaml @@ -0,0 +1,39 @@ +--- +pmMetaData: { presence: required, structure: { + pmHeader: { + presence: required, + structure: { + nfType: { + presence: required, + comment: "nfType comment" + } + } + }, + pmFields: { + presence: required, + structure: [ + -measChangeType: { + presence: required, + value: [added, modified, deleted], + comment: "measChangeType comment" + }, + -measAdditionalFields: { + presence: required, + comment: "measAdditionalFields comment", + structure: { + vendorField1: { + presence: required, + value: [X, Y, Z], + comment: "vendorField1 comment" + }, + vendorField2: { + presence: optional, + value: [A, B], + comment: "vendorField2 comment" + } + } + } + ] + } +}} +... diff --git a/csarvalidation/src/test/resources/yaml_schema/Simple_Unknown_Escape_Character.yaml b/csarvalidation/src/test/resources/yaml_schema/Simple_Unknown_Escape_Character.yaml new file mode 100644 index 0000000..2cac9e6 --- /dev/null +++ b/csarvalidation/src/test/resources/yaml_schema/Simple_Unknown_Escape_Character.yaml @@ -0,0 +1,149 @@ +--- +# PM Dictionary schema specifying and describing the meta information +# used to define perf3gpp measurements in the PM Dictionary +pmMetaData: { presence: required, structure: { + pmHeader: { + presence: required, + structure: { + nfType: { + presence: required, + comment: "NF type; should match the nfName-vendor string used in + the fileReady or perf3gpp eventName" + }, + pmDefSchemaVsn: { + presence: required, + value: 2.0, + comment: "PM Dictionary Schema Version from the VES Event + Registration specification" + }, + pmDefVsn: { + presence: required, + comment: "vendor-defined PM Dictionary version" + } + } + }, + pmFields: { + presence: required, + structure: { + iMeasInfoId: { + presence: required, + comment: "vendor-defined integer measurement group identifier" + }, + iMeasType: { + presence: required, + comment: "vendor-defined integer identifier for the measType; + must be combined with measInfoId to identify a + specific measurement." + }, + measChangeType: { + presence: required, + value: [added, modified, deleted], + comment: "indicates the type of change that occurred during + measLastChange" + }, + measCollectionMethod: { + presence: required, + value: [CC, SI, DER, Gauge, Average], + comment: "the measurement collection method; CC, SI, DER and + Gauge are as defined in 3GPP; average contains the + average value of the measurement during the + granularity period" + }, + measCondition: { + presence: required, + comment: "description of the condition causing the measurement" + }, + measDescription: { + presence: required, + comment: "description of the measurement information + and purpose" + }, + measFamily: { + presence: required, + comment: "abbreviation for a family of measurements, in + 3GPP format, or vendor defined" + }, + measInfoId: { + presence: required, + comment: "name for a group of related measurements in + 3GPP format or vendor defined" + }, + measLastChange: { + presence: required, + comment: "version of the PM Dictionary the last time this + measurement was added, modified or deleted" + }, + measObjClass: { + presence: required, + value: [NGBTS, NGCELL, IPNO, IPSEC, ETHIF], + comment: "measurement object class" + }, + measResultRange: { + presence: optional, + comment: "range of the measurement result; only necessary when + the range is smaller than the full range of the + data type" + }, + measResultType: { + presence: required, + value: [float, uint32, uint64], + comment: "data type of the measurement result" + }, + measResultUnits: { + presence: required, + value: [seconds, minutes, nanoseconds, microseconds, dB, + number, kilobytes, bytes, ethernetFrames, + packets, users], + comment: "units of measure for the measurement result" + }, + measType: { + presence: required, + comment: "measurement name in 3GPP or vendor-specific format; + vendor specific names are preceded with VS" + }, + measAdditionalFields: { + presence: required, + comment: "vendor-specific PM Dictionary fields", + structure: { + vendorField1: { + presence: required, + value: [X, Y, Z], + comment: "vendor field 1 description" + }, + vendorField2: { + presence: optional, + value: [A, B], + comment: "vendor field 2 description." + } + } + } + } + } +}} +... +# PM Dictionary perf3gpp measurements for the gnb-Nokia NF (bracket style yaml) +--- +pmMetaData: + pmHeader: + nfType: gnb-Nokia + pmDefSchemaVsn: 2.0 + pmDefVsn: 5G19_1906_002 + pmFields: + iMeasInfoId: 2204 + iMeasType: 1 + measCollectionMethod: CC + measCondition: "This measurement is updated when X2AP: SgNB Modification Required message is \sent\ to MeNB + with the SCG Change Indication set as PSCellChange." + measDescription: This counter indicates the number of intra gNB intra frequency PSCell change attempts. + measFamily: NINFC + measInfoId: "NR Intra Frequency PSCell Change" + measLastChange: 5G18A_1807_003 + measObjClass: NGCELL + measResultRange: 0-4096 + measResultType: integer + measResultUnits: number + measType: VS.NINFC.IntraFrPscelChAttempt + measAdditionalFields: + vendorField1: X + vendorField2: B +... diff --git a/csarvalidation/src/test/resources/yaml_schema/Simple_Valid_Schema.yaml b/csarvalidation/src/test/resources/yaml_schema/Simple_Valid_Schema.yaml new file mode 100644 index 0000000..a125b13 --- /dev/null +++ b/csarvalidation/src/test/resources/yaml_schema/Simple_Valid_Schema.yaml @@ -0,0 +1,39 @@ +--- +pmMetaData: { presence: required, structure: { + pmHeader: { + presence: required, + structure: { + nfType: { + presence: required, + comment: "nfType comment" + } + } + }, + pmFields: { + presence: required, + structure: { + measChangeType: { + presence: required, + value: [added, modified, deleted], + comment: "measChangeType comment" + }, + measAdditionalFields: { + presence: required, + comment: "measAdditionalFields comment", + structure: { + vendorField1: { + presence: required, + value: [X, Y, Z], + comment: "vendorField1 comment" + }, + vendorField2: { + presence: optional, + value: [A, B], + comment: "vendorField2 comment" + } + } + } + } + } +}} +... diff --git a/csarvalidation/src/test/resources/yaml_schema/Simple_Valid_Schema_Multi_Root.yaml b/csarvalidation/src/test/resources/yaml_schema/Simple_Valid_Schema_Multi_Root.yaml new file mode 100644 index 0000000..d73ca4f --- /dev/null +++ b/csarvalidation/src/test/resources/yaml_schema/Simple_Valid_Schema_Multi_Root.yaml @@ -0,0 +1,23 @@ +--- +root1: { presence: required, structure: { + field1: { + presence: required, + value: [X, Y, Z], + comment: "field 1 description" + } +}} +root2: { presence: required, structure: { + field2: { + presence: required, + value: [X, Y, Z], + comment: "field 1 description" + } +}} +root3: { presence: required, structure: { + field3: { + presence: required, + value: [X, Y, Z], + comment: "field 1 description" + } +}} +... diff --git a/deployment/pom.xml b/deployment/pom.xml index d4b11db..fb720d2 100644 --- a/deployment/pom.xml +++ b/deployment/pom.xml @@ -16,11 +16,15 @@ --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> + <properties> + <groovy-maven-plugin.version>2.0</groovy-maven-plugin.version> + <gmaven-plugin.version>1.5</gmaven-plugin.version> + </properties> <parent> <groupId>org.onap.vnfsdk.validation</groupId> <artifactId>validation</artifactId> - <version>1.2.4-SNAPSHOT</version> + <version>1.2.15-SNAPSHOT</version> </parent> <artifactId>csarvalidation-deployment</artifactId> @@ -33,7 +37,7 @@ <plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>groovy-maven-plugin</artifactId> - <version>2.0</version> + <version>${groovy-maven-plugin.version}</version> </plugin> </plugins> </pluginManagement> @@ -41,7 +45,7 @@ <plugin> <groupId>org.codehaus.gmaven</groupId> <artifactId>gmaven-plugin</artifactId> - <version>1.5</version> + <version>${gmaven-plugin.version}</version> <executions> <execution> <id>CSAR validator</id> @@ -10,11 +10,12 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.onap.vnfsdk.validation</groupId> <artifactId>validation</artifactId> - <version>1.2.4-SNAPSHOT</version> + <version>1.2.15-SNAPSHOT</version> <name>vnfsdk-validation</name> <packaging>pom</packaging> <properties> + <java.version>11</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <sonar.language>java</sonar.language> <sonar.surefire.reportsPath>${project.build.directory}/surefire-reports</sonar.surefire.reportsPath> @@ -22,8 +23,10 @@ <sonar.jacoco.reportMissing.force.zero>true</sonar.jacoco.reportMissing.force.zero> <sonar.projectVersion>${project.version}</sonar.projectVersion> <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis> + <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version> + <maven-jar-plugin.version>3.0.2</maven-jar-plugin.version> </properties> - + <scm> <tag>HEAD</tag> </scm> @@ -40,7 +43,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> - <version>3.0.2</version> + <version>${maven-jar-plugin.version}</version> <configuration> <archive> <manifest> @@ -56,10 +59,10 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> - <version>3.1</version> + <version>${maven-compiler-plugin.version}</version> <configuration> - <source>1.8</source> - <target>1.8</target> + <source>${java.version}</source> + <target>${java.version}</target> </configuration> </plugin> <plugin> diff --git a/releases/1.2.10-maven.yaml b/releases/1.2.10-maven.yaml new file mode 100644 index 0000000..a515add --- /dev/null +++ b/releases/1.2.10-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.10' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/394' diff --git a/releases/1.2.11-maven.yaml b/releases/1.2.11-maven.yaml new file mode 100644 index 0000000..f0e7073 --- /dev/null +++ b/releases/1.2.11-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.11' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/425' diff --git a/releases/1.2.12-maven.yaml b/releases/1.2.12-maven.yaml new file mode 100644 index 0000000..44dcb3a --- /dev/null +++ b/releases/1.2.12-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.12' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/446' diff --git a/releases/1.2.13-maven.yaml b/releases/1.2.13-maven.yaml new file mode 100644 index 0000000..405d742 --- /dev/null +++ b/releases/1.2.13-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.13' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/461' diff --git a/releases/1.2.14-maven.yaml b/releases/1.2.14-maven.yaml new file mode 100644 index 0000000..9ccef59 --- /dev/null +++ b/releases/1.2.14-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.14' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/490' diff --git a/releases/1.2.5-maven.yaml b/releases/1.2.5-maven.yaml new file mode 100644 index 0000000..1ce8c35 --- /dev/null +++ b/releases/1.2.5-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.5' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/327' diff --git a/releases/1.2.6-maven.yaml b/releases/1.2.6-maven.yaml new file mode 100644 index 0000000..55e3c6a --- /dev/null +++ b/releases/1.2.6-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.6' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/330' diff --git a/releases/1.2.7-maven.yaml b/releases/1.2.7-maven.yaml new file mode 100644 index 0000000..9fc362a --- /dev/null +++ b/releases/1.2.7-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.7' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/373'
\ No newline at end of file diff --git a/releases/1.2.8-maven.yaml b/releases/1.2.8-maven.yaml new file mode 100644 index 0000000..7ba12e7 --- /dev/null +++ b/releases/1.2.8-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.8' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/375' diff --git a/releases/1.2.9-maven.yaml b/releases/1.2.9-maven.yaml new file mode 100644 index 0000000..109148f --- /dev/null +++ b/releases/1.2.9-maven.yaml @@ -0,0 +1,5 @@ +--- +distribution_type: maven +version: '1.2.9' +project: 'vnfsdk-validation' +log_dir: 'vnfsdk-validation-maven-stage-master/388' diff --git a/version.properties b/version.properties index 79ab23a..c34e299 100644 --- a/version.properties +++ b/version.properties @@ -5,7 +5,7 @@ major=1 minor=2 -patch=4 +patch=15 base_version=${major}.${minor}.${patch} |