1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.util; 17 18 import com.android.tradefed.util.zip.CentralDirectoryInfo; 19 import com.android.tradefed.util.zip.EndCentralDirectoryInfo; 20 21 import java.io.FileInputStream; 22 import java.io.FileOutputStream; 23 import java.io.RandomAccessFile; 24 import java.util.Enumeration; 25 import java.util.zip.ZipEntry; 26 import java.util.zip.ZipOutputStream; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.util.List; 31 import java.util.zip.ZipFile; 32 import org.junit.AfterClass; 33 import org.junit.Assert; 34 import org.junit.BeforeClass; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 import org.junit.runners.JUnit4; 38 39 import static org.junit.Assert.fail; 40 41 /** {@link ZipUtilFuncTest} functional test.*/ 42 @RunWith(JUnit4.class) 43 public class ZipUtilFuncTest { 44 45 static private File sLargeFile = null; 46 static private File sTempDir = null; 47 static final private String OVERFLOW = "ffffffff"; 48 static final private String TEMPDIR = "Zip64Test"; 49 static final private int SENTRIES = 700; 50 51 @BeforeClass setUpBeforeClass()52 public static void setUpBeforeClass() throws Exception { 53 // Programmingly make one large zip file. 54 sLargeFile = FileUtil.createTempFile(TEMPDIR, ".zip"); 55 sTempDir = FileUtil.createTempDir(TEMPDIR); 56 createLargeZipFile(); 57 } 58 59 @AfterClass tearDownAfterClass()60 public static void tearDownAfterClass() throws Exception { 61 FileUtil.deleteFile(sLargeFile); 62 FileUtil.recursiveDelete(sTempDir); 63 } 64 65 /** Functional test for {@link EndCentralDirectoryInfo} to ensure the number of entries are the 66 * same when use-zip64-in-partial-download is set and file is larger than 4GB. */ 67 @Test testCentralDirectoryInfoSize()68 public void testCentralDirectoryInfoSize() throws IOException { 69 EndCentralDirectoryInfo endCentralDirInfo = new EndCentralDirectoryInfo(sLargeFile, true); 70 Assert.assertEquals(SENTRIES, endCentralDirInfo.getEntryNumber()); 71 } 72 73 /** 74 * Functional test for {@link EndCentralDirectoryInfo} to ensure the central directory offset 75 * is overflow when use-zip64-in-partial-download is not set and file is larger than 4GB. 76 */ 77 @Test testCentralDirectoryOffsetWithoutUseZip64()78 public void testCentralDirectoryOffsetWithoutUseZip64() throws IOException { 79 EndCentralDirectoryInfo endCentralDirInfo = new EndCentralDirectoryInfo(sLargeFile, false); 80 Assert.assertEquals(OVERFLOW, Long.toHexString(endCentralDirInfo.getCentralDirOffset())); 81 } 82 83 /** 84 * Functional test for {@link EndCentralDirectoryInfo} to ensure the central directory data 85 * is good when use-zip64-in-partial-download is set and file is larger than 4GB. 86 */ 87 @Test testCentralDirectoryInfos()88 public void testCentralDirectoryInfos() throws IOException { 89 EndCentralDirectoryInfo endCentralDirInfo = new EndCentralDirectoryInfo(sLargeFile, true); 90 91 // Use ZipFile to make ensure the contents are equal. 92 ZipFile zipFile = new ZipFile(sLargeFile.getAbsolutePath()); 93 List<CentralDirectoryInfo> zipEntries = 94 ZipUtil.getZipCentralDirectoryInfos( 95 sLargeFile, 96 endCentralDirInfo, 97 endCentralDirInfo.getCentralDirOffset(), 98 true); 99 Assert.assertEquals(zipFile.size(), endCentralDirInfo.getEntryNumber()); 100 for (CentralDirectoryInfo entry : zipEntries) { 101 Assert.assertFalse(validateCentralDirectoryInfo(entry)); 102 } 103 validateCentralDirectoryInfos(zipFile, zipEntries); 104 } 105 106 /** 107 * Functional test for {@link EndCentralDirectoryInfo} to ensure getting expected exception 108 * when use-zip64-in-partial-download is set and file is larger than 4GB. 109 */ 110 @Test testCentralDirectoryInfosWithoutUseZip64()111 public void testCentralDirectoryInfosWithoutUseZip64() throws IOException { 112 EndCentralDirectoryInfo endCentralDirInfo = new EndCentralDirectoryInfo(sLargeFile, false); 113 try { 114 ZipUtil.getZipCentralDirectoryInfos( 115 sLargeFile, 116 endCentralDirInfo, 117 endCentralDirInfo.getCentralDirOffset(), 118 false); 119 fail("Should have thrown an exception."); 120 } catch (IOException expected) { 121 Assert.assertEquals( 122 "Invalid central directory info for zip file is found.", expected.getMessage()); 123 } 124 } 125 126 /** Helper to create a large zip file with 700 entries, each entry is with 7MB size. */ createLargeZipFile()127 private static void createLargeZipFile() throws IOException { 128 FileOutputStream fos = new FileOutputStream(sLargeFile); 129 ZipOutputStream zos = new ZipOutputStream(fos); 130 // This sets the compression level to STORED, ie, uncompressed 131 zos.setLevel(ZipOutputStream.STORED); 132 133 long largeSize = 7000000; 134 for (int i = 1 ; i <= SENTRIES ; i++) { 135 File srcDir = FileUtil.createTempDir("src", sTempDir); 136 String testLargeFile = String.format("testLargeFile_%s", i); 137 File localLargeFile = new File(srcDir, testLargeFile); 138 localLargeFile.createNewFile(); 139 RandomAccessFile raf = new RandomAccessFile(localLargeFile, "rw"); 140 raf.setLength(largeSize); 141 raf.close(); 142 addToZipFile(localLargeFile.getAbsolutePath(), zos); 143 } 144 zos.close(); 145 fos.close(); 146 } 147 148 /** Helper to create a file. */ addToZipFile(String fileName, ZipOutputStream zos)149 private static void addToZipFile(String fileName, ZipOutputStream zos) throws IOException { 150 File file = new File(fileName); 151 FileInputStream fis = new FileInputStream(file); 152 ZipEntry zipEntry = new ZipEntry(fileName); 153 zos.putNextEntry(zipEntry); 154 byte[] bytes = new byte[1024]; 155 int length; 156 while ((length = fis.read(bytes)) >= 0) { 157 zos.write(bytes, 0, length); 158 } 159 zos.closeEntry(); 160 fis.close(); 161 } 162 163 /** Helper to validate the {@link CentralDirectoryInfo} that the data is overflow or not. */ validateCentralDirectoryInfo(CentralDirectoryInfo entry)164 private boolean validateCentralDirectoryInfo(CentralDirectoryInfo entry) { 165 return (Long.toHexString(entry.getCompressedSize()).equals(OVERFLOW) || 166 Long.toHexString(entry.getUncompressedSize()).equals(OVERFLOW) || 167 Long.toHexString(entry.getLocalHeaderOffset()).equals(OVERFLOW)); 168 } 169 170 /** Helper to validate the {@link CentralDirectoryInfo} objects are equal. */ validateCentralDirectoryInfos( ZipFile zipFile, List<CentralDirectoryInfo> zipEntries)171 private void validateCentralDirectoryInfos( 172 ZipFile zipFile, List<CentralDirectoryInfo> zipEntries) { 173 for (CentralDirectoryInfo entry : zipEntries) { 174 boolean found = false; 175 Enumeration<? extends ZipEntry> entries = zipFile.entries(); 176 while (entries.hasMoreElements()) { 177 ZipEntry zipEntry = entries.nextElement(); 178 if (zipEntry.getName().equals(entry.getFileName())) { 179 found = true; 180 break; 181 } 182 } 183 Assert.assertTrue(found); 184 } 185 } 186 } 187