--- /dev/null 2019-09-22 18:39:15.000000000 -0400 +++ new/test/jdk/jdk/nio/zipfs/CompressionModeTest.java 2019-09-22 18:39:14.000000000 -0400 @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import org.testng.annotations.*; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import static java.lang.String.format; +import static java.util.stream.Collectors.joining; +import static org.testng.Assert.*; + +/** + * @test + * @bug 8231093 + * @summary Test Zip FS compressionMethod property + * @modules jdk.zipfs + * @run testng CompressionModeTest + */ +public class CompressionModeTest { + + private static final Path HERE = Path.of("."); + + /** + * Number of ZIP entries to create + */ + private static final int ENTRIES = 5; + + /** + * Value used for creating the required entries in a ZIP or JAR file + */ + private static final String ZIP_FILE_VALUE = "US Open 2019"; + private static final byte[] ZIP_FILE_ENTRY = + ZIP_FILE_VALUE.getBytes(StandardCharsets.UTF_8); + + private static final SecureRandom random = new SecureRandom(); + + /** + * Validate that you can create a ZIP file with and without compression + * and that entries are created with the specified compression method. + * + * @param env Properties used for creating the ZIP Filesystem + * @param compression Indicates whether the files are DEFLATED(default) + * or STORED + * @throws Exception If an error occurs during the creation, verification or + * deletion of the ZIP file + */ + @Test(dataProvider = "validCompressionMethods", enabled = true) + public void testValidCompressionMehods(Map env, + int compression) throws Exception { + + System.out.printf("ZIP FS Map = %s, Compression mode= %s%n ", + formatMap(env), compression); + + Path zipfile = generatePath(HERE, "test", ".zip"); + Files.deleteIfExists(zipfile); + createZipFile(zipfile, env, ENTRIES); + verify(zipfile, compression, ENTRIES, 0); + Files.deleteIfExists(zipfile); + } + + /** + * Validate that an IllegalArgumentException is thrown when an invalid + * value is specified for the compressionMethod property. + * + * @param env Properties used for creating the ZIP Filesystem + * @throws Exception if an error occurs other than the expected + * IllegalArgumentException + */ + @Test(dataProvider = "invalidCompressionMethod") + public void testInvalidCompressionMethod(Map env) throws Exception { + System.out.printf("ZIP FS Map = %s%n ", formatMap(env)); + Path zipfile = generatePath(HERE, "test", ".zip"); + Files.deleteIfExists(zipfile); + assertThrows(IllegalArgumentException.class, () -> + createZipFile(zipfile, env, ENTRIES)); + Files.deleteIfExists(zipfile); + } + + /** + * Create a ZIP File System using the specified properties and a ZIP file + * with the specified number of entries + * + * @param zipFile Path to the ZIP File to create + * @param env Properties used for creating the ZIP Filesystem + * @param entries Number of entries to add to the ZIP File + * @throws IOException If an error occurs while creating the ZIP file + */ + private void createZipFile(Path zipFile, Map env, + int entries) throws IOException { + System.out.printf("Creating file = %s%n", zipFile); + try (FileSystem zipfs = + FileSystems.newFileSystem(zipFile, env)) { + + for (int i = 0; i < entries; i++) { + Files.writeString(zipfs.getPath("Entry-" + i), ZIP_FILE_VALUE); + } + } + } + + /** + * DataProvider used to validate that you can create a ZIP file with and + * without compression. + */ + @DataProvider(name = "validCompressionMethods") + private Object[][] validCompressionMethods() { + return new Object[][]{ + {Map.of("create", "true"), ZipEntry.DEFLATED}, + {Map.of("create", "true", "noCompression", "true"), + ZipEntry.STORED}, + {Map.of("create", "true", "noCompression", "false"), + ZipEntry.DEFLATED}, + {Map.of("create", "true", "compressionMethod", "STORED"), + ZipEntry.STORED}, + {Map.of("create", "true", "compressionMethod", "DEFLATED"), + ZipEntry.DEFLATED}, + {Map.of("create", "true", "compressionMethod", "stored"), + ZipEntry.STORED}, + {Map.of("create", "true", "compressionMethod", "deflated"), + ZipEntry.DEFLATED} + + }; + } + + /** + * DataProvider used to validate that an IllegalArgumentException is thrown + * for an invalid value for the compressionMethod property. + */ + @DataProvider(name = "invalidCompressionMethod") + private Object[][] invalidCompressionMethod() { + HashMap map = new HashMap<>(); + map.put("create", "true"); + map.put("compressionMethod", null); + return new Object[][]{ + {map}, + {Map.of("create", "true", "compressionMethod", "")}, + {Map.of("create", "true", "compressionMethod", "invalid")} + + }; + } + + /** + * Verify that the given path is a ZIP file containing the + * expected entries. + * + * @param zipfile ZIP file to be validated + * @param method Expected Compression method: STORED or DEFLATED + * @param entries Number of expected entries + * @param start Starting number for verifying entries + * @throws Exception If an error occurs while examining the ZIP file + */ + private static void verify(Path zipfile, int method, int entries, + int start) throws Exception { + // check entries with ZIP API + try (ZipFile zf = new ZipFile(zipfile.toFile())) { + // check entry count + assertEquals(entries, zf.size()); + + // check compression method and content of each entry + for (int i = start; i < entries; i++) { + ZipEntry ze = zf.getEntry("Entry-" + i); + assertNotNull(ze); + assertEquals(method, ze.getMethod()); + try (InputStream is = zf.getInputStream(ze)) { + byte[] bytes = is.readAllBytes(); + assertTrue(Arrays.equals(bytes, ZIP_FILE_ENTRY)); + } + } + } + // check entries with FileSystem API + try (FileSystem fs = FileSystems.newFileSystem(zipfile)) { + + // check entry count + Path top = fs.getPath("/"); + long count = Files.find(top, Integer.MAX_VALUE, (path, attrs) -> + attrs.isRegularFile() || (attrs.isDirectory() && + path.getFileName() != null && + path.getFileName().toString().equals("META-INF"))) + .count(); + assertEquals(entries, count); + + // check content of each entry + for (int i = start; i < entries; i++) { + Path file = fs.getPath("Entry-" + i); + byte[] bytes = Files.readAllBytes(file); + assertTrue(Arrays.equals(bytes, ZIP_FILE_ENTRY)); + } + } + } + + /** + * Generate a temporary file Path + * + * @param dir Directory used to create the path + * @param prefix The prefix string used to create the path + * @param suffix The suffix string used to create the path + * @return Path that was generated + */ + private static Path generatePath(Path dir, String prefix, String suffix) { + long n = random.nextLong(); + String s = prefix + Long.toUnsignedString(n) + suffix; + Path name = dir.getFileSystem().getPath(s); + // the generated name should be a simple file name + if (name.getParent() != null) + throw new IllegalArgumentException("Invalid prefix or suffix"); + return dir.resolve(name); + } + + /** + * Utility method to return a formatted String of the key:value entries for + * a Map + * + * @param env Map to format + * @return Formatted string of the Map entries + */ + private static String formatMap(Map env) { + return env.entrySet().stream() + .map(e -> format("(%s:%s)", e.getKey(), e.getValue())) + .collect(joining(", ")); + } +}