diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2017-07-04 08:55:25 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-07-04 08:55:25 +0000 |
commit | 702f599857e13697805ba8477437038f87a27206 (patch) | |
tree | 43261b5e7a4095257d2ee44a70a260b9f0af5982 /tzdata | |
parent | 3a7685f11b892f3b5faa631bd3061db5ae70f605 (diff) | |
parent | bf92f093d6001e7dba496d2120493c5377e30b50 (diff) | |
download | libcore-702f599857e13697805ba8477437038f87a27206.tar.gz |
Merge "Remove unused copy of TimeZoneDistroInstaller"
Diffstat (limited to 'tzdata')
3 files changed, 0 insertions, 1116 deletions
diff --git a/tzdata/update2/Android.mk b/tzdata/update2/Android.mk deleted file mode 100644 index de4f18edeeb..00000000000 --- a/tzdata/update2/Android.mk +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (C) 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) - -# The classes needed to handle installation of time zone updates. -include $(CLEAR_VARS) -LOCAL_MODULE := tzdata_update2 -LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := $(call all-java-files-under, src/main) -LOCAL_JAVACFLAGS := -encoding UTF-8 -LOCAL_JAVA_LIBRARIES := time_zone_distro -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_JAVA_LIBRARY) - -# Tests for tzdata_update2 code -include $(CLEAR_VARS) -LOCAL_MODULE := tzdata_update2-tests -LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := $(call all-java-files-under, src/test) -LOCAL_JAVACFLAGS := -encoding UTF-8 -LOCAL_STATIC_JAVA_LIBRARIES := time_zone_distro time_zone_distro_tools tzdata_update2 tzdata-testing junit -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistroInstaller.java b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistroInstaller.java deleted file mode 100644 index 29ec3909fef..00000000000 --- a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistroInstaller.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package libcore.tzdata.update2; - -import com.android.timezone.distro.DistroException; -import com.android.timezone.distro.DistroVersion; -import com.android.timezone.distro.FileUtils; -import com.android.timezone.distro.StagedDistroOperation; -import com.android.timezone.distro.TimeZoneDistro; - -import android.util.Slog; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import libcore.util.TimeZoneFinder; -import libcore.util.ZoneInfoDB; - -/** - * A distro-validation / extraction class. Separate from the services code that uses it for easier - * testing. This class is not thread-safe: callers are expected to handle mutual exclusion. - */ -public class TimeZoneDistroInstaller { - /** {@link #stageInstallWithErrorCode(TimeZoneDistro)} result code: Success. */ - public final static int INSTALL_SUCCESS = 0; - /** {@link #stageInstallWithErrorCode(TimeZoneDistro)} result code: Distro corrupt. */ - public final static int INSTALL_FAIL_BAD_DISTRO_STRUCTURE = 1; - /** {@link #stageInstallWithErrorCode(TimeZoneDistro)} result code: Distro version incompatible. */ - public final static int INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION = 2; - /** {@link #stageInstallWithErrorCode(TimeZoneDistro)} result code: Distro rules too old for device. */ - public final static int INSTALL_FAIL_RULES_TOO_OLD = 3; - /** {@link #stageInstallWithErrorCode(TimeZoneDistro)} result code: Distro content failed validation. */ - public final static int INSTALL_FAIL_VALIDATION_ERROR = 4; - - // This constant must match one in system/core/tzdatacheck.cpp. - private static final String STAGED_TZ_DATA_DIR_NAME = "staged"; - // This constant must match one in system/core/tzdatacheck.cpp. - private static final String CURRENT_TZ_DATA_DIR_NAME = "current"; - private static final String WORKING_DIR_NAME = "working"; - private static final String OLD_TZ_DATA_DIR_NAME = "old"; - - /** - * The name of the file in the staged directory used to indicate a staged uninstallation. - */ - // This constant must match one in system/core/tzdatacheck.cpp. - // VisibleForTesting. - public static final String UNINSTALL_TOMBSTONE_FILE_NAME = "STAGED_UNINSTALL_TOMBSTONE"; - - private final String logTag; - private final File systemTzDataFile; - private final File oldStagedDataDir; - private final File stagedTzDataDir; - private final File currentTzDataDir; - private final File workingDir; - - public TimeZoneDistroInstaller(String logTag, File systemTzDataFile, File installDir) { - this.logTag = logTag; - this.systemTzDataFile = systemTzDataFile; - oldStagedDataDir = new File(installDir, OLD_TZ_DATA_DIR_NAME); - stagedTzDataDir = new File(installDir, STAGED_TZ_DATA_DIR_NAME); - currentTzDataDir = new File(installDir, CURRENT_TZ_DATA_DIR_NAME); - workingDir = new File(installDir, WORKING_DIR_NAME); - } - - // VisibleForTesting - File getOldStagedDataDir() { - return oldStagedDataDir; - } - - // VisibleForTesting - File getStagedTzDataDir() { - return stagedTzDataDir; - } - - // VisibleForTesting - File getCurrentTzDataDir() { - return currentTzDataDir; - } - - // VisibleForTesting - File getWorkingDir() { - return workingDir; - } - - /** - * Stage an install of the supplied content, to be installed the next time the device boots. - * - * <p>Errors during unpacking or staging will throw an {@link IOException}. - * If the distro content is invalid this method returns {@code false}. - * If the installation completed successfully this method returns {@code true}. - */ - public boolean install(TimeZoneDistro distro) throws IOException { - int result = stageInstallWithErrorCode(distro); - return result == INSTALL_SUCCESS; - } - - /** - * Stage an install of the supplied content, to be installed the next time the device boots. - * - * <p>Errors during unpacking or staging will throw an {@link IOException}. - * Returns {@link #INSTALL_SUCCESS} or an error code. - */ - public int stageInstallWithErrorCode(TimeZoneDistro distro) throws IOException { - if (oldStagedDataDir.exists()) { - FileUtils.deleteRecursive(oldStagedDataDir); - } - if (workingDir.exists()) { - FileUtils.deleteRecursive(workingDir); - } - - Slog.i(logTag, "Unpacking / verifying time zone update"); - try { - unpackDistro(distro, workingDir); - - DistroVersion distroVersion; - try { - distroVersion = readDistroVersion(workingDir); - } catch (DistroException e) { - Slog.i(logTag, "Invalid distro version: " + e.getMessage()); - return INSTALL_FAIL_BAD_DISTRO_STRUCTURE; - } - if (distroVersion == null) { - Slog.i(logTag, "Update not applied: Distro version could not be loaded"); - return INSTALL_FAIL_BAD_DISTRO_STRUCTURE; - } - if (!DistroVersion.isCompatibleWithThisDevice(distroVersion)) { - Slog.i(logTag, "Update not applied: Distro format version check failed: " - + distroVersion); - return INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION; - } - - if (!checkDistroDataFilesExist(workingDir)) { - Slog.i(logTag, "Update not applied: Distro is missing required data file(s)"); - return INSTALL_FAIL_BAD_DISTRO_STRUCTURE; - } - - if (!checkDistroRulesNewerThanSystem(systemTzDataFile, distroVersion)) { - Slog.i(logTag, "Update not applied: Distro rules version check failed"); - return INSTALL_FAIL_RULES_TOO_OLD; - } - - // Validate the tzdata file. - File zoneInfoFile = new File(workingDir, TimeZoneDistro.TZDATA_FILE_NAME); - ZoneInfoDB.TzData tzData = ZoneInfoDB.TzData.loadTzData(zoneInfoFile.getPath()); - if (tzData == null) { - Slog.i(logTag, "Update not applied: " + zoneInfoFile + " could not be loaded"); - return INSTALL_FAIL_VALIDATION_ERROR; - } - try { - tzData.validate(); - } catch (IOException e) { - Slog.i(logTag, "Update not applied: " + zoneInfoFile + " failed validation", e); - return INSTALL_FAIL_VALIDATION_ERROR; - } finally { - tzData.close(); - } - - // Validate the tzlookup.xml file. - File tzLookupFile = new File(workingDir, TimeZoneDistro.TZLOOKUP_FILE_NAME); - if (!tzLookupFile.exists()) { - Slog.i(logTag, "Update not applied: " + tzLookupFile + " does not exist"); - return INSTALL_FAIL_BAD_DISTRO_STRUCTURE; - } - try { - TimeZoneFinder timeZoneFinder = - TimeZoneFinder.createInstance(tzLookupFile.getPath()); - timeZoneFinder.validate(); - } catch (IOException e) { - Slog.i(logTag, "Update not applied: " + tzLookupFile + " failed validation", e); - return INSTALL_FAIL_VALIDATION_ERROR; - } - - // TODO(nfuller): Add validity checks for ICU data / canarying before applying. - // http://b/31008728 - - Slog.i(logTag, "Applying time zone update"); - FileUtils.makeDirectoryWorldAccessible(workingDir); - - // Check if there is already a staged install or uninstall and remove it if there is. - if (!stagedTzDataDir.exists()) { - Slog.i(logTag, "Nothing to unstage at " + stagedTzDataDir); - } else { - Slog.i(logTag, "Moving " + stagedTzDataDir + " to " + oldStagedDataDir); - // Move stagedTzDataDir out of the way in one operation so we can't partially delete - // the contents. - FileUtils.rename(stagedTzDataDir, oldStagedDataDir); - } - - // Move the workingDir to be the new staged directory. - Slog.i(logTag, "Moving " + workingDir + " to " + stagedTzDataDir); - FileUtils.rename(workingDir, stagedTzDataDir); - Slog.i(logTag, "Install staged: " + stagedTzDataDir + " successfully created"); - return INSTALL_SUCCESS; - } finally { - deleteBestEffort(oldStagedDataDir); - deleteBestEffort(workingDir); - } - } - - /** - * Stage an uninstall of the current timezone update in /data which, on reboot, will return the - * device to using data from /system. Returns {@code true} if staging the uninstallation was - * successful, {@code false} if there was nothing installed in /data to uninstall. If there was - * something else staged it will be replaced by this call. - * - * <p>Errors encountered during uninstallation will throw an {@link IOException}. - */ - public boolean stageUninstall() throws IOException { - Slog.i(logTag, "Uninstalling time zone update"); - - if (oldStagedDataDir.exists()) { - // If we can't remove this, an exception is thrown and we don't continue. - FileUtils.deleteRecursive(oldStagedDataDir); - } - if (workingDir.exists()) { - FileUtils.deleteRecursive(workingDir); - } - - try { - // Check if there is already an install or uninstall staged and remove it. - if (!stagedTzDataDir.exists()) { - Slog.i(logTag, "Nothing to unstage at " + stagedTzDataDir); - } else { - Slog.i(logTag, "Moving " + stagedTzDataDir + " to " + oldStagedDataDir); - // Move stagedTzDataDir out of the way in one operation so we can't partially delete - // the contents. - FileUtils.rename(stagedTzDataDir, oldStagedDataDir); - } - - // If there's nothing actually installed, there's nothing to uninstall so no need to - // stage anything. - if (!currentTzDataDir.exists()) { - Slog.i(logTag, "Nothing to uninstall at " + currentTzDataDir); - return false; - } - - // Stage an uninstall in workingDir. - FileUtils.ensureDirectoriesExist(workingDir, true /* makeWorldReadable */); - FileUtils.createEmptyFile(new File(workingDir, UNINSTALL_TOMBSTONE_FILE_NAME)); - - // Move the workingDir to be the new staged directory. - Slog.i(logTag, "Moving " + workingDir + " to " + stagedTzDataDir); - FileUtils.rename(workingDir, stagedTzDataDir); - Slog.i(logTag, "Uninstall staged: " + stagedTzDataDir + " successfully created"); - - return true; - } finally { - deleteBestEffort(oldStagedDataDir); - deleteBestEffort(workingDir); - } - } - - /** - * Reads the currently installed distro version. Returns {@code null} if there is no distro - * installed. - * - * @throws IOException if there was a problem reading data from /data - * @throws DistroException if there was a problem with the installed distro format/structure - */ - public DistroVersion getInstalledDistroVersion() throws DistroException, IOException { - if (!currentTzDataDir.exists()) { - return null; - } - return readDistroVersion(currentTzDataDir); - } - - /** - * Reads information about any currently staged distro operation. Returns {@code null} if there - * is no distro operation staged. - * - * @throws IOException if there was a problem reading data from /data - * @throws DistroException if there was a problem with the staged distro format/structure - */ - public StagedDistroOperation getStagedDistroOperation() throws DistroException, IOException { - if (!stagedTzDataDir.exists()) { - return null; - } - if (new File(stagedTzDataDir, UNINSTALL_TOMBSTONE_FILE_NAME).exists()) { - return StagedDistroOperation.uninstall(); - } else { - return StagedDistroOperation.install(readDistroVersion(stagedTzDataDir)); - } - } - - /** - * Reads the timezone rules version present in /system. i.e. the version that would be present - * after a factory reset. - * - * @throws IOException if there was a problem reading data - */ - public String getSystemRulesVersion() throws IOException { - return readSystemRulesVersion(systemTzDataFile); - } - - private void deleteBestEffort(File dir) { - if (dir.exists()) { - Slog.i(logTag, "Deleting " + dir); - try { - FileUtils.deleteRecursive(dir); - } catch (IOException e) { - // Logged but otherwise ignored. - Slog.w(logTag, "Unable to delete " + dir, e); - } - } - } - - private void unpackDistro(TimeZoneDistro distro, File targetDir) throws IOException { - Slog.i(logTag, "Unpacking update content to: " + targetDir); - distro.extractTo(targetDir); - } - - private boolean checkDistroDataFilesExist(File unpackedContentDir) throws IOException { - Slog.i(logTag, "Verifying distro contents"); - return FileUtils.filesExist(unpackedContentDir, - TimeZoneDistro.TZDATA_FILE_NAME, - TimeZoneDistro.ICU_DATA_FILE_NAME); - } - - private DistroVersion readDistroVersion(File distroDir) throws DistroException, IOException { - Slog.i(logTag, "Reading distro format version: " + distroDir); - File distroVersionFile = new File(distroDir, TimeZoneDistro.DISTRO_VERSION_FILE_NAME); - if (!distroVersionFile.exists()) { - throw new DistroException("No distro version file found: " + distroVersionFile); - } - byte[] versionBytes = - FileUtils.readBytes(distroVersionFile, DistroVersion.DISTRO_VERSION_FILE_LENGTH); - return DistroVersion.fromBytes(versionBytes); - } - - /** - * Returns true if the the distro IANA rules version is >= system IANA rules version. - */ - private boolean checkDistroRulesNewerThanSystem( - File systemTzDataFile, DistroVersion distroVersion) throws IOException { - - // We only check the /system tzdata file and assume that other data like ICU is in sync. - // There is a CTS test that checks ICU and bionic/libcore are in sync. - Slog.i(logTag, "Reading /system rules version"); - String systemRulesVersion = readSystemRulesVersion(systemTzDataFile); - - String distroRulesVersion = distroVersion.rulesVersion; - // canApply = distroRulesVersion >= systemRulesVersion - boolean canApply = distroRulesVersion.compareTo(systemRulesVersion) >= 0; - if (!canApply) { - Slog.i(logTag, "Failed rules version check: distroRulesVersion=" - + distroRulesVersion + ", systemRulesVersion=" + systemRulesVersion); - } else { - Slog.i(logTag, "Passed rules version check: distroRulesVersion=" - + distroRulesVersion + ", systemRulesVersion=" + systemRulesVersion); - } - return canApply; - } - - private String readSystemRulesVersion(File systemTzDataFile) throws IOException { - if (!systemTzDataFile.exists()) { - Slog.i(logTag, "tzdata file cannot be found in /system"); - throw new FileNotFoundException("system tzdata does not exist: " + systemTzDataFile); - } - return ZoneInfoDB.TzData.getRulesVersion(systemTzDataFile); - } -} diff --git a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneDistroInstallerTest.java b/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneDistroInstallerTest.java deleted file mode 100644 index 51f95534bf4..00000000000 --- a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneDistroInstallerTest.java +++ /dev/null @@ -1,707 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package libcore.tzdata.update2; - -import com.android.timezone.distro.DistroVersion; -import com.android.timezone.distro.FileUtils; -import com.android.timezone.distro.StagedDistroOperation; -import com.android.timezone.distro.TimeZoneDistro; -import com.android.timezone.distro.tools.TimeZoneDistroBuilder; - -import junit.framework.TestCase; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; -import libcore.io.IoUtils; -import libcore.tzdata.testing.ZoneInfoTestHelper; - -import static org.junit.Assert.assertArrayEquals; - -/** - * Tests for {@link TimeZoneDistroInstaller}. - */ -public class TimeZoneDistroInstallerTest extends TestCase { - - // OLDER_RULES_VERSION < SYSTEM_RULES_VERSION < NEW_RULES_VERSION < NEWER_RULES_VERSION - private static final String OLDER_RULES_VERSION = "2030a"; - private static final String SYSTEM_RULES_VERSION = "2030b"; - private static final String NEW_RULES_VERSION = "2030c"; - private static final String NEWER_RULES_VERSION = "2030d"; - - private TimeZoneDistroInstaller installer; - private File tempDir; - private File testInstallDir; - private File testSystemTzDataDir; - - @Override - public void setUp() throws Exception { - super.setUp(); - tempDir = createUniqueDirectory(null, "tempDir"); - testInstallDir = createSubDirectory(tempDir, "testInstall"); - testSystemTzDataDir = createSubDirectory(tempDir, "testSystemTzData"); - - // Create a file to represent the tzdata file in the /system partition of the device. - File testSystemTzDataFile = new File(testSystemTzDataDir, "tzdata"); - byte[] systemTzDataBytes = createTzData(SYSTEM_RULES_VERSION); - createFile(testSystemTzDataFile, systemTzDataBytes); - - installer = new TimeZoneDistroInstaller( - "TimeZoneDistroInstallerTest", testSystemTzDataFile, testInstallDir); - } - - /** - * Creates a unique temporary directory. rootDir can be null, in which case the directory will - * be created beneath the directory pointed to by the java.io.tmpdir system property. - */ - private static File createUniqueDirectory(File rootDir, String prefix) throws Exception { - File dir = File.createTempFile(prefix, "", rootDir); - assertTrue(dir.delete()); - assertTrue(dir.mkdir()); - return dir; - } - - private static File createSubDirectory(File parent, String subDirName) { - File dir = new File(parent, subDirName); - assertTrue(dir.mkdir()); - return dir; - } - - @Override - public void tearDown() throws Exception { - if (tempDir.exists()) { - FileUtils.deleteRecursive(tempDir); - } - super.tearDown(); - } - - /** Tests the an update on a device will fail if the /system tzdata file cannot be found. */ - public void testStageInstallWithErrorCode_badSystemFile() throws Exception { - File doesNotExist = new File(testSystemTzDataDir, "doesNotExist"); - TimeZoneDistroInstaller brokenSystemInstaller = new TimeZoneDistroInstaller( - "TimeZoneDistroInstallerTest", doesNotExist, testInstallDir); - byte[] distroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - - try { - brokenSystemInstaller.stageInstallWithErrorCode(new TimeZoneDistro(distroBytes)); - fail(); - } catch (IOException expected) {} - - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - } - - /** Tests the first successful update on a device */ - public void testStageInstallWithErrorCode_successfulFirstUpdate() throws Exception { - byte[] distroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distroBytes))); - assertInstallDistroStaged(distroBytes); - assertNoInstalledDistro(); - } - - /** - * Tests we can install an update the same version as is in /system. - */ - public void testStageInstallWithErrorCode_successfulFirstUpdate_sameVersionAsSystem() - throws Exception { - byte[] distroBytes = createValidTimeZoneDistroBytes(SYSTEM_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distroBytes))); - assertInstallDistroStaged(distroBytes); - assertNoInstalledDistro(); - } - - /** - * Tests we cannot install an update older than the version in /system. - */ - public void testStageInstallWithErrorCode_unsuccessfulFirstUpdate_olderVersionThanSystem() - throws Exception { - byte[] distroBytes = createValidTimeZoneDistroBytes(OLDER_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distroBytes))); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - } - - /** - * Tests an update on a device when there is a prior update already staged. - */ - public void testStageInstallWithErrorCode_successfulFollowOnUpdate_newerVersion() - throws Exception { - byte[] distro1Bytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distro1Bytes))); - assertInstallDistroStaged(distro1Bytes); - - byte[] distro2Bytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 2); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distro2Bytes))); - assertInstallDistroStaged(distro2Bytes); - - byte[] distro3Bytes = createValidTimeZoneDistroBytes(NEWER_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distro3Bytes))); - assertInstallDistroStaged(distro3Bytes); - assertNoInstalledDistro(); - } - - /** - * Tests an update on a device when there is a prior update already applied, but the follow - * on update is older than in /system. - */ - public void testStageInstallWithErrorCode_unsuccessfulFollowOnUpdate_olderVersion() - throws Exception { - byte[] distro1Bytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 2); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distro1Bytes))); - assertInstallDistroStaged(distro1Bytes); - - byte[] distro2Bytes = createValidTimeZoneDistroBytes(OLDER_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distro2Bytes))); - assertInstallDistroStaged(distro1Bytes); - assertNoInstalledDistro(); - } - - /** Tests that a distro with a missing tzdata file will not update the content. */ - public void testStageInstallWithErrorCode_missingTzDataFile() throws Exception { - byte[] stagedDistroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(stagedDistroBytes))); - assertInstallDistroStaged(stagedDistroBytes); - - byte[] incompleteDistroBytes = - createValidTimeZoneDistroBuilder(NEWER_RULES_VERSION, 1) - .clearTzDataForTests() - .buildUnvalidatedBytes(); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE, - installer.stageInstallWithErrorCode(new TimeZoneDistro(incompleteDistroBytes))); - assertInstallDistroStaged(stagedDistroBytes); - assertNoInstalledDistro(); - } - - /** Tests that a distro with a missing ICU file will not update the content. */ - public void testStageInstallWithErrorCode_missingIcuFile() throws Exception { - byte[] stagedDistroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(stagedDistroBytes))); - assertInstallDistroStaged(stagedDistroBytes); - - byte[] incompleteDistroBytes = - createValidTimeZoneDistroBuilder(NEWER_RULES_VERSION, 1) - .clearIcuDataForTests() - .buildUnvalidatedBytes(); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE, - installer.stageInstallWithErrorCode(new TimeZoneDistro(incompleteDistroBytes))); - assertInstallDistroStaged(stagedDistroBytes); - assertNoInstalledDistro(); - } - - /** Tests that a distro with a missing tzlookup file will not update the content. */ - public void testStageInstallWithErrorCode_missingTzLookupFile() throws Exception { - byte[] stagedDistroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(stagedDistroBytes))); - assertInstallDistroStaged(stagedDistroBytes); - - byte[] incompleteDistroBytes = - createValidTimeZoneDistroBuilder(NEWER_RULES_VERSION, 1) - .setTzLookupXml(null) - .buildUnvalidatedBytes(); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE, - installer.stageInstallWithErrorCode(new TimeZoneDistro(incompleteDistroBytes))); - assertInstallDistroStaged(stagedDistroBytes); - assertNoInstalledDistro(); - } - - /** Tests that a distro with a bad tzlookup file will not update the content. */ - public void testStageInstallWithErrorCode_badTzLookupFile() throws Exception { - byte[] stagedDistroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(stagedDistroBytes))); - assertInstallDistroStaged(stagedDistroBytes); - - byte[] incompleteDistroBytes = - createValidTimeZoneDistroBuilder(NEWER_RULES_VERSION, 1) - .setTzLookupXml("<foo />") - .buildUnvalidatedBytes(); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR, - installer.stageInstallWithErrorCode(new TimeZoneDistro(incompleteDistroBytes))); - assertInstallDistroStaged(stagedDistroBytes); - assertNoInstalledDistro(); - } - - /** - * Tests that an update will be unpacked even if there is a partial update from a previous run. - */ - public void testStageInstallWithErrorCode_withWorkingDir() throws Exception { - File workingDir = installer.getWorkingDir(); - assertTrue(workingDir.mkdir()); - createFile(new File(workingDir, "myFile"), new byte[] { 'a' }); - - byte[] distroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distroBytes))); - assertInstallDistroStaged(distroBytes); - assertNoInstalledDistro(); - } - - /** - * Tests that a distro without a distro version file will be rejected. - */ - public void testStageInstallWithErrorCode_withMissingDistroVersionFile() throws Exception { - // Create a distro without a version file. - byte[] distroBytes = createValidTimeZoneDistroBuilder(NEW_RULES_VERSION, 1) - .clearVersionForTests() - .buildUnvalidatedBytes(); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distroBytes))); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - } - - /** - * Tests that a distro with an newer distro version will be rejected. - */ - public void testStageInstallWithErrorCode_withNewerDistroVersion() throws Exception { - // Create a distro that will appear to be newer than the one currently supported. - byte[] distroBytes = createValidTimeZoneDistroBuilder(NEW_RULES_VERSION, 1) - .replaceFormatVersionForTests(2, 1) - .buildUnvalidatedBytes(); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distroBytes))); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - } - - /** - * Tests that a distro with a badly formed distro version will be rejected. - */ - public void testStageInstallWithErrorCode_withBadlyFormedDistroVersion() throws Exception { - // Create a distro that has an invalid major distro version. It should be 3 numeric - // characters, "." and 3 more numeric characters. - DistroVersion validDistroVersion = new DistroVersion(1, 1, NEW_RULES_VERSION, 1); - byte[] invalidFormatVersionBytes = validDistroVersion.toBytes(); - invalidFormatVersionBytes[0] = 'A'; - - TimeZoneDistro distro = createTimeZoneDistroWithVersionBytes(invalidFormatVersionBytes); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE, - installer.stageInstallWithErrorCode(distro)); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - } - - /** - * Tests that a distro with a badly formed revision will be rejected. - */ - public void testStageInstallWithErrorCode_withBadlyFormedRevision() throws Exception { - // Create a distro that has an invalid revision. It should be 3 numeric characters. - DistroVersion validDistroVersion = new DistroVersion(1, 1, NEW_RULES_VERSION, 1); - byte[] invalidRevisionBytes = validDistroVersion.toBytes(); - invalidRevisionBytes[invalidRevisionBytes.length - 3] = 'A'; - - TimeZoneDistro distro = createTimeZoneDistroWithVersionBytes(invalidRevisionBytes); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE, - installer.stageInstallWithErrorCode(distro)); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - } - - /** - * Tests that a distro with a badly formed rules version will be rejected. - */ - public void testStageInstallWithErrorCode_withBadlyFormedRulesVersion() throws Exception { - // Create a distro that has an invalid rules version. It should be in the form "2016c". - DistroVersion validDistroVersion = new DistroVersion(1, 1, NEW_RULES_VERSION, 1); - byte[] invalidRulesVersionBytes = validDistroVersion.toBytes(); - invalidRulesVersionBytes[invalidRulesVersionBytes.length - 6] = 'B'; - - TimeZoneDistro distro = createTimeZoneDistroWithVersionBytes(invalidRulesVersionBytes); - assertEquals( - TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE, - installer.stageInstallWithErrorCode(distro)); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - } - - public void testStageUninstall_noExistingDistro() throws Exception { - // To stage an uninstall, there would need to be installed rules. - assertFalse(installer.stageUninstall()); - - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - } - - public void testStageUninstall_existingStagedDataDistro() throws Exception { - // To stage an uninstall, we need to have some installed rules. - byte[] installedDistroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - simulateInstalledDistro(installedDistroBytes); - - File stagedDataDir = installer.getStagedTzDataDir(); - assertTrue(stagedDataDir.mkdir()); - - assertTrue(installer.stageUninstall()); - assertDistroUninstallStaged(); - assertInstalledDistro(installedDistroBytes); - } - - public void testStageUninstall_oldDirsAlreadyExists() throws Exception { - // To stage an uninstall, we need to have some installed rules. - byte[] installedDistroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - simulateInstalledDistro(installedDistroBytes); - - File oldStagedDataDir = installer.getOldStagedDataDir(); - assertTrue(oldStagedDataDir.mkdir()); - - File workingDir = installer.getWorkingDir(); - assertTrue(workingDir.mkdir()); - - assertTrue(installer.stageUninstall()); - - assertDistroUninstallStaged(); - assertFalse(workingDir.exists()); - assertFalse(oldStagedDataDir.exists()); - assertInstalledDistro(installedDistroBytes); - } - - public void testGetSystemRulesVersion() throws Exception { - assertEquals(SYSTEM_RULES_VERSION, installer.getSystemRulesVersion()); - } - - public void testGetInstalledDistroVersion() throws Exception { - // Check result when nothing installed. - assertNull(installer.getInstalledDistroVersion()); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - - // Now simulate there being an existing install active. - byte[] distroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - simulateInstalledDistro(distroBytes); - assertInstalledDistro(distroBytes); - - // Check result when something installed. - assertEquals(new TimeZoneDistro(distroBytes).getDistroVersion(), - installer.getInstalledDistroVersion()); - assertNoDistroOperationStaged(); - assertInstalledDistro(distroBytes); - } - - public void testGetStagedDistroOperation() throws Exception { - byte[] distro1Bytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - byte[] distro2Bytes = createValidTimeZoneDistroBytes(NEWER_RULES_VERSION, 1); - - // Check result when nothing staged. - assertNull(installer.getStagedDistroOperation()); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - - // Check result after unsuccessfully staging an uninstall. - // Can't stage an uninstall without an installed distro. - assertFalse(installer.stageUninstall()); - assertNull(installer.getStagedDistroOperation()); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - - // Check result after staging an install. - assertEquals( - TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distro1Bytes))); - StagedDistroOperation expectedStagedInstall = - StagedDistroOperation.install(new TimeZoneDistro(distro1Bytes).getDistroVersion()); - assertEquals(expectedStagedInstall, installer.getStagedDistroOperation()); - assertInstallDistroStaged(distro1Bytes); - assertNoInstalledDistro(); - - // Check result after unsuccessfully staging an uninstall (but after removing a staged - // install). Can't stage an uninstall without an installed distro. - assertFalse(installer.stageUninstall()); - assertNull(installer.getStagedDistroOperation()); - assertNoDistroOperationStaged(); - assertNoInstalledDistro(); - - // Now simulate there being an existing install active. - simulateInstalledDistro(distro1Bytes); - assertInstalledDistro(distro1Bytes); - - // Check state after successfully staging an uninstall. - assertTrue(installer.stageUninstall()); - StagedDistroOperation expectedStagedUninstall = StagedDistroOperation.uninstall(); - assertEquals(expectedStagedUninstall, installer.getStagedDistroOperation()); - assertDistroUninstallStaged(); - assertInstalledDistro(distro1Bytes); - - // Check state after successfully staging an install. - assertEquals(TimeZoneDistroInstaller.INSTALL_SUCCESS, - installer.stageInstallWithErrorCode(new TimeZoneDistro(distro2Bytes))); - StagedDistroOperation expectedStagedInstall2 = - StagedDistroOperation.install(new TimeZoneDistro(distro2Bytes).getDistroVersion()); - assertEquals(expectedStagedInstall2, installer.getStagedDistroOperation()); - assertInstallDistroStaged(distro2Bytes); - assertInstalledDistro(distro1Bytes); - } - - private static byte[] createValidTimeZoneDistroBytes( - String rulesVersion, int revision) throws Exception { - return createValidTimeZoneDistroBuilder(rulesVersion, revision).buildBytes(); - } - - private static TimeZoneDistroBuilder createValidTimeZoneDistroBuilder( - String rulesVersion, int revision) throws Exception { - - byte[] tzData = createTzData(rulesVersion); - byte[] icuData = new byte[] { 'a' }; - String tzlookupXml = "<timezones>\n" - + " <countryzones>\n" - + " <country code=\"us\">\n" - + " <id>America/New_York\"</id>\n" - + " <id>America/Los_Angeles</id>\n" - + " </country>\n" - + " <country code=\"gb\">\n" - + " <id>Europe/London</id>\n" - + " </country>\n" - + " </countryzones>\n" - + "</timezones>\n"; - DistroVersion distroVersion = new DistroVersion( - DistroVersion.CURRENT_FORMAT_MAJOR_VERSION, - DistroVersion.CURRENT_FORMAT_MINOR_VERSION, - rulesVersion, - revision); - return new TimeZoneDistroBuilder() - .setDistroVersion(distroVersion) - .setTzDataFile(tzData) - .setIcuDataFile(icuData) - .setTzLookupXml(tzlookupXml); - } - - private void assertInstallDistroStaged(byte[] expectedDistroBytes) throws Exception { - assertTrue(testInstallDir.exists()); - - File stagedTzDataDir = installer.getStagedTzDataDir(); - assertTrue(stagedTzDataDir.exists()); - - File distroVersionFile = - new File(stagedTzDataDir, TimeZoneDistro.DISTRO_VERSION_FILE_NAME); - assertTrue(distroVersionFile.exists()); - - File tzdataFile = new File(stagedTzDataDir, TimeZoneDistro.TZDATA_FILE_NAME); - assertTrue(tzdataFile.exists()); - - File icuFile = new File(stagedTzDataDir, TimeZoneDistro.ICU_DATA_FILE_NAME); - assertTrue(icuFile.exists()); - - File tzLookupFile = new File(stagedTzDataDir, TimeZoneDistro.TZLOOKUP_FILE_NAME); - assertTrue(tzLookupFile.exists()); - - // Assert getStagedDistroState() is reporting correctly. - StagedDistroOperation stagedDistroOperation = installer.getStagedDistroOperation(); - assertNotNull(stagedDistroOperation); - assertFalse(stagedDistroOperation.isUninstall); - assertEquals(new TimeZoneDistro(expectedDistroBytes).getDistroVersion(), - stagedDistroOperation.distroVersion); - - File expectedZipContentDir = createUniqueDirectory(tempDir, "expectedZipContent"); - new TimeZoneDistro(expectedDistroBytes).extractTo(expectedZipContentDir); - - assertContentsMatches( - new File(expectedZipContentDir, TimeZoneDistro.DISTRO_VERSION_FILE_NAME), - distroVersionFile); - assertContentsMatches( - new File(expectedZipContentDir, TimeZoneDistro.ICU_DATA_FILE_NAME), - icuFile); - assertContentsMatches( - new File(expectedZipContentDir, TimeZoneDistro.TZDATA_FILE_NAME), - tzdataFile); - assertContentsMatches( - new File(expectedZipContentDir, TimeZoneDistro.TZLOOKUP_FILE_NAME), - tzLookupFile); - assertFileCount(4, expectedZipContentDir); - - // Also check no working directory is left lying around. - File workingDir = installer.getWorkingDir(); - assertFalse(workingDir.exists()); - } - - private static void assertFileCount(int expectedFiles, File rootDir) throws Exception { - final List<Path> paths = new ArrayList<>(); - FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() { - @Override - public FileVisitResult visitFile(Path filePath, BasicFileAttributes attrs) - throws IOException { - paths.add(filePath); - return FileVisitResult.CONTINUE; - } - }; - Files.walkFileTree(rootDir.toPath(), visitor); - assertEquals("Found: " + paths, expectedFiles, paths.size()); - } - - private void assertContentsMatches(File expected, File actual) throws IOException { - byte[] actualBytes = IoUtils.readFileAsByteArray(actual.getPath()); - byte[] expectedBytes = IoUtils.readFileAsByteArray(expected.getPath()); - assertArrayEquals(expectedBytes, actualBytes); - } - - private void assertNoDistroOperationStaged() throws Exception { - assertNull(installer.getStagedDistroOperation()); - - File stagedTzDataDir = installer.getStagedTzDataDir(); - assertFalse(stagedTzDataDir.exists()); - - // Also check no working directories are left lying around. - File workingDir = installer.getWorkingDir(); - assertFalse(workingDir.exists()); - - File oldDataDir = installer.getOldStagedDataDir(); - assertFalse(oldDataDir.exists()); - } - - private void assertDistroUninstallStaged() throws Exception { - assertEquals(StagedDistroOperation.uninstall(), installer.getStagedDistroOperation()); - - File stagedTzDataDir = installer.getStagedTzDataDir(); - assertTrue(stagedTzDataDir.exists()); - assertTrue(stagedTzDataDir.isDirectory()); - - File uninstallTombstone = - new File(stagedTzDataDir, TimeZoneDistroInstaller.UNINSTALL_TOMBSTONE_FILE_NAME); - assertTrue(uninstallTombstone.exists()); - assertTrue(uninstallTombstone.isFile()); - - // Also check no working directories are left lying around. - File workingDir = installer.getWorkingDir(); - assertFalse(workingDir.exists()); - - File oldDataDir = installer.getOldStagedDataDir(); - assertFalse(oldDataDir.exists()); - } - - private void simulateInstalledDistro(byte[] distroBytes) throws Exception { - File currentTzDataDir = installer.getCurrentTzDataDir(); - assertFalse(currentTzDataDir.exists()); - assertTrue(currentTzDataDir.mkdir()); - new TimeZoneDistro(distroBytes).extractTo(currentTzDataDir); - } - - private void assertNoInstalledDistro() { - assertFalse(installer.getCurrentTzDataDir().exists()); - } - - private void assertInstalledDistro(byte[] distroBytes) throws Exception { - File currentTzDataDir = installer.getCurrentTzDataDir(); - assertTrue(currentTzDataDir.exists()); - File versionFile = new File(currentTzDataDir, TimeZoneDistro.DISTRO_VERSION_FILE_NAME); - assertTrue(versionFile.exists()); - byte[] expectedVersionBytes = new TimeZoneDistro(distroBytes).getDistroVersion().toBytes(); - byte[] actualVersionBytes = FileUtils.readBytes(versionFile, expectedVersionBytes.length); - assertArrayEquals(expectedVersionBytes, actualVersionBytes); - } - - private static byte[] createTzData(String rulesVersion) { - return new ZoneInfoTestHelper.TzDataBuilder() - .initializeToValid() - .setHeaderMagic("tzdata" + rulesVersion) - .build(); - } - - private static void createFile(File file, byte[] bytes) { - try (FileOutputStream fos = new FileOutputStream(file)) { - fos.write(bytes); - } catch (IOException e) { - fail(e.getMessage()); - } - } - - /** - * Creates a TimeZoneDistro containing arbitrary bytes in the version file. Used for testing - * distros with badly formed version info. - */ - private TimeZoneDistro createTimeZoneDistroWithVersionBytes(byte[] versionBytes) - throws Exception { - - // Extract a valid distro to a working dir. - byte[] distroBytes = createValidTimeZoneDistroBytes(NEW_RULES_VERSION, 1); - File workingDir = createUniqueDirectory(tempDir, "versionBytes"); - new TimeZoneDistro(distroBytes).extractTo(workingDir); - - // Modify the version file. - File versionFile = new File(workingDir, TimeZoneDistro.DISTRO_VERSION_FILE_NAME); - assertTrue(versionFile.exists()); - try (FileOutputStream fos = new FileOutputStream(versionFile, false /* append */)) { - fos.write(versionBytes); - } - - // Zip the distro back up again. - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (ZipOutputStream zos = new ZipOutputStream(baos)) { - Path workingDirPath = workingDir.toPath(); - Files.walkFileTree(workingDirPath, new SimpleFileVisitor<Path>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - byte[] bytes = IoUtils.readFileAsByteArray(file.toString()); - String relativeFileName = workingDirPath.relativize(file).toString(); - addZipEntry(zos, relativeFileName, bytes); - return FileVisitResult.CONTINUE; - } - }); - } - - return new TimeZoneDistro(baos.toByteArray()); - } - - private static void addZipEntry(ZipOutputStream zos, String name, byte[] content) - throws IOException { - ZipEntry zipEntry = new ZipEntry(name); - zipEntry.setSize(content.length); - zos.putNextEntry(zipEntry); - zos.write(content); - zos.closeEntry(); - } -} |