Initial commit
This commit is contained in:
parent
1df3e2ad81
commit
6447b1d90b
19 changed files with 565 additions and 54 deletions
10
.idea/.gitignore
generated
vendored
Normal file
10
.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
|
|
@ -0,0 +1 @@
|
|||
benchmark
|
||||
10
.idea/go.imports.xml
generated
Normal file
10
.idea/go.imports.xml
generated
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GoImports">
|
||||
<option name="excludedPackages">
|
||||
<array>
|
||||
<option value="golang.org/x/net/context" />
|
||||
</array>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
17
.idea/gradle.xml
generated
Normal file
17
.idea/gradle.xml
generated
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="myGradleHome" value="" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
10
.idea/misc.xml
generated
Normal file
10
.idea/misc.xml
generated
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="homebrew-25" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
7
build.gradle
Normal file → Executable file
7
build.gradle
Normal file → Executable file
|
|
@ -10,8 +10,15 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation group: 'commons-io', name: 'commons-io', version: '2.21.0'
|
||||
implementation "org.apache.commons:commons-lang3:3.20.0"
|
||||
implementation "org.slf4j:jul-to-slf4j:$sl4j_version"
|
||||
implementation "org.slf4j:log4j-over-slf4j:$sl4j_version"
|
||||
|
||||
testImplementation platform('org.junit:junit-bom:6.0.0')
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter'
|
||||
testImplementation group: 'org.hamcrest', name: 'hamcrest-library', version: '3.0'
|
||||
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
|
|
|
|||
1
gradle.properties
Executable file
1
gradle.properties
Executable file
|
|
@ -0,0 +1 @@
|
|||
sl4j_version=1.7.35
|
||||
0
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file → Executable file
0
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file → Executable file
2
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file → Executable file
2
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file → Executable file
|
|
@ -1,4 +1,4 @@
|
|||
#Wed Apr 08 21:42:31 CEST 2026
|
||||
#Wed Apr 08 22:08:17 CEST 2026
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
||||
|
|
|
|||
0
gradlew.bat
vendored
Normal file → Executable file
0
gradlew.bat
vendored
Normal file → Executable file
2
settings.gradle
Normal file → Executable file
2
settings.gradle
Normal file → Executable file
|
|
@ -1 +1 @@
|
|||
rootProject.name = 'Benchmark'
|
||||
rootProject.name = 'benchmark'
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package ch.illgner;
|
||||
|
||||
public class OrderCalculator {
|
||||
|
||||
/**
|
||||
* Berechnet den Endpreis nach Rabatt und inklusive 19% MwSt.
|
||||
*
|
||||
* @param basePrice Der Nettopreis
|
||||
* @param discountRate Der Rabatt (z.B. 0.1 für 10%)
|
||||
* @return Der Endpreis gerundet auf 2 Nachkommastellen
|
||||
*/
|
||||
public double calculateFinalPrice(double basePrice, double discountRate) {
|
||||
double discountedPrice = basePrice * discountRate;
|
||||
|
||||
double priceWithTax = discountedPrice * 1.19;
|
||||
|
||||
return priceWithTax;
|
||||
}
|
||||
}
|
||||
138
src/main/java/illgner/ch/createzip/PostBoxZipFileWriter.java
Executable file
138
src/main/java/illgner/ch/createzip/PostBoxZipFileWriter.java
Executable file
|
|
@ -0,0 +1,138 @@
|
|||
package illgner.ch.createzip;
|
||||
|
||||
import illgner.ch.encryption.IOutputStreamEnhancer;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.output.CountingOutputStream;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import static java.nio.file.attribute.PosixFilePermission.GROUP_READ;
|
||||
import static java.nio.file.attribute.PosixFilePermission.OTHERS_READ;
|
||||
import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
|
||||
import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
|
||||
|
||||
public class PostBoxZipFileWriter implements Closeable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PostBoxZipFileWriter.class);
|
||||
|
||||
private static final Set<PosixFilePermission> ZIP_FILE_PERMISSIONS = EnumSet.of(OWNER_READ, OWNER_WRITE, GROUP_READ, OTHERS_READ);
|
||||
|
||||
private final Path destinationDir;
|
||||
private final String baseName;
|
||||
private final int chunkSize;
|
||||
private final int bufferSize;
|
||||
private final ZipResult zipResult;
|
||||
IOutputStreamEnhancer outputStreamEnhancer;
|
||||
|
||||
private ZipOutputStream zipOutputStream;
|
||||
|
||||
private int fileCount = 1;
|
||||
private long bytesWritten = 0;
|
||||
private File actualZipFile;
|
||||
private CountingOutputStream countingOutputStream;
|
||||
|
||||
public PostBoxZipFileWriter(Path destinationDir, String baseName, int chunkSize, int bufferSize, IOutputStreamEnhancer outputStreamEnhancer) {
|
||||
this.destinationDir = destinationDir;
|
||||
this.baseName = baseName;
|
||||
this.chunkSize = chunkSize;
|
||||
this.bufferSize = bufferSize;
|
||||
this.zipResult = new ZipResult();
|
||||
this.outputStreamEnhancer = outputStreamEnhancer;
|
||||
}
|
||||
|
||||
private ZipOutputStream createNewZipOutputStream() throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException,
|
||||
NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
|
||||
String actualZipFilename = createOutputFilename();
|
||||
actualZipFile = destinationDir.resolve(actualZipFilename).toFile();
|
||||
|
||||
LOG.info("Creating zip part {}: {}", fileCount, actualZipFilename);
|
||||
|
||||
countingOutputStream = new CountingOutputStream(outputStreamEnhancer.enhance(new BufferedOutputStream(new FileOutputStream(actualZipFile), bufferSize)));
|
||||
return new ZipOutputStream(countingOutputStream);
|
||||
}
|
||||
|
||||
private String createOutputFilename() {
|
||||
return String.format("%s_%02d.zip", baseName, fileCount);
|
||||
}
|
||||
|
||||
public void write(InputStream inputStream, String path) throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException,
|
||||
NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
|
||||
if (countingOutputStream == null) {
|
||||
zipOutputStream = createNewZipOutputStream();
|
||||
}
|
||||
if (bytesWritten >= chunkSize) {
|
||||
switchOutputFile();
|
||||
}
|
||||
LOG.info("Writing file {} to zip", path);
|
||||
zipOutputStream.putNextEntry(new ZipEntry(path));
|
||||
bytesWritten += IOUtils.copyLarge(inputStream, zipOutputStream);
|
||||
zipOutputStream.closeEntry();
|
||||
}
|
||||
|
||||
private void switchOutputFile() throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
LOG.info("Switching zip");
|
||||
zipOutputStream.flush();
|
||||
zipOutputStream.close();
|
||||
addZipToResult();
|
||||
fileCount++;
|
||||
zipOutputStream = createNewZipOutputStream();
|
||||
bytesWritten = 0;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
LOG.info("Closing zip {}", actualZipFile.getName());
|
||||
zipOutputStream.flush();
|
||||
zipOutputStream.close();
|
||||
addZipToResult();
|
||||
}
|
||||
|
||||
public void writeReadMe() throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException,
|
||||
NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
|
||||
if (zipOutputStream != null) {
|
||||
LOG.info("Skip adding Readme");
|
||||
return;
|
||||
}
|
||||
|
||||
try (InputStream readmeStream = this.getClass().getClassLoader().getResourceAsStream("Readme.txt")) {
|
||||
if (readmeStream == null) {
|
||||
throw new IOException("Cannot open Readme");
|
||||
}
|
||||
|
||||
LOG.info("Writing Readme");
|
||||
write(readmeStream, "Readme.txt");
|
||||
} catch (IOException e) {
|
||||
throw new IOException("Could not write Readme", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ZipResult getZipResult() {
|
||||
return this.zipResult;
|
||||
}
|
||||
|
||||
private void addZipToResult() throws IOException {
|
||||
zipResult.add(actualZipFile.getName(), countingOutputStream.getCount());
|
||||
Files.setPosixFilePermissions(actualZipFile.toPath(), ZIP_FILE_PERMISSIONS);
|
||||
}
|
||||
}
|
||||
23
src/main/java/illgner/ch/createzip/ZipResult.java
Executable file
23
src/main/java/illgner/ch/createzip/ZipResult.java
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
package illgner.ch.createzip;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ZipResult {
|
||||
|
||||
private final List<String> zipFilenames = new ArrayList<>();
|
||||
private final List<Long> zipFileLengths = new ArrayList<>();
|
||||
|
||||
void add(String fileName, long bytesWritten) {
|
||||
zipFilenames.add(fileName);
|
||||
zipFileLengths.add(bytesWritten);
|
||||
}
|
||||
|
||||
public List<Long> getFileLengths() {
|
||||
return zipFileLengths;
|
||||
}
|
||||
|
||||
public List<String> getFilenames() {
|
||||
return zipFilenames;
|
||||
}
|
||||
}
|
||||
15
src/main/java/illgner/ch/encryption/IInputStreamEnhancer.java
Executable file
15
src/main/java/illgner/ch/encryption/IInputStreamEnhancer.java
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
package illgner.ch.encryption;
|
||||
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
|
||||
public interface IInputStreamEnhancer {
|
||||
|
||||
InputStream enhance(InputStream inputStream) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IOException, InvalidAlgorithmParameterException, NoSuchProviderException;
|
||||
|
||||
}
|
||||
18
src/main/java/illgner/ch/encryption/IOutputStreamEnhancer.java
Executable file
18
src/main/java/illgner/ch/encryption/IOutputStreamEnhancer.java
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
package illgner.ch.encryption;
|
||||
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
|
||||
public interface IOutputStreamEnhancer {
|
||||
/**
|
||||
* This method enhances the given input stream {@link OutputStream} wrapping with the additional functionality (in our case with encryption)
|
||||
* @param outputStream the original stream {@link OutputStream} to be enhanced.
|
||||
* @return A new {@link OutputStream} that wraps the functionality to input stream.
|
||||
*/
|
||||
OutputStream enhance(OutputStream outputStream) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IOException, InvalidAlgorithmParameterException, NoSuchProviderException;
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package ch.illgner;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class OrderCalculatorTest {
|
||||
|
||||
@Test
|
||||
public void testCalculateFinalPrice_NormalScenario() {
|
||||
OrderCalculator calculator = new OrderCalculator();
|
||||
|
||||
// Szenario: 100€ Basis, 10% Rabatt = 90€.
|
||||
// 90€ + 19% MwSt (17.10€) = 107.10€
|
||||
double result = calculator.calculateFinalPrice(100.0, 0.10);
|
||||
|
||||
assertEquals(107.10, result, "Der Endpreis für 100€ mit 10% Rabatt muss 107.10 sein.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCalculateFinalPrice_Rounding() {
|
||||
OrderCalculator calculator = new OrderCalculator();
|
||||
|
||||
// Szenario: 10.55€ Basis, 5% Rabatt = 10.0225€
|
||||
// 10.0225€ + 19% MwSt = 11.926775€ -> Gerundet: 11.93€
|
||||
double result = calculator.calculateFinalPrice(10.55, 0.05);
|
||||
|
||||
assertEquals(11.93, result, "Der Preis muss korrekt auf 2 Stellen gerundet werden.");
|
||||
}
|
||||
}
|
||||
306
src/test/java/illgner/ch/jobs/postboxbulk/service/PostBoxZipFileWriterTest.java
Executable file
306
src/test/java/illgner/ch/jobs/postboxbulk/service/PostBoxZipFileWriterTest.java
Executable file
|
|
@ -0,0 +1,306 @@
|
|||
package illgner.ch.jobs.postboxbulk.service;
|
||||
|
||||
import illgner.ch.createzip.PostBoxZipFileWriter;
|
||||
import illgner.ch.createzip.ZipResult;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Objects;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
|
||||
import static org.hamcrest.io.FileMatchers.aFileNamed;
|
||||
import static org.hamcrest.io.FileMatchers.anExistingFile;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class PostBoxZipFileWriterTest {
|
||||
|
||||
private static final Path DESTINATION_DIR = Paths.get("./destination");
|
||||
private static final int ONE_BYTE = 1024;
|
||||
private static final int HALF_BYTE = ONE_BYTE / 2;
|
||||
private static final int ZIP_BUFFER_SIZE_IN_BYTE = 2 * ONE_BYTE;
|
||||
private static final int ZIP_CHUNK_SIZE_IN_BYTE = 3 * ONE_BYTE;
|
||||
|
||||
@BeforeAll
|
||||
static void setUp() throws IOException {
|
||||
FileUtils.deleteDirectory(DESTINATION_DIR.toFile());
|
||||
boolean directoryCreated = DESTINATION_DIR.toFile().mkdir();
|
||||
assertTrue(directoryCreated);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void cleanUp() throws IOException {
|
||||
FileUtils.deleteDirectory(DESTINATION_DIR.toFile());
|
||||
boolean directoryCreated = DESTINATION_DIR.toFile().mkdir();
|
||||
assertTrue(directoryCreated);
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleFileSmallerThanChunkSizeToOneZip() throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
byte[] fileSimpleContent = RandomStringUtils.randomAlphanumeric(2 * ONE_BYTE).getBytes(StandardCharsets.UTF_8);
|
||||
ZipResult zipResult;
|
||||
String outputFileName = RandomStringUtils.randomAlphanumeric(10);
|
||||
String inputFileName = "singleFileSmallerThanChunkSizeToOneZip.txt";
|
||||
PostBoxZipFileWriter postBoxZipFileWriter = new PostBoxZipFileWriter(
|
||||
DESTINATION_DIR, outputFileName, ZIP_CHUNK_SIZE_IN_BYTE, ZIP_BUFFER_SIZE_IN_BYTE, (OutputStream outputStream) -> outputStream);
|
||||
try (postBoxZipFileWriter) {
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(fileSimpleContent), inputFileName);
|
||||
}
|
||||
String expectedZippedFileName = outputFileName + "_01.zip";
|
||||
zipResult = postBoxZipFileWriter.getZipResult();
|
||||
File createdZipFile = DESTINATION_DIR.resolve(expectedZippedFileName).toFile();
|
||||
|
||||
assertThat(zipResult.getFilenames(), hasSize(1));
|
||||
assertThat(zipResult.getFileLengths(), hasSize(1));
|
||||
assertThat(zipResult.getFilenames().get(0), is(equalTo(expectedZippedFileName)));
|
||||
assertThat(zipResult.getFileLengths().get(0), is(equalTo(createdZipFile.length())));
|
||||
assertThat(createdZipFile, is(anExistingFile()));
|
||||
assertThat(createdZipFile, is(aFileNamed(equalTo(expectedZippedFileName))));
|
||||
|
||||
// check zip content
|
||||
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(createdZipFile))) {
|
||||
assertThat(Objects.requireNonNull(zipInputStream.getNextEntry()).getName(), is(equalTo(inputFileName)));
|
||||
assertThat(IOUtils.toByteArray(zipInputStream), is(equalTo(fileSimpleContent)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void singleFileGreaterThanChunkSizeToOneZip() throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
byte[] fileSimpleContent = RandomStringUtils.randomAlphanumeric(4 * ONE_BYTE).getBytes(StandardCharsets.UTF_8);
|
||||
ZipResult zipResult;
|
||||
String outputFileName = RandomStringUtils.randomAlphanumeric(10);
|
||||
String inputFileName = "singleFileGreaterThanChunkSizeToOneZip.txt";
|
||||
PostBoxZipFileWriter postBoxZipFileWriter = new PostBoxZipFileWriter(
|
||||
DESTINATION_DIR, outputFileName, ZIP_CHUNK_SIZE_IN_BYTE, ZIP_BUFFER_SIZE_IN_BYTE, (OutputStream outputStream) -> outputStream);
|
||||
try (postBoxZipFileWriter) {
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(fileSimpleContent), inputFileName);
|
||||
}
|
||||
String expectedZippedFileNamePartOne = outputFileName + "_01.zip";
|
||||
zipResult = postBoxZipFileWriter.getZipResult();
|
||||
assertThat(zipResult.getFilenames(), hasSize(1));
|
||||
assertThat(zipResult.getFileLengths(), hasSize(1));
|
||||
assertTrue(zipResult.getFilenames().contains(expectedZippedFileNamePartOne));
|
||||
|
||||
File createdZipOne = DESTINATION_DIR.resolve(expectedZippedFileNamePartOne).toFile();
|
||||
|
||||
assertThat(createdZipOne, is(anExistingFile()));
|
||||
assertThat(createdZipOne, is(aFileNamed(equalTo(expectedZippedFileNamePartOne))));
|
||||
|
||||
// check zip content
|
||||
extractSplitZipFiles(new File[]{createdZipOne});
|
||||
File extractedFile = new File(DESTINATION_DIR + "/" + inputFileName);
|
||||
byte[] extractedFileBytes = IOUtils.toByteArray(new FileInputStream(extractedFile));
|
||||
assertThat(extractedFileBytes, is(equalTo(fileSimpleContent)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleFileSmallerThanChunkSizeToSingleZip() throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
byte[] firstFile = RandomStringUtils.randomAlphanumeric(ONE_BYTE).getBytes(StandardCharsets.UTF_8);
|
||||
byte[] secondFile = "uts öäü ÖÄÜ ß".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
String outputFileName = RandomStringUtils.randomAlphanumeric(10);
|
||||
String inputFileNameOne = "multipleFileSmallerThanChunkSizeToSingleZip1.txt";
|
||||
String inputFileNameTwo = "multipleFileSmallerThanChunkSizeToSingleZip2.txt";
|
||||
|
||||
ZipResult zipResult;
|
||||
PostBoxZipFileWriter postBoxZipFileWriter = new PostBoxZipFileWriter(
|
||||
DESTINATION_DIR, outputFileName, ZIP_CHUNK_SIZE_IN_BYTE, ZIP_BUFFER_SIZE_IN_BYTE, (OutputStream outputStream) -> outputStream);
|
||||
try (postBoxZipFileWriter) {
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(firstFile), inputFileNameOne);
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(secondFile), inputFileNameTwo);
|
||||
}
|
||||
|
||||
zipResult = postBoxZipFileWriter.getZipResult();
|
||||
String expectedZippedFileNamePartOne = outputFileName + "_01.zip";
|
||||
File createdZip = DESTINATION_DIR.resolve(expectedZippedFileNamePartOne).toFile();
|
||||
|
||||
assertThat(zipResult.getFilenames(), hasSize(1));
|
||||
assertThat(zipResult.getFileLengths(), hasSize(1));
|
||||
assertThat(createdZip, is(anExistingFile()));
|
||||
assertThat(createdZip, is(aFileNamed(equalTo(expectedZippedFileNamePartOne))));
|
||||
assertThat(zipResult.getFilenames().get(0), is(equalTo(expectedZippedFileNamePartOne)));
|
||||
assertThat(zipResult.getFileLengths().get(0), is(equalTo(createdZip.length())));
|
||||
|
||||
// check zip content
|
||||
try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(createdZip))) {
|
||||
assertThat(Objects.requireNonNull(zipInputStream.getNextEntry()).getName(), is(equalTo(inputFileNameOne)));
|
||||
assertThat(IOUtils.toByteArray(zipInputStream), is(equalTo(firstFile)));
|
||||
assertThat(zipInputStream.getNextEntry().getName(), is(equalTo(inputFileNameTwo)));
|
||||
assertThat(IOUtils.toByteArray(zipInputStream), is(equalTo(secondFile)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleFilesTogetherGreaterThanChunkSizeToSingleZip() throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
String text1 = RandomStringUtils.randomAlphanumeric(2 * ONE_BYTE + HALF_BYTE);
|
||||
String text2 = RandomStringUtils.randomAlphanumeric(2 * ONE_BYTE + HALF_BYTE);
|
||||
byte[] firstFile = text1.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] secondFile = text2.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
String outputFileName = RandomStringUtils.randomAlphanumeric(10);
|
||||
String inputFileNameOne = "multipleFilesTogetherGreaterThanChunkSizeToSingleZip1.txt";
|
||||
String inputFileNameTwo = "multipleFilesTogetherGreaterThanChunkSizeToSingleZip2.txt";
|
||||
|
||||
ZipResult zipResult;
|
||||
PostBoxZipFileWriter postBoxZipFileWriter = new PostBoxZipFileWriter(
|
||||
DESTINATION_DIR, outputFileName, ZIP_CHUNK_SIZE_IN_BYTE, ZIP_BUFFER_SIZE_IN_BYTE, (OutputStream outputStream) -> outputStream);
|
||||
try (postBoxZipFileWriter) {
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(firstFile), inputFileNameOne);
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(secondFile), inputFileNameTwo);
|
||||
} finally {
|
||||
zipResult = postBoxZipFileWriter.getZipResult();
|
||||
}
|
||||
|
||||
String expectedZippedFileNamePartOne = outputFileName + "_01.zip";
|
||||
|
||||
assertThat(zipResult.getFilenames(), hasSize(1));
|
||||
assertThat(zipResult.getFileLengths(), hasSize(1));
|
||||
assertTrue(zipResult.getFilenames().contains(expectedZippedFileNamePartOne));
|
||||
|
||||
File createdZipOne = DESTINATION_DIR.resolve(expectedZippedFileNamePartOne).toFile();
|
||||
|
||||
assertThat(createdZipOne, is(anExistingFile()));
|
||||
assertThat(createdZipOne, is(aFileNamed(equalTo(expectedZippedFileNamePartOne))));
|
||||
|
||||
// check zip content
|
||||
extractSplitZipFiles(new File[]{createdZipOne});
|
||||
File extractedFile = new File(DESTINATION_DIR + "/" + inputFileNameOne);
|
||||
byte[] extractedFileBytes = IOUtils.toByteArray(new FileInputStream(extractedFile));
|
||||
assertThat(extractedFileBytes, is(equalTo(firstFile)));
|
||||
|
||||
extractedFile = new File(DESTINATION_DIR + "/" + inputFileNameTwo);
|
||||
extractedFileBytes = IOUtils.toByteArray(new FileInputStream(extractedFile));
|
||||
assertThat(extractedFileBytes, is(equalTo(secondFile)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleBigFilesToMultipleZip() throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
ZipResult zipResult;
|
||||
int bigChuckSize = ONE_BYTE * 50;
|
||||
int bigBufferSize = ONE_BYTE * 10;
|
||||
// First two files will be zipped together and third file will be zipped in the second file.
|
||||
byte[] firstFile = RandomStringUtils.randomAlphanumeric(40 * ONE_BYTE).getBytes(StandardCharsets.UTF_8);
|
||||
byte[] secondFile = RandomStringUtils.randomAlphanumeric(70 * ONE_BYTE).getBytes(StandardCharsets.UTF_8);
|
||||
byte[] thirdFile = RandomStringUtils.randomAlphanumeric(10 * ONE_BYTE).getBytes(StandardCharsets.UTF_8);
|
||||
String[] originalFileNames = {"multipleBigFilesToMultipleZip1.txt", "multipleBigFilesToMultipleZip2.txt", "multipleBigFilesToMultipleZip3.txt"};
|
||||
String outputFileName = RandomStringUtils.randomAlphanumeric(10);
|
||||
|
||||
PostBoxZipFileWriter postBoxZipFileWriter = new PostBoxZipFileWriter(
|
||||
DESTINATION_DIR, outputFileName, bigChuckSize, bigBufferSize, (OutputStream outputStream) -> outputStream);
|
||||
try (postBoxZipFileWriter) {
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(firstFile), originalFileNames[0]);
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(secondFile), originalFileNames[1]);
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(thirdFile), originalFileNames[2]);
|
||||
} finally {
|
||||
zipResult = postBoxZipFileWriter.getZipResult();
|
||||
}
|
||||
|
||||
String expectedZippedFileNamePartOne = outputFileName + "_01.zip";
|
||||
String expectedZippedFileNamePartTwo = outputFileName + "_02.zip";
|
||||
|
||||
assertThat(zipResult.getFilenames(), hasSize(2));
|
||||
assertThat(zipResult.getFileLengths(), hasSize(2));
|
||||
assertTrue(zipResult.getFilenames().contains(expectedZippedFileNamePartOne));
|
||||
assertTrue(zipResult.getFilenames().contains(expectedZippedFileNamePartTwo));
|
||||
|
||||
File part1 = DESTINATION_DIR.resolve(expectedZippedFileNamePartOne).toFile();
|
||||
File part2 = DESTINATION_DIR.resolve(expectedZippedFileNamePartTwo).toFile();
|
||||
|
||||
File[] zippedFiles = {part1, part2};
|
||||
|
||||
assertThat(part1, is(anExistingFile()));
|
||||
assertThat(part1, is(aFileNamed(equalTo(expectedZippedFileNamePartOne))));
|
||||
assertThat(part2, is(anExistingFile()));
|
||||
assertThat(part2, is(aFileNamed(equalTo(expectedZippedFileNamePartTwo))));
|
||||
|
||||
extractSplitZipFiles(zippedFiles);
|
||||
|
||||
// check zip content
|
||||
File extractedFile = new File(DESTINATION_DIR + "/" + originalFileNames[0]);
|
||||
byte[] extractedFileBytes = IOUtils.toByteArray(new FileInputStream(extractedFile));
|
||||
assertThat(extractedFileBytes, is(equalTo(firstFile)));
|
||||
|
||||
extractedFile = new File(DESTINATION_DIR + "/" + originalFileNames[1]);
|
||||
extractedFileBytes = IOUtils.toByteArray(new FileInputStream(extractedFile));
|
||||
assertThat(extractedFileBytes, is(equalTo(secondFile)));
|
||||
|
||||
extractedFile = new File(DESTINATION_DIR + "/" + originalFileNames[2]);
|
||||
extractedFileBytes = IOUtils.toByteArray(new FileInputStream(extractedFile));
|
||||
assertThat(extractedFileBytes, is(equalTo(thirdFile)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createBigZip() throws IOException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
// first implementation crashed with an OutOfMemoryException while copying an 50MB Stream,
|
||||
// so we added a test for this
|
||||
|
||||
try (PostBoxZipFileWriter zipFileWriter = new PostBoxZipFileWriter(
|
||||
DESTINATION_DIR, "testBigMulti", 100 * 1000 * 1000, ZIP_BUFFER_SIZE_IN_BYTE, (OutputStream outputStream) -> outputStream)) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
byte[] content = RandomStringUtils.randomAlphanumeric(50 * 1000 * 1000).getBytes();
|
||||
zipFileWriter.write(new ByteArrayInputStream(content), "test" + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void addCompressibleFiles() throws InvalidAlgorithmParameterException, NoSuchPaddingException, IOException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException {
|
||||
byte[] content1 = new byte[10000];
|
||||
byte[] content2 = new byte[10000];
|
||||
byte[] content3 = new byte[10000];
|
||||
|
||||
String outputFileName = RandomStringUtils.randomAlphanumeric(10);
|
||||
|
||||
ZipResult zipResult;
|
||||
try (PostBoxZipFileWriter postBoxZipFileWriter = new PostBoxZipFileWriter(DESTINATION_DIR, outputFileName, 1000, 2048, (OutputStream outputStream) -> outputStream)) {
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(content1), "file1");
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(content2), "file2");
|
||||
postBoxZipFileWriter.write(new ByteArrayInputStream(content3), "file3");
|
||||
zipResult = postBoxZipFileWriter.getZipResult();
|
||||
}
|
||||
assertThat("compressible files only containing zeroes should be compressed into one file", zipResult.getFileLengths().size(), is(1));
|
||||
}
|
||||
|
||||
public static void extractSplitZipFiles(File[] zipFiles) throws IOException {
|
||||
byte[] buffer = new byte[ZIP_BUFFER_SIZE_IN_BYTE];
|
||||
for (File zipFilePath : zipFiles) {
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath))) {
|
||||
ZipEntry zipEntry = zis.getNextEntry();
|
||||
|
||||
while (zipEntry != null) {
|
||||
File newFile = new File(DESTINATION_DIR + "/" + zipEntry.getName());
|
||||
new File(newFile.getParent()).mkdirs(); // Create directories for nested files
|
||||
try (FileOutputStream fos = new FileOutputStream(newFile, true)) {
|
||||
int len;
|
||||
while ((len = zis.read(buffer)) > 0) {
|
||||
fos.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
zipEntry = zis.getNextEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue