test/jdk/jdk/nio/zipfs/UpdateEntryTest.java
changeset 57842 abf6ee4c477c
child 58845 e492513d3630
equal deleted inserted replaced
57841:0094711309c3 57842:abf6ee4c477c
       
     1 /*
       
     2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 import org.testng.annotations.Test;
       
    26 
       
    27 import java.io.IOException;
       
    28 import java.io.InputStream;
       
    29 import java.io.OutputStream;
       
    30 import java.nio.charset.StandardCharsets;
       
    31 import java.nio.file.FileSystem;
       
    32 import java.nio.file.FileSystems;
       
    33 import java.nio.file.Files;
       
    34 import java.nio.file.Path;
       
    35 import java.util.Arrays;
       
    36 import java.util.spi.ToolProvider;
       
    37 import java.util.zip.CRC32;
       
    38 import java.util.zip.ZipEntry;
       
    39 import java.util.zip.ZipFile;
       
    40 import java.util.zip.ZipOutputStream;
       
    41 
       
    42 import static org.testng.Assert.*;
       
    43 
       
    44 /**
       
    45  * @test
       
    46  * @bug 8229887
       
    47  * @summary Validate ZIP FileSystem can replace existing STORED and DEFLATED entries
       
    48  * @modules jdk.zipfs
       
    49  * @run testng UpdateEntryTest
       
    50  */
       
    51 @Test
       
    52 public class UpdateEntryTest {
       
    53 
       
    54     private static final Path HERE = Path.of(".");
       
    55 
       
    56     // Use the ToolProvider interface for accessing the jar tool
       
    57     private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
       
    58             .orElseThrow(() -> new RuntimeException("jar tool not found")
       
    59             );
       
    60 
       
    61     /**
       
    62      * Represents an entry in a ZIP file. An entry encapsulates a name, a
       
    63      * compression method, and its contents/data.
       
    64      */
       
    65     static class Entry {
       
    66         private final String name;
       
    67         private final int method;
       
    68         private final byte[] bytes;
       
    69 
       
    70         Entry(String name, int method, String contents) {
       
    71             this.name = name;
       
    72             this.method = method;
       
    73             this.bytes = contents.getBytes(StandardCharsets.UTF_8);
       
    74         }
       
    75 
       
    76         static Entry of(String name, int method, String contents) {
       
    77             return new Entry(name, method, contents);
       
    78         }
       
    79 
       
    80         /**
       
    81          * Returns a new Entry with the same name and compression method as this
       
    82          * Entry but with the given content.
       
    83          */
       
    84         Entry content(String contents) {
       
    85             return new Entry(name, method, contents);
       
    86         }
       
    87 
       
    88         /**
       
    89          * Writes this entry to the given ZIP output stream.
       
    90          */
       
    91         ZipEntry put(ZipOutputStream zos) throws IOException {
       
    92             ZipEntry e = new ZipEntry(name);
       
    93             e.setMethod(method);
       
    94             e.setTime(System.currentTimeMillis());
       
    95             if (method == ZipEntry.STORED) {
       
    96                 var crc = new CRC32();
       
    97                 crc.update(bytes);
       
    98                 e.setCrc(crc.getValue());
       
    99                 e.setSize(bytes.length);
       
   100             }
       
   101             zos.putNextEntry(e);
       
   102             zos.write(bytes);
       
   103             return e;
       
   104         }
       
   105     }
       
   106 
       
   107     /**
       
   108      * Validate that you can replace an existing entry in a JAR file that
       
   109      * was added with the STORED(no-compression) option
       
   110      */
       
   111     public void testReplaceStoredEntry() throws IOException {
       
   112         String jarFileName = "updateStoredEntry.jar";
       
   113         String storedFileName = "storedFile.txt";
       
   114         String replacedValue = "bar";
       
   115         Path zipFile = Path.of(jarFileName);
       
   116 
       
   117         // Create JAR file with a STORED(non-compressed) entry
       
   118         Files.writeString(Path.of(storedFileName), "foobar");
       
   119         int rc = JAR_TOOL.run(System.out, System.err,
       
   120                 "cM0vf", jarFileName, storedFileName);
       
   121 
       
   122         // Replace the STORED entry
       
   123         try (FileSystem fs = FileSystems.newFileSystem(zipFile)) {
       
   124             Files.writeString(fs.getPath(storedFileName), replacedValue);
       
   125         }
       
   126         Entry e1 = Entry.of(storedFileName, ZipEntry.STORED, replacedValue);
       
   127         verify(zipFile, e1);
       
   128     }
       
   129 
       
   130     /**
       
   131      * Test updating an entry that is STORED (not compressed)
       
   132      */
       
   133     public void test1() throws IOException {
       
   134         Entry e1 = Entry.of("foo", ZipEntry.STORED, "hello");
       
   135         Entry e2 = Entry.of("bar", ZipEntry.STORED, "world");
       
   136         test(e1, e2);
       
   137     }
       
   138 
       
   139     /**
       
   140      * Test updating an entry that is DEFLATED (compressed)
       
   141      */
       
   142     public void test2() throws IOException {
       
   143         Entry e1 = Entry.of("foo", ZipEntry.DEFLATED, "hello");
       
   144         Entry e2 = Entry.of("bar", ZipEntry.STORED, "world");
       
   145         test(e1, e2);
       
   146     }
       
   147 
       
   148     private void test(Entry e1, Entry e2) throws IOException {
       
   149         Path zipfile = Files.createTempFile(HERE, "test", "zip");
       
   150 
       
   151         // create zip file
       
   152         try (OutputStream out = Files.newOutputStream(zipfile);
       
   153              ZipOutputStream zos = new ZipOutputStream(out)) {
       
   154             e1.put(zos);
       
   155             e2.put(zos);
       
   156         }
       
   157 
       
   158         verify(zipfile, e1, e2);
       
   159 
       
   160         String newContents = "hi";
       
   161 
       
   162         // replace contents of e1
       
   163         try (FileSystem fs = FileSystems.newFileSystem(zipfile)) {
       
   164             Path foo = fs.getPath(e1.name);
       
   165             Files.writeString(foo, newContents);
       
   166         }
       
   167 
       
   168         verify(zipfile, e1.content(newContents), e2);
       
   169     }
       
   170 
       
   171 
       
   172     /**
       
   173      * Verify that the given path is a zip files containing exactly the
       
   174      * given entries.
       
   175      */
       
   176     private static void verify(Path zipfile, Entry... entries) throws IOException {
       
   177         // check entries with zip API
       
   178         try (ZipFile zf = new ZipFile(zipfile.toFile())) {
       
   179             // check entry count
       
   180             assertTrue(zf.size() == entries.length);
       
   181 
       
   182             // check compression method and content of each entry
       
   183             for (Entry e : entries) {
       
   184                 ZipEntry ze = zf.getEntry(e.name);
       
   185                 assertTrue(ze != null);
       
   186                 assertTrue(ze.getMethod() == e.method);
       
   187                 try (InputStream in = zf.getInputStream(ze)) {
       
   188                     byte[] bytes = in.readAllBytes();
       
   189                     assertTrue(Arrays.equals(bytes, e.bytes));
       
   190                 }
       
   191             }
       
   192         }
       
   193 
       
   194         // check entries with FileSystem API
       
   195         try (FileSystem fs = FileSystems.newFileSystem(zipfile)) {
       
   196             // check entry count
       
   197             Path top = fs.getPath("/");
       
   198             long count = Files.find(top, Integer.MAX_VALUE,
       
   199                     (path, attrs) -> attrs.isRegularFile()).count();
       
   200             assertTrue(count == entries.length);
       
   201 
       
   202             // check content of each entry
       
   203             for (Entry e : entries) {
       
   204                 Path file = fs.getPath(e.name);
       
   205                 byte[] bytes = Files.readAllBytes(file);
       
   206                 assertTrue(Arrays.equals(bytes, e.bytes));
       
   207             }
       
   208         }
       
   209     }
       
   210 }