2 * Copyright © 2016-2018 European Support Limited
3 * Modification Copyright (C) 2021 Nokia.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 package org.openecomp.sdc.tosca.csar;
20 import static org.junit.jupiter.api.Assertions.assertAll;
21 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22 import static org.junit.jupiter.api.Assertions.assertEquals;
23 import static org.junit.jupiter.api.Assertions.assertFalse;
24 import static org.junit.jupiter.api.Assertions.assertSame;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
27 import com.google.common.collect.ImmutableMap;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.lang.reflect.Field;
32 import java.lang.reflect.InvocationTargetException;
33 import java.lang.reflect.Method;
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.HashMap;
37 import java.util.List;
39 import java.util.Map.Entry;
40 import java.util.Optional;
42 import org.junit.jupiter.api.BeforeEach;
43 import org.junit.jupiter.api.Test;
44 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
45 import org.openecomp.sdc.common.errors.Messages;
48 class SOL004ManifestOnboardingTest {
50 private Manifest manifest;
54 manifest = new SOL004ManifestOnboarding();
58 public void testSuccessfulParsing() throws IOException {
59 try (final InputStream manifestAsStream =
60 getClass().getResourceAsStream("/vspmanager.csar/manifest/ValidTosca.mf")) {
61 manifest.parse(manifestAsStream);
62 assertValidManifest(4, 5, Collections.emptyMap(), ResourceTypeEnum.VF, false);
67 public void testNoMetadataParsing() throws IOException {
68 try (final InputStream manifestAsStream = getClass()
69 .getResourceAsStream("/vspmanager.csar/manifest/invalid/no-metadata.mf")) {
70 manifest.parse(manifestAsStream);
71 final List<String> expectedErrorList = new ArrayList<>();
72 expectedErrorList.add(
73 buildErrorMessage(3, "Source: MainServiceTemplate.yaml", Messages.MANIFEST_START_METADATA)
75 assertInvalidManifest(expectedErrorList);
80 public void testBrokenMDParsing() throws IOException {
81 try (final InputStream manifestAsStream =
82 getClass().getResourceAsStream("/vspmanager.csar/manifest/InvalidTosca2.mf")) {
83 manifest.parse(manifestAsStream);
84 final List<String> expectedErrorList = new ArrayList<>();
85 expectedErrorList.add(Messages.MANIFEST_INVALID_LINE.formatMessage(9, "vnf_package_version: 1.0"));
86 assertInvalidManifest(expectedErrorList);
91 public void testNoMetaParsing() throws IOException {
92 try (final InputStream manifestAsStream = getClass()
93 .getResourceAsStream("/vspmanager.csar/manifest/invalid/empty-metadata-with-source.mf")) {
94 manifest.parse(manifestAsStream);
95 final List<String> expectedErrorList = new ArrayList<>();
96 expectedErrorList.add(
97 buildErrorMessage(4, "Source: MainServiceTemplate.yaml",
98 Messages.MANIFEST_METADATA_INVALID_ENTRY1, "Source: MainServiceTemplate.yaml")
100 assertInvalidManifest(expectedErrorList);
105 public void testSuccessfulNonManoParsing() throws IOException {
106 try (final InputStream manifestAsStream = getClass()
107 .getResourceAsStream("/vspmanager.csar/manifest/ValidNonManoTosca.mf")) {
108 manifest.parse(manifestAsStream);
109 assertValidManifest(4, 5,
110 ImmutableMap.of("foo_bar", 3, "prv.happy-nfv.cool", 3), ResourceTypeEnum.VF, false);
115 public void testInvalidNonManoParsing() throws IOException {
116 try (final InputStream manifestAsStream = getClass()
117 .getResourceAsStream("/vspmanager.csar/manifest/InValidNonManoTosca.mf")) {
118 manifest.parse(manifestAsStream);
119 final List<String> errorList = Collections.singletonList(
120 buildErrorMessage(34, "vnf_product_name: Mock", Messages.MANIFEST_INVALID_NON_MANO_KEY,
123 assertInvalidManifest(errorList);
127 private String buildErrorMessage(final int lineNumber, final String line, final Messages message,
128 final Object... params) {
129 return Messages.MANIFEST_ERROR_WITH_LINE.formatMessage(message.formatMessage(params), lineNumber, line);
133 public void testNonManoParsingWithGarbage() throws IOException {
134 try (final InputStream manifestAsStream = getClass()
135 .getResourceAsStream("/vspmanager.csar/manifest/InvalidToscaNonManoGarbageAtEnd.mf")) {
136 manifest.parse(manifestAsStream);
137 final List<String> errorList = Collections.singletonList(
138 Messages.MANIFEST_ERROR_WITH_LINE.formatMessage(
139 Messages.MANIFEST_INVALID_NON_MANO_KEY.formatMessage("some garbage"),
142 assertInvalidManifest(errorList);
147 public void testInvalidManifestFile() throws IOException {
148 try (final InputStream manifestAsStream = getClass()
149 .getResourceAsStream("/vspmanager.csar/manifest/SOME_WRONG_FILE")) {
150 manifest.parse(manifestAsStream);
151 assertInvalidManifest(Collections.singletonList(Messages.MANIFEST_PARSER_INTERNAL.getErrorMessage()));
156 public void testManifestSigned() throws IOException {
157 try (final InputStream manifestAsStream = getClass()
158 .getResourceAsStream("/vspmanager.csar/manifest/valid/signed.mf")) {
159 manifest.parse(manifestAsStream);
160 assertValidManifest(4, 3, Collections.emptyMap(), ResourceTypeEnum.VF, true);
165 public void testManifestSignedWithNonManoArtifacts() throws IOException {
166 try (final InputStream manifestAsStream = getClass()
167 .getResourceAsStream("/vspmanager.csar/manifest/valid/signed-with-non-mano.mf")) {
168 manifest.parse(manifestAsStream);
169 assertValidManifest(4, 3, ImmutableMap.of("foo_bar", 3), ResourceTypeEnum.VF, true);
170 manifest.getType().ifPresent(typeEnum -> assertSame(typeEnum, ResourceTypeEnum.VF));
175 public void testManifestWithPnf() throws IOException {
176 try (final InputStream manifestAsStream = getClass()
177 .getResourceAsStream("/vspmanager.csar/manifest/valid/metadata-pnfd.mf")) {
178 manifest.parse(manifestAsStream);
179 assertValidManifest(4, 3, new HashMap<>(), ResourceTypeEnum.PNF, true);
184 public void testMetadataWithNoValue() throws IOException {
185 try (final InputStream manifestAsStream = getClass()
186 .getResourceAsStream("/vspmanager.csar/manifest/invalid/metadata-no-value.mf")) {
187 manifest.parse(manifestAsStream);
189 final List<String> expectedErrorList = new ArrayList<>();
190 expectedErrorList.add(
191 buildErrorMessage(3, "vnf_provider_id", Messages.MANIFEST_METADATA_INVALID_ENTRY1, "vnf_provider_id")
193 assertInvalidManifest(expectedErrorList);
198 public void testMetadataWithValueButNoEntry() throws IOException {
199 try (final InputStream manifestAsStream = getClass()
200 .getResourceAsStream("/vspmanager.csar/manifest/invalid/metadata-no-entry.mf")) {
201 manifest.parse(manifestAsStream);
203 final List<String> expectedErrorList = new ArrayList<>();
204 expectedErrorList.add(
205 buildErrorMessage(3, ": no-entry-value", Messages.MANIFEST_METADATA_INVALID_ENTRY1, ": no-entry-value")
207 assertInvalidManifest(expectedErrorList);
212 public void testMetadataWithIncorrectEntry() throws IOException {
213 try (final InputStream manifestAsStream = getClass()
214 .getResourceAsStream("/vspmanager.csar/manifest/invalid/metadata-incorrect-entry.mf")) {
215 manifest.parse(manifestAsStream);
216 final List<String> expectedErrorList = new ArrayList<>();
217 expectedErrorList.add(
218 buildErrorMessage(4, "vnf_release_data_time: 2019-08-29T22:17:39.275281",
219 Messages.MANIFEST_METADATA_INVALID_ENTRY1, "vnf_release_data_time: 2019-08-29T22:17:39.275281")
221 assertInvalidManifest(expectedErrorList);
226 public void testMetadataWithMixedEntries() throws IOException {
227 try (final InputStream manifestAsStream = getClass()
228 .getResourceAsStream("/vspmanager.csar/manifest/invalid/metadata-mixed-entries.mf")) {
229 manifest.parse(manifestAsStream);
230 final List<String> expectedErrorList = new ArrayList<>();
231 expectedErrorList.add(buildErrorMessage(6, "", Messages.MANIFEST_METADATA_UNEXPECTED_ENTRY_TYPE));
232 assertInvalidManifest(expectedErrorList);
237 public void testMetadataWithDuplicatedEntries() throws IOException {
238 try (final InputStream manifestAsStream =
239 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/metadata-duplicated-entries.mf")) {
240 manifest.parse(manifestAsStream);
241 final List<String> expectedErrorList = new ArrayList<>();
242 expectedErrorList.add(
243 buildErrorMessage(4, "vnf_product_name: vPP", Messages.MANIFEST_METADATA_DUPLICATED_ENTRY,
246 assertInvalidManifest(expectedErrorList);
251 public void testManifestNonManoKeyWithoutSources() throws IOException {
252 try (final InputStream manifestAsStream =
253 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/non-mano-key-with-no-sources.mf")) {
254 manifest.parse(manifestAsStream);
255 final List<String> expectedErrorList = new ArrayList<>();
256 expectedErrorList.add(
257 buildErrorMessage(11, "", Messages.MANIFEST_EMPTY_NON_MANO_KEY,
260 assertInvalidManifest(expectedErrorList);
265 public void testManifestNonManoKeyWithEmptySourceEntry() throws IOException {
266 try (final InputStream manifestAsStream =
267 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/non-mano-key-with-empty-source.mf")) {
268 manifest.parse(manifestAsStream);
269 final List<String> expectedErrorList = new ArrayList<>();
270 expectedErrorList.add(
271 buildErrorMessage(11, "Source:", Messages.MANIFEST_EMPTY_NON_MANO_SOURCE)
273 assertInvalidManifest(expectedErrorList);
278 public void testManifestWithEmptyMetadata() throws IOException {
279 try (final InputStream manifestAsStream =
280 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/empty-metadata.mf")) {
281 manifest.parse(manifestAsStream);
282 final List<String> expectedErrorList = new ArrayList<>();
283 expectedErrorList.add(buildErrorMessage(2, "", Messages.MANIFEST_NO_METADATA));
284 assertInvalidManifest(expectedErrorList);
289 public void testManifestSourceAlgorithmWithoutHash() throws IOException {
290 try (final InputStream manifestAsStream =
291 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/source-algorithm-without-hash.mf")) {
292 manifest.parse(manifestAsStream);
293 final List<String> expectedErrorList = new ArrayList<>();
294 expectedErrorList.add(buildErrorMessage(9, "", Messages.MANIFEST_EXPECTED_HASH_ENTRY));
295 assertInvalidManifest(expectedErrorList);
300 public void testManifestSourceHashWithoutAlgorithm() throws IOException {
301 try (final InputStream manifestAsStream =
302 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/source-hash-without-algorithm.mf")) {
303 manifest.parse(manifestAsStream);
304 final List<String> expectedErrorList = new ArrayList<>();
305 expectedErrorList.add(buildErrorMessage(8, "Hash: 3b119b37da5b76ec7c933168b21cedd8", Messages.MANIFEST_EXPECTED_ALGORITHM_BEFORE_HASH));
306 assertInvalidManifest(expectedErrorList);
311 public void testManifestSourceAlgorithmWithoutValue() throws IOException {
312 try (final InputStream manifestAsStream =
313 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/source-algorithm-without-value.mf")) {
314 manifest.parse(manifestAsStream);
315 final List<String> expectedErrorList = new ArrayList<>();
316 expectedErrorList.add(buildErrorMessage(8, "Algorithm:", Messages.MANIFEST_EXPECTED_ALGORITHM_VALUE));
317 assertInvalidManifest(expectedErrorList);
322 public void testManifestSourceHashWithoutValue() throws IOException {
323 try (final InputStream manifestAsStream =
324 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/source-hash-without-value.mf")) {
325 manifest.parse(manifestAsStream);
326 final List<String> expectedErrorList = new ArrayList<>();
327 expectedErrorList.add(buildErrorMessage(9, "Hash:", Messages.MANIFEST_EXPECTED_HASH_VALUE));
328 assertInvalidManifest(expectedErrorList);
333 public void testEmptyManifest() throws IOException {
334 try (final InputStream manifestAsStream =
335 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/empty-manifest.mf")) {
336 manifest.parse(manifestAsStream);
337 final List<String> expectedErrorList = new ArrayList<>();
338 expectedErrorList.add(Messages.MANIFEST_EMPTY.getErrorMessage());
339 assertInvalidManifest(expectedErrorList);
344 public void testManifestWithDuplicatedCmsSignature()
345 throws IOException, NoSuchFieldException, IllegalAccessException {
346 try (final InputStream manifestAsStream =
347 getClass().getResourceAsStream("/vspmanager.csar/manifest/valid/signed.mf")) {
348 //forcing an existing signature
349 final Field cmsSignatureField = AbstractOnboardingManifest.class.getDeclaredField("cmsSignature");
350 cmsSignatureField.setAccessible(true);
351 cmsSignatureField.set(manifest, "any value");
352 manifest.parse(manifestAsStream);
354 final List<String> expectedErrorList = new ArrayList<>();
356 .add(buildErrorMessage(18, "-----BEGIN CMS-----", Messages.MANIFEST_SIGNATURE_DUPLICATED));
357 assertInvalidManifest(expectedErrorList);
362 public void testGetEntry() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
363 final Method getEntryMethod = AbstractOnboardingManifest.class.getDeclaredMethod("readEntryName", String.class);
364 getEntryMethod.setAccessible(true);
365 final Optional<String> noEntry = (Optional<String>) getEntryMethod.invoke(manifest, ":");
366 assertFalse(noEntry.isPresent(), "Entry should not be present");
368 final Optional<String> blankEntry = (Optional<String>) getEntryMethod.invoke(manifest, " :");
369 assertFalse(blankEntry.isPresent(), "Entry should not be present");
371 final Optional<String> noColon = (Optional<String>) getEntryMethod.invoke(manifest, "anyKeyWithoutColon ");
372 assertFalse(noColon.isPresent(), "Entry should not be present");
374 final Optional<String> blank = (Optional<String>) getEntryMethod.invoke(manifest, " ");
375 assertFalse(blank.isPresent(), "Entry should not be present");
377 final Optional<String> empty = (Optional<String>) getEntryMethod.invoke(manifest, "");
378 assertFalse(empty.isPresent(), "Entry should not be present");
380 final Optional<String> nul1 = (Optional<String>) getEntryMethod.invoke(manifest, new Object[]{null});
381 assertFalse(nul1.isPresent(), "Entry should not be present");
383 final Optional<String> entry = (Optional<String>) getEntryMethod
384 .invoke(manifest, " entry to test : : a value ::: test test: ");
385 assertTrue(entry.isPresent(), "Entry should be present");
386 assertEquals("entry to test", entry.get(), "Entry should be as expected");
390 public void testGetValue() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
391 final Method getValueMethod = AbstractOnboardingManifest.class.getDeclaredMethod("readEntryValue", String.class);
392 getValueMethod.setAccessible(true);
393 final Optional<String> noValue = (Optional<String>) getValueMethod.invoke(manifest, ":");
394 assertFalse(noValue.isPresent(), "Value should not be present");
396 final Optional<String> blankValue = (Optional<String>) getValueMethod.invoke(manifest, ": ");
397 assertFalse(blankValue.isPresent(), "Value should not be present");
399 final Optional<String> noColon = (Optional<String>) getValueMethod.invoke(manifest, "anyKeyWithoutColon ");
400 assertFalse(noColon.isPresent(), "Value should not be present");
402 final Optional<String> blank = (Optional<String>) getValueMethod.invoke(manifest, " ");
403 assertFalse(blank.isPresent(), "Value should not be present");
405 final Optional<String> empty = (Optional<String>) getValueMethod.invoke(manifest, "");
406 assertFalse(empty.isPresent(), "Value should not be present");
408 final Optional<String> nul1 = (Optional<String>) getValueMethod.invoke(manifest, new Object[]{null});
409 assertFalse(nul1.isPresent(), "Value should not be present");
411 final Optional<String> value = (Optional<String>) getValueMethod
412 .invoke(manifest, "attribute : : a value ::: test test: ");
413 assertTrue(value.isPresent(), "Value should be present");
414 assertEquals(": a value ::: test test:", value.get(), "Value should be as expected");
418 public void testSuccessfulSignedManifestWithIndividualSignature() throws IOException {
419 try (final InputStream manifestAsStream =
420 getClass().getResourceAsStream("/vspmanager.csar/manifest/valid/individualSignature/signedWithIndividualSignature.mf")) {
421 manifest.parse(manifestAsStream);
422 assertValidManifest(4, 3, Collections.emptyMap(), ResourceTypeEnum.VF, true);
427 public void testSuccessfulUnsignedManifestWithIndividualSignaturee() throws IOException {
428 try (final InputStream manifestAsStream =
429 getClass().getResourceAsStream("/vspmanager.csar/manifest/valid/individualSignature/unsignedWithIndividualSignature.mf")) {
430 manifest.parse(manifestAsStream);
431 assertValidManifest(4, 3, Collections.emptyMap(), ResourceTypeEnum.VF, false);
436 public void testSuccessfulSignedManifestWithIndividualSignatureAndHash() throws IOException {
437 try (final InputStream manifestAsStream =
438 getClass().getResourceAsStream("/vspmanager.csar/manifest/valid/individualSignature/signedWithIndividualSignatureAndHash.mf")) {
439 manifest.parse(manifestAsStream);
440 assertValidManifest(4, 3, Collections.emptyMap(), ResourceTypeEnum.VF, true);
445 public void testSuccessfulSignedManifestWithIndividualSignatureAndCommonCert() throws IOException {
446 try (final InputStream manifestAsStream =
447 getClass().getResourceAsStream("/vspmanager.csar/manifest/valid/individualSignature/signedWithIndividualSignatureCommonCert.mf")) {
448 manifest.parse(manifestAsStream);
449 assertValidManifest(4, 3, Collections.emptyMap(), ResourceTypeEnum.VF, true);
454 public void testEmptyIndividualSignature() throws IOException {
455 try (final InputStream manifestAsStream =
456 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/individualSignature/signedWithEmptyIndividualSignature.mf")) {
457 manifest.parse(manifestAsStream);
458 final List<String> expectedErrorList = List.of(
460 8, "Signature:", Messages.MANIFEST_EXPECTED_SIGNATURE_VALUE
462 assertInvalidManifest(expectedErrorList);
467 public void testEmptyIndividualCertificate() throws IOException {
468 try (final InputStream manifestAsStream =
469 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/individualSignature/signedWithEmptyIndividualCertificate.mf")) {
470 manifest.parse(manifestAsStream);
471 final List<String> expectedErrorList = List.of(
473 9, "Certificate:", Messages.MANIFEST_EXPECTED_CERTIFICATE_VALUE
475 assertInvalidManifest(expectedErrorList);
480 public void testOnlyIndividualCertificateNoSignature() throws IOException {
481 try (final InputStream manifestAsStream =
482 getClass().getResourceAsStream("/vspmanager.csar/manifest/invalid/individualSignature/signedWithIndividualCertificateNoSignature.mf")) {
483 manifest.parse(manifestAsStream);
484 final List<String> expectedErrorList = List.of(
486 8, "Certificate: TOSCA-Metadata/TOSCA.cert", Messages.MANIFEST_EXPECTED_SIGNATURE_BEFORE_CERTIFICATE
488 assertInvalidManifest(expectedErrorList);
492 private void assertValidManifest(final int expectedMetadataSize, final int expectedSourcesSize,
493 final Map<String, Integer> expectedNonManoKeySize,
494 final ResourceTypeEnum resourceType, final boolean isSigned) {
496 "manifest should be valid",
497 () -> assertTrue(manifest.getErrors().isEmpty(), "Should have no errors"),
498 () -> assertTrue(manifest.isValid(), "Should be valid"),
499 () -> assertTrue(manifest.getType().isPresent(), "Should have a type"),
500 () -> assertEquals(resourceType, manifest.getType().get(), "Type should be as expected"),
501 () -> assertEquals(isSigned, manifest.isSigned(), "Signature status should be as expected")
504 "manifest should have expected fields",
505 () -> assertEquals(expectedMetadataSize, manifest.getMetadata().keySet().size(),
506 "Metadata should have the expected size"),
507 () -> assertEquals(expectedSourcesSize, manifest.getSources().size(),
508 "Sources should have the expected size"),
509 () -> assertEquals(expectedNonManoKeySize.keySet().size(), manifest.getNonManoSources().keySet().size(),
510 "Non Mano Sources keys should have the expected size")
512 for (final Entry<String, Integer> nonManoKeyAndSize : expectedNonManoKeySize.entrySet()) {
513 final String nonManoKey = nonManoKeyAndSize.getKey();
516 () -> assertTrue(manifest.getNonManoSources().containsKey(nonManoKey),
517 "Should contain expected Non Mano Sources key"),
518 () -> assertEquals(nonManoKeyAndSize.getValue(),manifest.getNonManoSources().get(nonManoKey).size(),
519 String.format("Non Mano Sources keys %s should have the expected sources size", nonManoKey))
524 private void assertInvalidManifest(final List<String> expectedErrorList) {
526 "manifest should be invalid and should contain expected errors",
527 () -> assertFalse(manifest.isValid(), "Should be invalid"),
528 () -> assertArrayEquals(manifest.getErrors().toArray(), expectedErrorList.toArray(), "Should have expected errors")