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 */ 16 package com.android.timezone.distro; 17 18 import junit.framework.TestCase; 19 20 import android.system.Os; 21 import android.system.OsConstants; 22 import android.system.StructStat; 23 24 import libcore.testing.io.TestIoUtils; 25 26 import java.io.File; 27 import java.io.FileNotFoundException; 28 import java.io.FileOutputStream; 29 import java.io.IOException; 30 import java.nio.charset.StandardCharsets; 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import java.util.Collections; 34 import java.util.List; 35 36 /** 37 * Tests for {@link FileUtils}. 38 */ 39 public class FileUtilsTest extends TestCase { 40 41 private List<File> testFiles = new ArrayList<>(); 42 43 @Override tearDown()44 public void tearDown() throws Exception { 45 // Delete in reverse order 46 Collections.reverse(testFiles); 47 for (File tempFile : testFiles) { 48 tempFile.delete(); 49 } 50 super.tearDown(); 51 } 52 testDeleteRecursive()53 public void testDeleteRecursive() throws Exception { 54 File dir = createTempDir(); 55 File file1 = createRegularFile(dir, "file1"); 56 File file2 = createRegularFile(dir, "file2"); 57 File symLink1 = createSymlink(file1, dir, "symLink1"); 58 File subDir = createDir(dir, "subDir"); 59 File file3 = createRegularFile(subDir, "subFile1"); 60 File file4 = createRegularFile(subDir, "subFile2"); 61 File symLink2 = createSymlink(file1, dir, "symLink2"); 62 63 File otherDir = createTempDir(); 64 File otherFile = createRegularFile(otherDir, "kept"); 65 66 File linkToOtherDir = createSymlink(otherDir, subDir, "linkToOtherDir"); 67 File linkToOtherFile = createSymlink(otherFile, subDir, "linkToOtherFile"); 68 69 File[] filesToDelete = { dir, file1, file2, symLink1, subDir, file3, file4, symLink2, 70 linkToOtherDir, linkToOtherFile }; 71 File[] filesToKeep = { otherDir, otherFile }; 72 assertFilesExist(filesToDelete); 73 assertFilesExist(filesToKeep); 74 75 FileUtils.deleteRecursive(dir); 76 assertFilesDoNotExist(filesToDelete); 77 assertFilesExist(filesToKeep); 78 } 79 testIsSymlink()80 public void testIsSymlink() throws Exception { 81 File dir = createTempDir(); 82 File subDir = createDir(dir, "subDir"); 83 File fileInSubDir = createRegularFile(subDir, "fileInSubDir"); 84 File normalFile = createRegularFile(dir, "normalFile"); 85 File symlinkToDir = createSymlink(subDir, dir, "symlinkToDir"); 86 File symlinkToFile = createSymlink(fileInSubDir, dir, "symlinkToFile"); 87 File symlinkToFileInSubDir = createSymlink(fileInSubDir, dir, "symlinkToFileInSubDir"); 88 File normalFileViaSymlink = new File(symlinkToDir, "normalFile"); 89 90 assertFalse(FileUtils.isSymlink(dir)); 91 assertFalse(FileUtils.isSymlink(subDir)); 92 assertFalse(FileUtils.isSymlink(fileInSubDir)); 93 assertFalse(FileUtils.isSymlink(normalFile)); 94 assertTrue(FileUtils.isSymlink(symlinkToDir)); 95 assertTrue(FileUtils.isSymlink(symlinkToFile)); 96 assertTrue(FileUtils.isSymlink(symlinkToFileInSubDir)); 97 assertFalse(FileUtils.isSymlink(normalFileViaSymlink)); 98 } 99 testCreateSubFile()100 public void testCreateSubFile() throws Exception { 101 File dir1 = createTempDir().getCanonicalFile(); 102 103 File actualSubFile = FileUtils.createSubFile(dir1, "file"); 104 assertEquals(new File(dir1, "file"), actualSubFile); 105 106 File existingSubFile = createRegularFile(dir1, "file"); 107 actualSubFile = FileUtils.createSubFile(dir1, "file"); 108 assertEquals(existingSubFile, actualSubFile); 109 110 File existingSubDir = createDir(dir1, "subdir"); 111 actualSubFile = FileUtils.createSubFile(dir1, "subdir"); 112 assertEquals(existingSubDir, actualSubFile); 113 114 assertCreateSubFileThrows(dir1, "../file"); 115 assertCreateSubFileThrows(dir1, "../../file"); 116 assertCreateSubFileThrows(dir1, "../otherdir/file"); 117 118 File dir2 = createTempDir().getCanonicalFile(); 119 createSymlink(dir2, dir1, "symlinkToDir2"); 120 assertCreateSubFileThrows(dir1, "symlinkToDir2"); 121 122 assertCreateSubFileThrows(dir1, "symlinkToDir2/fileInSymlinkedDir"); 123 124 createRegularFile(dir1, "symlinkToDir2/fileInSymlinkedDir"); 125 assertCreateSubFileThrows(dir1, "symlinkToDir2/fileInSymlinkedDir"); 126 } 127 testEnsureDirectoryExists()128 public void testEnsureDirectoryExists() throws Exception { 129 File dir = createTempDir(); 130 131 File exists = new File(dir, "exists"); 132 assertTrue(exists.mkdir()); 133 assertTrue(exists.setReadable(true /* readable */, true /* ownerOnly */)); 134 assertTrue(exists.setExecutable(true /* readable */, true /* ownerOnly */)); 135 FileUtils.ensureDirectoriesExist(exists, true /* makeWorldReadable */); 136 assertDirExistsAndIsAccessible(exists, false /* requireWorldReadable */); 137 138 File subDir = new File(dir, "subDir"); 139 assertFalse(subDir.exists()); 140 FileUtils.ensureDirectoriesExist(subDir, true /* makeWorldReadable */); 141 assertDirExistsAndIsAccessible(subDir, true /* requireWorldReadable */); 142 143 File one = new File(dir, "one"); 144 File two = new File(one, "two"); 145 File three = new File(two, "three"); 146 FileUtils.ensureDirectoriesExist(three, true /* makeWorldReadable */); 147 assertDirExistsAndIsAccessible(one, true /* requireWorldReadable */); 148 assertDirExistsAndIsAccessible(two, true /* requireWorldReadable */); 149 assertDirExistsAndIsAccessible(three, true /* requireWorldReadable */); 150 } 151 testEnsureDirectoriesExist_noPermissions()152 public void testEnsureDirectoriesExist_noPermissions() throws Exception { 153 File dir = createTempDir(); 154 assertDirExistsAndIsAccessible(dir, false /* requireWorldReadable */); 155 156 File unreadableSubDir = new File(dir, "unreadableSubDir"); 157 assertTrue(unreadableSubDir.mkdir()); 158 assertTrue(unreadableSubDir.setReadable(false /* readable */, true /* ownerOnly */)); 159 assertTrue(unreadableSubDir.setExecutable(false /* readable */, true /* ownerOnly */)); 160 161 File toCreate = new File(unreadableSubDir, "toCreate"); 162 try { 163 FileUtils.ensureDirectoriesExist(toCreate, true /* makeWorldReadable */); 164 fail(); 165 } catch (IOException expected) { 166 } 167 assertDirExistsAndIsAccessible(dir, false /* requireWorldReadable */); 168 assertFalse(unreadableSubDir.canRead() && unreadableSubDir.canExecute()); 169 assertFalse(toCreate.exists()); 170 } 171 testEnsureFileDoesNotExist()172 public void testEnsureFileDoesNotExist() throws Exception { 173 File dir = createTempDir(); 174 175 FileUtils.ensureFileDoesNotExist(new File(dir, "doesNotExist")); 176 177 File exists1 = createRegularFile(dir, "exists1"); 178 assertTrue(exists1.exists()); 179 FileUtils.ensureFileDoesNotExist(exists1); 180 assertFalse(exists1.exists()); 181 182 exists1 = createRegularFile(dir, "exists1"); 183 File symlink = createSymlink(exists1, dir, "symlinkToFile"); 184 assertTrue(symlink.exists()); 185 FileUtils.ensureFileDoesNotExist(symlink); 186 assertFalse(symlink.exists()); 187 assertTrue(exists1.exists()); 188 189 // Only files and symlinks supported. We do not delete directories. 190 File emptyDir = createTempDir(); 191 try { 192 FileUtils.ensureFileDoesNotExist(emptyDir); 193 fail(); 194 } catch (IOException expected) { 195 } 196 assertTrue(emptyDir.exists()); 197 } 198 199 // This test does not pass when run as root because root can do anything even if the permissions 200 // don't allow it. testEnsureFileDoesNotExist_noPermission()201 public void testEnsureFileDoesNotExist_noPermission() throws Exception { 202 File dir = createTempDir(); 203 204 File protectedDir = createDir(dir, "protected"); 205 File undeletable = createRegularFile(protectedDir, "undeletable"); 206 assertTrue(protectedDir.setWritable(false)); 207 assertTrue(undeletable.exists()); 208 try { 209 FileUtils.ensureFileDoesNotExist(undeletable); 210 fail(); 211 } catch (IOException expected) { 212 } finally { 213 assertTrue(protectedDir.setWritable(true)); // Reset for clean-up 214 } 215 assertTrue(undeletable.exists()); 216 } 217 testCheckFilesExist()218 public void testCheckFilesExist() throws Exception { 219 File dir = createTempDir(); 220 createRegularFile(dir, "exists1"); 221 File subDir = createDir(dir, "subDir"); 222 createRegularFile(subDir, "exists2"); 223 assertTrue(FileUtils.filesExist(dir, "exists1", "subDir/exists2")); 224 assertFalse(FileUtils.filesExist(dir, "doesNotExist")); 225 assertFalse(FileUtils.filesExist(dir, "subDir/doesNotExist")); 226 } 227 testReadBytes()228 public void testReadBytes() throws Exception { 229 File dir = createTempDir(); 230 231 try { 232 FileUtils.readBytes(new File(dir, "doesNotExist"), 0); 233 fail(); 234 } catch (IllegalArgumentException expected) { 235 } 236 237 try { 238 FileUtils.readBytes(new File(dir, "doesNotExist"), 10); 239 fail(); 240 } catch (FileNotFoundException expected) { 241 } 242 243 byte[] contents = "One\nTwo\nThree\n".getBytes(StandardCharsets.US_ASCII); 244 File file = createFile(contents); 245 byte[] oneByte = FileUtils.readBytes(file, 1); 246 assertEquals(1, oneByte.length); 247 assertEquals(contents[0], oneByte[0]); 248 249 byte[] allBytes = FileUtils.readBytes(file, contents.length); 250 assertTrue(Arrays.equals(contents, allBytes)); 251 252 byte[] exhaustedFileRead = FileUtils.readBytes(file, contents.length + 1); 253 assertTrue(Arrays.equals(contents, exhaustedFileRead)); 254 } 255 testCreateEmptyFile()256 public void testCreateEmptyFile() throws Exception { 257 File dir = createTempDir(); 258 File file = new File(dir, "one"); 259 assertFalse(file.exists()); 260 FileUtils.createEmptyFile(file); 261 assertTrue(file.exists()); 262 assertEquals(0, file.length()); 263 } 264 testCreateEmptyFile_isDir()265 public void testCreateEmptyFile_isDir() throws Exception { 266 File dir = createTempDir(); 267 assertTrue(dir.exists()); 268 assertTrue(dir.isDirectory()); 269 270 try { 271 FileUtils.createEmptyFile(dir); 272 } catch (FileNotFoundException expected) { 273 } 274 assertTrue(dir.exists()); 275 assertTrue(dir.isDirectory()); 276 } 277 testCreateEmptyFile_truncatesExisting()278 public void testCreateEmptyFile_truncatesExisting() throws Exception { 279 File dir = createTempDir(); 280 File file = new File(dir, "one"); 281 282 try (FileOutputStream fos = new FileOutputStream(file)) { 283 fos.write(new byte[1000]); 284 } 285 assertTrue(file.exists()); 286 assertEquals(1000, file.length()); 287 288 FileUtils.createEmptyFile(file); 289 assertTrue(file.exists()); 290 assertEquals(0, file.length()); 291 } 292 createFile(byte[] contents)293 private File createFile(byte[] contents) throws IOException { 294 File file = File.createTempFile(getClass().getSimpleName(), ".txt"); 295 try (FileOutputStream fos = new FileOutputStream(file)) { 296 fos.write(contents); 297 } 298 return file; 299 } 300 createSymlink(File file, File symlinkDir, String symlinkName)301 private File createSymlink(File file, File symlinkDir, String symlinkName) throws Exception { 302 assertTrue(file.exists()); 303 304 File symlink = new File(symlinkDir, symlinkName); 305 Os.symlink(file.getAbsolutePath(), symlink.getAbsolutePath()); 306 testFiles.add(symlink); 307 return symlink; 308 } 309 assertCreateSubFileThrows(File parentDir, String name)310 private static void assertCreateSubFileThrows(File parentDir, String name) { 311 try { 312 FileUtils.createSubFile(parentDir, name); 313 fail(); 314 } catch (IOException expected) { 315 assertTrue(expected.getMessage().contains("must exist beneath")); 316 } 317 } 318 assertFilesDoNotExist(File... files)319 private static void assertFilesDoNotExist(File... files) { 320 for (File f : files) { 321 assertFalse(f + " unexpectedly exists", f.exists()); 322 } 323 } 324 assertFilesExist(File... files)325 private static void assertFilesExist(File... files) { 326 for (File f : files) { 327 assertTrue(f + " expected to exist", f.exists()); 328 } 329 } 330 assertDirExistsAndIsAccessible(File dir, boolean requireWorldReadable)331 private static void assertDirExistsAndIsAccessible(File dir, boolean requireWorldReadable) 332 throws Exception { 333 assertTrue(dir.exists() && dir.isDirectory() && dir.canRead() && dir.canExecute()); 334 335 String path = dir.getCanonicalPath(); 336 StructStat sb = Os.stat(path); 337 int mask = OsConstants.S_IXUSR | OsConstants.S_IRUSR; 338 if (requireWorldReadable) { 339 mask = mask | OsConstants.S_IXGRP | OsConstants.S_IRGRP 340 | OsConstants.S_IXOTH | OsConstants.S_IROTH; 341 } 342 assertTrue("Permission mask required: " + Integer.toOctalString(mask), 343 (sb.st_mode & mask) == mask); 344 } 345 createTempDir()346 private File createTempDir() { 347 final String tempPrefix = getClass().getSimpleName(); 348 File tempDir = TestIoUtils.createTemporaryDirectory(tempPrefix); 349 testFiles.add(tempDir); 350 return tempDir; 351 } 352 createDir(File parentDir, String name)353 private File createDir(File parentDir, String name) { 354 File dir = new File(parentDir, name); 355 assertTrue(dir.mkdir()); 356 testFiles.add(dir); 357 return dir; 358 } 359 createRegularFile(File dir, String name)360 private File createRegularFile(File dir, String name) throws Exception { 361 File file = new File(dir, name); 362 try (FileOutputStream fos = new FileOutputStream(file)) { 363 fos.write("Hello".getBytes()); 364 } 365 testFiles.add(file); 366 return file; 367 } 368 } 369