1/* 2 * Copyright (C) 2015 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 */ 16package libcore.tzdata.update; 17 18import junit.framework.TestCase; 19 20import java.io.File; 21import java.io.FileOutputStream; 22import java.io.IOException; 23import libcore.tzdata.update.tools.TzDataBundleBuilder; 24 25/** 26 * Tests for {@link libcore.tzdata.update.TzDataBundleInstaller}. 27 */ 28public class TzDataBundleInstallerTest extends TestCase { 29 30 private static final File SYSTEM_ZONE_INFO_FILE = new File("/system/usr/share/zoneinfo/tzdata"); 31 32 private TzDataBundleInstaller installer; 33 private File tempDir; 34 private File testInstallDir; 35 36 @Override 37 public void setUp() throws Exception { 38 super.setUp(); 39 tempDir = createDirectory("tempDir"); 40 testInstallDir = createDirectory("testInstall"); 41 installer = new TzDataBundleInstaller("TzDataBundleInstallerTest", testInstallDir); 42 } 43 44 private static File createDirectory(String prefix) throws IOException { 45 File dir = File.createTempFile(prefix, ""); 46 assertTrue(dir.delete()); 47 assertTrue(dir.mkdir()); 48 return dir; 49 } 50 51 @Override 52 public void tearDown() throws Exception { 53 if (testInstallDir.exists()) { 54 FileUtils.deleteRecursive(testInstallDir); 55 } 56 if (tempDir.exists()) { 57 FileUtils.deleteRecursive(tempDir); 58 } 59 super.tearDown(); 60 } 61 62 /** Tests the first update on a device */ 63 public void testSuccessfulFirstUpdate() throws Exception { 64 ConfigBundle tzData = createValidTzDataBundle("2030a"); 65 66 assertTrue(install(tzData)); 67 assertTzDataInstalled(tzData); 68 } 69 70 /** 71 * Tests an update on a device when there is a prior update already applied. 72 */ 73 public void testSuccessfulFollowOnUpdate() throws Exception { 74 ConfigBundle tzData1 = createValidTzDataBundle("2030a"); 75 assertTrue(install(tzData1)); 76 assertTzDataInstalled(tzData1); 77 78 ConfigBundle tzData2 = createValidTzDataBundle("2030b"); 79 assertTrue(install(tzData2)); 80 assertTzDataInstalled(tzData2); 81 } 82 83 84 /** Tests that a bundle with a missing file will not update the content. */ 85 public void testMissingRequiredBundleFile() throws Exception { 86 ConfigBundle installedConfigBundle = createValidTzDataBundle("2030a"); 87 assertTrue(install(installedConfigBundle)); 88 assertTzDataInstalled(installedConfigBundle); 89 90 ConfigBundle incompleteUpdate = 91 createValidTzDataBundleBuilder("2030b").clearBionicTzData().buildUnvalidated(); 92 assertFalse(install(incompleteUpdate)); 93 assertTzDataInstalled(installedConfigBundle); 94 } 95 96 /** 97 * Tests that an update will be unpacked even if there is a partial update from a previous run. 98 */ 99 public void testInstallWithWorkingDir() throws Exception { 100 File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME); 101 assertTrue(workingDir.mkdir()); 102 createFile(new File(workingDir, "myFile")); 103 104 ConfigBundle tzData = createValidTzDataBundle("2030a"); 105 assertTrue(install(tzData)); 106 assertTzDataInstalled(tzData); 107 } 108 109 /** 110 * Tests that a bundle with a checksum entry that references a missing file will not update the 111 * content. 112 */ 113 public void testChecksumBundleEntry_fileMissing() throws Exception { 114 ConfigBundle badUpdate = 115 createValidTzDataBundleBuilder("2030b") 116 .addChecksum("/fileDoesNotExist", 1234) 117 .build(); 118 assertFalse(install(badUpdate)); 119 assertNoContentInstalled(); 120 } 121 122 /** 123 * Tests that a bundle with a checksum entry with a bad checksum will not update the 124 * content. 125 */ 126 public void testChecksumBundleEntry_incorrectChecksum() throws Exception { 127 File fileToChecksum = SYSTEM_ZONE_INFO_FILE; 128 long badChecksum = FileUtils.calculateChecksum(fileToChecksum) + 1; 129 ConfigBundle badUpdate = 130 createValidTzDataBundleBuilder("2030b") 131 .clearChecksumEntries() 132 .addChecksum(fileToChecksum.getPath(), badChecksum) 133 .build(); 134 assertFalse(install(badUpdate)); 135 assertNoContentInstalled(); 136 } 137 138 private boolean install(ConfigBundle configBundle) throws Exception { 139 return installer.install(configBundle.getBundleBytes()); 140 } 141 142 private ConfigBundle createValidTzDataBundle(String tzDataVersion) 143 throws IOException { 144 return createValidTzDataBundleBuilder(tzDataVersion).build(); 145 } 146 147 private TzDataBundleBuilder createValidTzDataBundleBuilder(String tzDataVersion) 148 throws IOException { 149 150 // The file to include in the installation-time checksum check. 151 File fileToChecksum = SYSTEM_ZONE_INFO_FILE; 152 long checksum = FileUtils.calculateChecksum(fileToChecksum); 153 154 File bionicTzData = new File(tempDir, "zoneinfo"); 155 createFile(bionicTzData); 156 157 File icuData = new File(tempDir, "icudata"); 158 createFile(icuData); 159 160 return new TzDataBundleBuilder() 161 .addChecksum(fileToChecksum.getPath(), checksum) 162 .setTzDataVersion(tzDataVersion) 163 .addBionicTzData(bionicTzData) 164 .addIcuTzData(icuData); 165 } 166 167 private void assertTzDataInstalled(ConfigBundle expectedTzData) throws Exception { 168 assertTrue(testInstallDir.exists()); 169 170 File currentTzDataDir = new File(testInstallDir, TzDataBundleInstaller.CURRENT_TZ_DATA_DIR_NAME); 171 assertTrue(currentTzDataDir.exists()); 172 173 File checksumFile = new File(currentTzDataDir, ConfigBundle.CHECKSUMS_FILE_NAME); 174 assertTrue(checksumFile.exists()); 175 176 File versionFile = new File(currentTzDataDir, 177 ConfigBundle.TZ_DATA_VERSION_FILE_NAME); 178 assertTrue(versionFile.exists()); 179 180 File bionicFile = new File(currentTzDataDir, ConfigBundle.ZONEINFO_FILE_NAME); 181 assertTrue(bionicFile.exists()); 182 183 File icuFile = new File(currentTzDataDir, ConfigBundle.ICU_DATA_FILE_NAME); 184 assertTrue(icuFile.exists()); 185 186 // Also check no working directory is left lying around. 187 File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME); 188 assertFalse(workingDir.exists()); 189 } 190 191 private void assertNoContentInstalled() { 192 File currentTzDataDir = new File(testInstallDir, TzDataBundleInstaller.CURRENT_TZ_DATA_DIR_NAME); 193 assertFalse(currentTzDataDir.exists()); 194 195 // Also check no working directories are left lying around. 196 File workingDir = new File(testInstallDir, TzDataBundleInstaller.WORKING_DIR_NAME); 197 assertFalse(workingDir.exists()); 198 199 File oldDataDir = new File(testInstallDir, TzDataBundleInstaller.OLD_TZ_DATA_DIR_NAME); 200 assertFalse(oldDataDir.exists()); 201 } 202 203 private static void createFile(File file) { 204 try (FileOutputStream fos = new FileOutputStream(file)) { 205 fos.write('a'); 206 } catch (IOException e) { 207 fail(e.getMessage()); 208 } 209 } 210} 211