Merge "Test for yang file archive limitation"
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java b/cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java
index 534077c..3e01f6e 100644
--- a/cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/utils/MultipartFileUtil.java
@@ -2,6 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Pantheon.tech
* Modifications Copyright (C) 2021 Bell Canada.
+ * Modifications Copyright (C) 2023 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -127,16 +128,17 @@
}
private static String extractYangResourceContent(final ZipInputStream zipInputStream,
- final ZipFileSizeValidator zipFileSizeValidator) throws IOException {
+ final ZipFileSizeValidator zipFileSizeValidator)
+ throws IOException {
try (final var byteArrayOutputStream = new ByteArrayOutputStream()) {
var totalSizeEntry = 0;
int numberOfBytesRead;
final var buffer = new byte[READ_BUFFER_SIZE];
- zipFileSizeValidator.incrementTotalEntryInArchive();
+ zipFileSizeValidator.incrementTotalYangFileEntryCountInArchive();
while ((numberOfBytesRead = zipInputStream.read(buffer, 0, READ_BUFFER_SIZE)) > 0) {
byteArrayOutputStream.write(buffer, 0, numberOfBytesRead);
totalSizeEntry += numberOfBytesRead;
- zipFileSizeValidator.updateTotalSizeArchive(numberOfBytesRead);
+ zipFileSizeValidator.updateTotalUncompressedSizeOfYangFilesInArchive(numberOfBytesRead);
zipFileSizeValidator.validateCompresssionRatio(totalSizeEntry);
}
return byteArrayOutputStream.toString(StandardCharsets.UTF_8);
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/utils/ZipFileSizeValidator.java b/cps-rest/src/main/java/org/onap/cps/rest/utils/ZipFileSizeValidator.java
index d148fb7..2e303d1 100644
--- a/cps-rest/src/main/java/org/onap/cps/rest/utils/ZipFileSizeValidator.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/utils/ZipFileSizeValidator.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Bell Canada.
+ * Modifications Copyright (C) 2023 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,31 +29,33 @@
public class ZipFileSizeValidator {
private static final int THRESHOLD_ENTRIES = 10000;
- private static final int THRESHOLD_SIZE = 100000000;
+ private static int THRESHOLD_SIZE = 100000000;
private static final double THRESHOLD_RATIO = 40;
private static final String INVALID_ZIP = "Invalid ZIP archive content.";
- private int totalSizeArchive = 0;
- private int totalEntryInArchive = 0;
+ private int totalUncompressedSizeOfYangFilesInArchive = 0;
+ private int totalYangFileEntriesInArchive = 0;
private long compressedSize = 0;
/**
* Increment the totalEntryInArchive by 1.
*/
- public void incrementTotalEntryInArchive() {
- totalEntryInArchive++;
+ public void incrementTotalYangFileEntryCountInArchive() {
+ totalYangFileEntriesInArchive++;
}
/**
* Update the totalSizeArchive by numberOfBytesRead.
+ *
* @param numberOfBytesRead the number of bytes of each entry
*/
- public void updateTotalSizeArchive(final int numberOfBytesRead) {
- totalSizeArchive += numberOfBytesRead;
+ public void updateTotalUncompressedSizeOfYangFilesInArchive(final int numberOfBytesRead) {
+ totalUncompressedSizeOfYangFilesInArchive += numberOfBytesRead;
}
/**
* Validate the total Compression size of the zip.
+ *
* @param totalEntrySize the size of the unzipped entry.
*/
public void validateCompresssionRatio(final int totalEntrySize) {
@@ -68,13 +71,14 @@
* Validate the total Size and number of entries in the zip.
*/
public void validateSizeAndEntries() {
- if (totalSizeArchive > THRESHOLD_SIZE) {
+ if (totalUncompressedSizeOfYangFilesInArchive > THRESHOLD_SIZE) {
throw new ModelValidationException(INVALID_ZIP,
- String.format("The uncompressed data size exceeds the CPS limit %s bytes.", THRESHOLD_SIZE));
+ String.format("The total size of uncompressed yang files exceeds the CPS limit of %s bytes.",
+ THRESHOLD_SIZE));
}
- if (totalEntryInArchive > THRESHOLD_ENTRIES) {
+ if (totalYangFileEntriesInArchive > THRESHOLD_ENTRIES) {
throw new ModelValidationException(INVALID_ZIP,
- String.format("The number of entries in the archive exceeds the CPS limit %s.",
+ String.format("The number of yang file entries in the archive exceeds the CPS limit %s.",
THRESHOLD_ENTRIES));
}
}
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/utils/MultipartFileUtilSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/utils/MultipartFileUtilSpec.groovy
index 3f4729e..67ee50e 100644
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/utils/MultipartFileUtilSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/utils/MultipartFileUtilSpec.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Pantheon.tech
+ * Modifications Copyright (C) 2023 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -51,7 +52,7 @@
def 'Extract yang resources from zip archive.'() {
given: 'uploaded zip archive containing 2 yang files and 1 not yang (json) file'
def multipartFile = new MockMultipartFile("file", "TEST.ZIP", "application/zip",
- getClass().getResource("/yang-files-set.zip").getBytes())
+ getClass().getResource("/yang-files-set.zip").getBytes())
when: 'resources are extracted from zip file'
def result = MultipartFileUtil.extractYangResourcesMap(multipartFile)
then: 'information from yang files is extracted, not yang file (json) is ignored'
@@ -60,6 +61,32 @@
assert result["component.yang"] == "fake component content 1\n"
}
+ def 'Yang file limits in zip archive: #scenario for the bug reported in CPS-1477'() {
+ given: 'a yang file size (uncompressed) limit of #threshold bytes'
+ ZipFileSizeValidator.THRESHOLD_SIZE = threshold
+ and: 'an archive with a yang file of 1083 bytes'
+ def multipartFile = multipartZipFileFromResource('/yang-files-set-total-1083-bytes.zip')
+ when: 'attempt to extract yang files'
+ def thrownException = null
+ try {
+ MultipartFileUtil.extractYangResourcesMap(multipartFile)
+ } catch (Exception e) {
+ thrownException = e
+ }
+ then: 'ModelValidationException indicating size limit is only thrown when threshold exceeded'
+ if (thresholdExceeded) {
+ assert thrownException instanceof ModelValidationException
+ assert thrownException.details.contains('limit of ' + threshold + ' bytes')
+ } else {
+ assert thrownException == null
+ }
+ where:
+ scenario | threshold || thresholdExceeded
+ 'exceed limit' | 1082 || true
+ 'equals to limit' | 1083 || false
+ 'within limit' | 1084 || false
+ }
+
def 'Extract resources from zip archive having #caseDescriptor.'() {
when: 'attempt to extract resources from zip file is performed'
MultipartFileUtil.extractYangResourcesMap(multipartFile)
@@ -91,7 +118,7 @@
def multipartZipFileFromResource(resourcePath) {
return new MockMultipartFile("file", "TEST.ZIP", "application/zip",
- getClass().getResource(resourcePath).getBytes())
+ getClass().getResource(resourcePath).getBytes())
}
def multipartFileForIOException(extension) {
diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/utils/ZipFileSizeValidatorSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/utils/ZipFileSizeValidatorSpec.groovy
index 16fbf98..60ecb2e 100644
--- a/cps-rest/src/test/groovy/org/onap/cps/rest/utils/ZipFileSizeValidatorSpec.groovy
+++ b/cps-rest/src/test/groovy/org/onap/cps/rest/utils/ZipFileSizeValidatorSpec.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Bell Canada.
+ * Modifications Copyright (C) 2023 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,25 +33,25 @@
def compressedFileSize = 100
def setup() {
- objectUnderTest.setTotalEntryInArchive(0)
- objectUnderTest.setTotalSizeArchive(0)
+ objectUnderTest.setTotalYangFileEntriesInArchive(0)
+ objectUnderTest.setTotalUncompressedSizeOfYangFilesInArchive(0)
objectUnderTest.setCompressedSize(compressedFileSize)
}
- def 'Increment the total entries in Archive.'() {
- when: 'the totalEntriesInArchive value is incremented'
- objectUnderTest.incrementTotalEntryInArchive()
- then: 'the totalEntriesInArchive is incremented by 1'
- assert objectUnderTest.totalEntryInArchive == old(objectUnderTest.totalEntryInArchive) + 1
+ def 'Increment the total yang file entry count in Archive.'() {
+ when: 'the totalYangFileEntryInArchive value is incremented'
+ objectUnderTest.incrementTotalYangFileEntryCountInArchive()
+ then: 'the totalYangFileEntryInArchive is incremented by 1'
+ assert objectUnderTest.totalYangFileEntriesInArchive == old(objectUnderTest.totalYangFileEntriesInArchive) + 1
}
- def 'Update the total size of Archive.'() {
+ def 'Update the total uncompressed size of yang files in Archive.'() {
given: 'the size of an entry of archive'
def entrySize = 100
- when: 'the totalSizeArchive is to be updated with the latest entry Size'
- objectUnderTest.updateTotalSizeArchive(entrySize)
- then: 'the totalSizeArchive is updated as expected'
- assert objectUnderTest.totalSizeArchive == old(objectUnderTest.totalSizeArchive) + entrySize
+ when: 'the totalUncompressedSizeOfYangFilesInArchive is to be updated with the latest entry Size'
+ objectUnderTest.updateTotalUncompressedSizeOfYangFilesInArchive(entrySize)
+ then: 'the totalUncompressedSizeOfYangFilesInArchive is updated as expected'
+ assert objectUnderTest.totalUncompressedSizeOfYangFilesInArchive == old(objectUnderTest.totalUncompressedSizeOfYangFilesInArchive) + entrySize
}
def 'Validate the zip archive for compression ratio less that threshold compression ratio.'() {
@@ -73,29 +74,29 @@
def 'Validate the zip archive for thresholdSize and thresholdEntries #caseDescriptor.'() {
given:
- objectUnderTest.setTotalEntryInArchive(totalEntriesInArchive)
- objectUnderTest.setTotalSizeArchive(totalSizeArchive)
+ objectUnderTest.setTotalYangFileEntriesInArchive(totalYangEntriesInArchive)
+ objectUnderTest.setTotalUncompressedSizeOfYangFilesInArchive(totalUncompressedSizeofYangArchive)
when: 'the validation is performed against the threshold size and threshold Entries count'
objectUnderTest.validateSizeAndEntries()
then: 'validation passes and no exception is thrown'
noExceptionThrown()
where: 'following cases are tested'
- caseDescriptor | totalSizeArchive | totalEntriesInArchive
- 'less than threshold value' | thresholdSize - 1 | thresholdEntries - 1
- 'at threshold value' | thresholdSize | thresholdEntries
+ caseDescriptor | totalUncompressedSizeofYangArchive | totalYangEntriesInArchive
+ 'less than threshold value' | thresholdSize - 1 | thresholdEntries - 1
+ 'at threshold value' | thresholdSize | thresholdEntries
}
def 'Validate the zip archive for thresholdSize and thresholdEntries with #caseDescriptor.'() {
given:
- objectUnderTest.setTotalEntryInArchive(totalEntriesInArchive)
- objectUnderTest.setTotalSizeArchive(totalSizeArchive)
+ objectUnderTest.setTotalYangFileEntriesInArchive(totalYangEntriesInArchive)
+ objectUnderTest.setTotalUncompressedSizeOfYangFilesInArchive(totalUncompressedSizeofYangArchive)
when: 'the validation is performed against the threshold size and threshold Entries count'
objectUnderTest.validateSizeAndEntries()
then: 'validation fails and exception is thrown'
thrown ModelValidationException
where: 'following cases are tested'
- caseDescriptor | totalSizeArchive | totalEntriesInArchive
- 'totalEntriesInArchive exceeds threshold value' | thresholdSize | thresholdEntries + 1
- 'totalSizeArchive exceeds threshold value' | thresholdSize + 1 | thresholdEntries
+ caseDescriptor | totalUncompressedSizeofYangArchive | totalYangEntriesInArchive
+ 'totalEntriesInArchive exceeds threshold value' | thresholdSize | thresholdEntries + 1
+ 'totalSizeArchive exceeds threshold value' | thresholdSize + 1 | thresholdEntries
}
}
diff --git a/cps-rest/src/test/resources/yang-files-set-total-1083-bytes.zip b/cps-rest/src/test/resources/yang-files-set-total-1083-bytes.zip
new file mode 100644
index 0000000..9908055
--- /dev/null
+++ b/cps-rest/src/test/resources/yang-files-set-total-1083-bytes.zip
Binary files differ