288995dfed71a190f2fc017866682ba57d82dc5d
[sdc.git] /
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  * Modification Copyright (C) 2021 Nokia.
4  *
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 package org.openecomp.sdc.tosca.csar;
19
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;
26
27 import com.google.common.collect.ImmutableMap;
28
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;
38 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.Optional;
41
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;
46
47
48 class SOL004ManifestOnboardingTest {
49
50     private Manifest manifest;
51
52     @BeforeEach
53     public void setUp() {
54         manifest = new SOL004ManifestOnboarding();
55     }
56
57     @Test
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);
63         }
64     }
65
66     @Test
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)
74             );
75             assertInvalidManifest(expectedErrorList);
76         }
77     }
78
79     @Test
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);
87         }
88     }
89
90     @Test
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")
99             );
100             assertInvalidManifest(expectedErrorList);
101         }
102     }
103
104     @Test
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);
111         }
112     }
113
114     @Test
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,
121                     "vnf_product_name")
122             );
123             assertInvalidManifest(errorList);
124         }
125     }
126
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);
130     }
131
132     @Test
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"),
140                     34, "some garbage")
141             );
142             assertInvalidManifest(errorList);
143         }
144     }
145
146     @Test
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()));
152         }
153     }
154
155     @Test
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);
161         }
162     }
163
164     @Test
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));
171         }
172     }
173
174     @Test
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);
180         }
181     }
182
183     @Test
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);
188
189             final List<String> expectedErrorList = new ArrayList<>();
190             expectedErrorList.add(
191                 buildErrorMessage(3, "vnf_provider_id", Messages.MANIFEST_METADATA_INVALID_ENTRY1, "vnf_provider_id")
192             );
193             assertInvalidManifest(expectedErrorList);
194         }
195     }
196
197     @Test
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);
202
203             final List<String> expectedErrorList = new ArrayList<>();
204             expectedErrorList.add(
205                 buildErrorMessage(3, ": no-entry-value", Messages.MANIFEST_METADATA_INVALID_ENTRY1, ": no-entry-value")
206             );
207             assertInvalidManifest(expectedErrorList);
208         }
209     }
210
211     @Test
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")
220             );
221             assertInvalidManifest(expectedErrorList);
222         }
223     }
224
225     @Test
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);
233         }
234     }
235
236     @Test
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,
244                     "vnf_product_name")
245             );
246             assertInvalidManifest(expectedErrorList);
247         }
248     }
249
250     @Test
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,
258                     "foo_bar")
259             );
260             assertInvalidManifest(expectedErrorList);
261         }
262     }
263
264     @Test
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)
272             );
273             assertInvalidManifest(expectedErrorList);
274         }
275     }
276
277     @Test
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);
285         }
286     }
287
288     @Test
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);
296         }
297     }
298
299     @Test
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);
307         }
308     }
309
310     @Test
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);
318         }
319     }
320
321     @Test
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);
329         }
330     }
331
332     @Test
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);
340         }
341     }
342
343     @Test
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);
353
354             final List<String> expectedErrorList = new ArrayList<>();
355             expectedErrorList
356                 .add(buildErrorMessage(18, "-----BEGIN CMS-----", Messages.MANIFEST_SIGNATURE_DUPLICATED));
357             assertInvalidManifest(expectedErrorList);
358         }
359     }
360
361     @Test
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");
367
368         final Optional<String> blankEntry = (Optional<String>) getEntryMethod.invoke(manifest, "        :");
369         assertFalse(blankEntry.isPresent(), "Entry should not be present");
370
371         final Optional<String> noColon = (Optional<String>) getEntryMethod.invoke(manifest, "anyKeyWithoutColon   ");
372         assertFalse(noColon.isPresent(), "Entry should not be present");
373
374         final Optional<String> blank = (Optional<String>) getEntryMethod.invoke(manifest, "   ");
375         assertFalse(blank.isPresent(), "Entry should not be present");
376
377         final Optional<String> empty = (Optional<String>) getEntryMethod.invoke(manifest, "");
378         assertFalse(empty.isPresent(), "Entry should not be present");
379
380         final Optional<String> nul1 = (Optional<String>) getEntryMethod.invoke(manifest, new Object[]{null});
381         assertFalse(nul1.isPresent(), "Entry should not be present");
382
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");
387     }
388
389     @Test
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");
395
396         final Optional<String> blankValue = (Optional<String>) getValueMethod.invoke(manifest, ":          ");
397         assertFalse(blankValue.isPresent(), "Value should not be present");
398
399         final Optional<String> noColon = (Optional<String>) getValueMethod.invoke(manifest, "anyKeyWithoutColon   ");
400         assertFalse(noColon.isPresent(), "Value should not be present");
401
402         final Optional<String> blank = (Optional<String>) getValueMethod.invoke(manifest, "   ");
403         assertFalse(blank.isPresent(), "Value should not be present");
404
405         final Optional<String> empty = (Optional<String>) getValueMethod.invoke(manifest, "");
406         assertFalse(empty.isPresent(), "Value should not be present");
407
408         final Optional<String> nul1 = (Optional<String>) getValueMethod.invoke(manifest, new Object[]{null});
409         assertFalse(nul1.isPresent(), "Value should not be present");
410
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");
415     }
416
417     @Test
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);
423         }
424     }
425
426     @Test
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);
432         }
433     }
434
435     @Test
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);
441         }
442     }
443
444     @Test
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);
450         }
451     }
452
453     @Test
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(
459                 buildErrorMessage(
460                     8, "Signature:", Messages.MANIFEST_EXPECTED_SIGNATURE_VALUE
461                 ));
462             assertInvalidManifest(expectedErrorList);
463         }
464     }
465
466     @Test
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(
472                 buildErrorMessage(
473                     9, "Certificate:", Messages.MANIFEST_EXPECTED_CERTIFICATE_VALUE
474                 ));
475             assertInvalidManifest(expectedErrorList);
476         }
477     }
478
479     @Test
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(
485                 buildErrorMessage(
486                     8, "Certificate: TOSCA-Metadata/TOSCA.cert", Messages.MANIFEST_EXPECTED_SIGNATURE_BEFORE_CERTIFICATE
487                 ));
488             assertInvalidManifest(expectedErrorList);
489         }
490     }
491
492     private void assertValidManifest(final int expectedMetadataSize, final int expectedSourcesSize,
493                                      final Map<String, Integer> expectedNonManoKeySize,
494                                      final ResourceTypeEnum resourceType, final boolean isSigned) {
495         assertAll(
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")
502         );
503         assertAll(
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")
511         );
512         for (final Entry<String, Integer> nonManoKeyAndSize : expectedNonManoKeySize.entrySet()) {
513             final String nonManoKey = nonManoKeyAndSize.getKey();
514             assertAll(
515                 "",
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))
520             );
521         }
522     }
523
524     private void assertInvalidManifest(final List<String> expectedErrorList) {
525         assertAll(
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")
529         );
530     }
531 }