1 /* 2 * Copyright (C) 2010 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 static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.fail; 23 24 import org.junit.After; 25 import org.junit.Test; 26 import org.junit.runner.RunWith; 27 import org.junit.runners.JUnit4; 28 29 import java.io.ByteArrayInputStream; 30 import java.io.File; 31 import java.io.FileInputStream; 32 import java.io.IOException; 33 import java.io.InputStream; 34 import java.util.Collections; 35 import java.util.HashSet; 36 import java.util.Set; 37 38 /** Functional tests for {@link FileUtil}. */ 39 @RunWith(JUnit4.class) 40 public class FileUtilFuncTest { 41 private static final String PERMS_NONE = "---------"; 42 private static final String PERMS_GRWX = "rwxrwx---"; 43 private static final String ROOT_PERMS_GRWX = "rwxrwxr-x"; 44 private static final String DPERMS_NONE = "d" + PERMS_NONE; 45 private static final String DPERMS_GRWX = "d" + PERMS_GRWX; 46 private static final String ROOT_DPERMS_GRWX = "d" + ROOT_PERMS_GRWX; 47 48 private Set<File> mTempFiles = new HashSet<File>(); 49 50 @After tearDown()51 public void tearDown() throws Exception { 52 for (File file : mTempFiles) { 53 if (file != null && file.exists()) { 54 if (file.isDirectory()) { 55 FileUtil.recursiveDelete(file); 56 } else { 57 file.delete(); 58 } 59 } 60 } 61 } 62 63 /** 64 * Make sure that {@link FileUtil#mkdirsRWX} works when there are multiple levels of directories 65 */ 66 @Test testMkdirsRWX_multiLevel()67 public void testMkdirsRWX_multiLevel() throws IOException { 68 final int subdirCount = 5; 69 File tmpParentDir = createTempDir("foo"); 70 // create a hierarchy of directories to be created 71 File[] subdirs = new File[subdirCount]; 72 subdirs[0] = new File(tmpParentDir, "patient0"); 73 for (int i = 1; i < subdirCount; i++) { 74 subdirs[i] = new File(subdirs[i - 1], String.format("subdir%d", i)); 75 } 76 assertFalse(subdirs[0].exists()); 77 FileUtil.mkdirsRWX(subdirs[subdirs.length - 1]); 78 79 for (int i = 0; i < subdirCount; i++) { 80 assertTrue(subdirs[i].exists()); 81 assertUnixPerms(subdirs[i], DPERMS_GRWX, ROOT_DPERMS_GRWX); 82 } 83 } 84 85 /** Make sure that {@link FileUtil#mkdirsRWX} works in the basic case */ 86 @Test testMkdirsRWX_singleLevel()87 public void testMkdirsRWX_singleLevel() throws IOException { 88 File tmpParentDir = createTempDir("foo"); 89 File subdir = new File(tmpParentDir, "subdirectory"); 90 assertFalse(subdir.exists()); 91 FileUtil.mkdirsRWX(subdir); 92 assertTrue(subdir.exists()); 93 assertUnixPerms(subdir, DPERMS_GRWX, ROOT_DPERMS_GRWX); 94 } 95 96 /** 97 * Make sure that {@link FileUtil#mkdirsRWX} works when the directory to be touched already 98 * exists 99 */ 100 @Test testMkdirsRWX_preExisting()101 public void testMkdirsRWX_preExisting() throws IOException { 102 File tmpParentDir = createTempDir("foo"); 103 File subdir = new File(tmpParentDir, "subdirectory"); 104 subdir.mkdir(); 105 subdir.setExecutable(false, false); 106 subdir.setReadable(false, false); 107 subdir.setWritable(false, false); 108 109 assertUnixPerms(subdir, DPERMS_NONE, null); 110 FileUtil.mkdirsRWX(subdir); 111 assertTrue(subdir.exists()); 112 assertUnixPerms(subdir, DPERMS_GRWX, null); 113 } 114 115 /** Simple test for {@link FileUtil#chmodGroupRW(File)}. */ 116 @Test testChmodGroupRW()117 public void testChmodGroupRW() throws IOException { 118 File tmpFile = createTempFile("foo", "txt"); 119 tmpFile.setReadable(false); 120 tmpFile.setWritable(false); 121 FileUtil.chmodGroupRW(tmpFile); 122 assertTrue(tmpFile.canRead()); 123 assertTrue(tmpFile.canWrite()); 124 } 125 126 /** Simple test for {@link FileUtil#createTempDir(String)}. */ 127 @Test testCreateTempDir()128 public void testCreateTempDir() throws IOException { 129 File tmpDir = createTempDir("foo"); 130 assertTrue(tmpDir.exists()); 131 assertTrue(tmpDir.isDirectory()); 132 } 133 134 /** Simple test for {@link FileUtil#createTempDir(String, File)}. */ 135 @Test testCreateTempDir_parentFile()136 public void testCreateTempDir_parentFile() throws IOException { 137 File tmpParentDir = createTempDir("foo"); 138 File childDir = createTempDir("foochild", tmpParentDir); 139 assertTrue(childDir.exists()); 140 assertTrue(childDir.isDirectory()); 141 assertEquals(tmpParentDir.getAbsolutePath(), childDir.getParent()); 142 } 143 144 /** Simple test for {@link FileUtil#createTempFile(String, String)}. */ 145 @Test testCreateTempFile()146 public void testCreateTempFile() throws IOException { 147 File tmpFile = createTempFile("foo", ".txt"); 148 assertTrue(tmpFile.exists()); 149 assertTrue(tmpFile.isFile()); 150 assertTrue(tmpFile.getName().startsWith("foo")); 151 assertTrue(tmpFile.getName().endsWith(".txt")); 152 } 153 154 /** Simple test for {@link FileUtil#createTempFile(String, String, File)}. */ 155 @Test testCreateTempFile_parentDir()156 public void testCreateTempFile_parentDir() throws IOException { 157 File tmpParentDir = createTempDir("foo"); 158 159 File tmpFile = createTempFile("foo", ".txt", tmpParentDir); 160 assertTrue(tmpFile.exists()); 161 assertTrue(tmpFile.isFile()); 162 assertTrue(tmpFile.getName().startsWith("foo")); 163 assertTrue(tmpFile.getName().endsWith(".txt")); 164 assertEquals(tmpParentDir.getAbsolutePath(), tmpFile.getParent()); 165 } 166 167 /** Simple test method for {@link FileUtil#writeToFile(InputStream, File)}. */ 168 @Test testWriteToFile()169 public void testWriteToFile() throws IOException { 170 final String testContents = "this is the temp file test data"; 171 InputStream input = new ByteArrayInputStream(testContents.getBytes()); 172 File tmpFile = createTempFile("foo", ".txt"); 173 FileUtil.writeToFile(input, tmpFile); 174 String readContents = StreamUtil.getStringFromStream(new FileInputStream(tmpFile)); 175 assertEquals(testContents, readContents); 176 } 177 178 @Test testRecursiveDelete()179 public void testRecursiveDelete() throws IOException { 180 File tmpParentDir = createTempDir("foo"); 181 File childDir = createTempDir("foochild", tmpParentDir); 182 File subFile = createTempFile("foo", ".txt", childDir); 183 FileUtil.recursiveDelete(tmpParentDir); 184 assertFalse(subFile.exists()); 185 assertFalse(childDir.exists()); 186 assertFalse(tmpParentDir.exists()); 187 } 188 189 /** 190 * Test {@link FileUtil#recursiveCopy(File, File)} to recursively copy a directory to an 191 * existing, empty directory. 192 */ 193 @Test testRecursiveCopy()194 public void testRecursiveCopy() throws IOException { 195 // create source tree 196 File tmpParentDir = createTempDir("foo"); 197 File childDir = createTempDir("foochild", tmpParentDir); 198 File subFile = createTempFile("foo", ".txt", childDir); 199 FileUtil.writeToFile("foo", subFile); 200 // create empty destination directory 201 File destDir = createTempDir("dest"); 202 // invoke target method 203 FileUtil.recursiveCopy(tmpParentDir, destDir); 204 // check tree was copied 205 File subFileCopy = new File(destDir, String.format("%s%s%s", childDir.getName(), 206 File.separator, subFile.getName())); 207 assertTrue(subFileCopy.exists()); 208 assertTrue(FileUtil.compareFileContents(subFile, subFileCopy)); 209 } 210 211 /** 212 * Test {@link FileUtil#recursiveCopy(File, File)} to recursively copy a directory to a 213 * directory that does not exist. 214 */ 215 @Test testRecursiveCopyToNonexistentTarget()216 public void testRecursiveCopyToNonexistentTarget() throws IOException { 217 // create source tree 218 File tmpParentDir = createTempDir("foo"); 219 File childDir = createTempDir("foochild", tmpParentDir); 220 File subFile = createTempFile("foo", ".txt", childDir); 221 FileUtil.writeToFile("foo", subFile); 222 // generate an unique name for destination dir and make sure it doesn't exist 223 File destDir = createTempDir("dest"); 224 assertTrue(destDir.delete()); 225 assertFalse(destDir.exists()); 226 // invoke target method 227 FileUtil.recursiveCopy(tmpParentDir, destDir); 228 // check that destination was created and tree was copied 229 File subFileCopy = new File(destDir, String.format("%s%s%s", childDir.getName(), 230 File.separator, subFile.getName())); 231 assertTrue(destDir.exists()); 232 assertTrue(subFileCopy.exists()); 233 assertTrue(FileUtil.compareFileContents(subFile, subFileCopy)); 234 } 235 236 @Test testFindDirsUnder()237 public void testFindDirsUnder() throws IOException { 238 File absRootDir = createTempDir("rootDir"); 239 File relRootDir = new File(absRootDir.getName()); 240 File absSubDir1 = createTempDir("subdir1", absRootDir); 241 File relSubDir1 = new File(relRootDir.getName(), absSubDir1.getName()); 242 File absSubDir2 = createTempDir("subdir2", absRootDir); 243 File relSubDir2 = new File(relRootDir.getName(), absSubDir2.getName()); 244 File aFile = createTempFile("aFile", ".txt", absSubDir2); 245 246 HashSet<File> expected = new HashSet<File>(); 247 Collections.addAll(expected, relRootDir, relSubDir1, relSubDir2); 248 assertEquals(expected, FileUtil.findDirsUnder(absRootDir, null)); 249 expected.clear(); 250 File fakeRoot = new File("fakeRoot"); 251 Collections.addAll(expected, 252 new File(fakeRoot, relRootDir.getPath()), 253 new File(fakeRoot, relSubDir1.getPath()), 254 new File(fakeRoot, relSubDir2.getPath())); 255 assertEquals("Failed to apply a new relative parent", expected, 256 FileUtil.findDirsUnder(absRootDir, fakeRoot)); 257 assertEquals("found something when passing null as a root dir", 0, 258 FileUtil.findDirsUnder(null, null).size()); 259 try { 260 FileUtil.findDirsUnder(aFile, null); 261 fail("should have thrown an excpetion when passing in something that's not a dir"); 262 } catch (IllegalArgumentException e) { 263 assertTrue(true); 264 } 265 } 266 267 /** Test method for {@link FileUtil#createTempFileForRemote(String, File)}. */ 268 @Test testCreateTempFileForRemote()269 public void testCreateTempFileForRemote() throws IOException { 270 String remoteFilePath = "path/userdata.img"; 271 File tmpFile = FileUtil.createTempFileForRemote(remoteFilePath, null); 272 try { 273 assertTrue(tmpFile.getAbsolutePath().contains("userdata")); 274 assertTrue(tmpFile.getAbsolutePath().endsWith(".img")); 275 } finally { 276 FileUtil.deleteFile(tmpFile); 277 } 278 } 279 280 /** Test method for {@link FileUtil#createTempFileForRemote(String, File)} for a nested path. */ 281 @Test testCreateTempFileForRemote_nested()282 public void testCreateTempFileForRemote_nested() throws IOException { 283 String remoteFilePath = "path/2path/userdata.img"; 284 File tmpFile = FileUtil.createTempFileForRemote(remoteFilePath, null); 285 try { 286 assertTrue(tmpFile.getAbsolutePath().contains("userdata")); 287 assertTrue(tmpFile.getAbsolutePath().endsWith(".img")); 288 } finally { 289 FileUtil.deleteFile(tmpFile); 290 } 291 } 292 293 /** Test {@link FileUtil#createTempFileForRemote(String, File)} for file with no extension */ 294 @Test testCreateTempFileForRemote_noext()295 public void testCreateTempFileForRemote_noext() throws IOException { 296 String remoteFilePath = "path/2path/userddddmg"; 297 File tmpFile = FileUtil.createTempFileForRemote(remoteFilePath, null); 298 try { 299 assertTrue(tmpFile.getAbsolutePath().contains("userddddmg")); 300 } finally { 301 FileUtil.deleteFile(tmpFile); 302 } 303 } 304 305 /** Test {@link FileUtil#createTempFileForRemote(String, File)} for a too small prefix. */ 306 @Test testCreateTempFileForRemote_short()307 public void testCreateTempFileForRemote_short() throws IOException { 308 String remoteFilePath = "path/2path/us.img"; 309 File tmpFile = FileUtil.createTempFileForRemote(remoteFilePath, null); 310 try { 311 assertTrue(tmpFile.getAbsolutePath().contains("usXXX")); 312 assertTrue(tmpFile.getAbsolutePath().endsWith(".img")); 313 } finally { 314 FileUtil.deleteFile(tmpFile); 315 } 316 } 317 318 /** Test {@link FileUtil#createTempFileForRemote(String, File)} for remoteFile in root path. */ 319 @Test testCreateTempFileForRemote_singleFile()320 public void testCreateTempFileForRemote_singleFile() throws IOException { 321 String remoteFilePath = "userdata.img"; 322 File tmpFile = FileUtil.createTempFileForRemote(remoteFilePath, null); 323 try { 324 assertTrue(tmpFile.getAbsolutePath().contains("userdata")); 325 assertTrue(tmpFile.getAbsolutePath().endsWith(".img")); 326 } finally { 327 FileUtil.deleteFile(tmpFile); 328 } 329 } 330 331 /** 332 * Verify {@link FileUtil#calculateMd5(File)} works. 333 * 334 * @throws IOException 335 */ 336 @Test testCalculateMd5()337 public void testCalculateMd5() throws IOException { 338 final String source = "testtesttesttesttest"; 339 final String md5 = "f317f682fafe0309c6a423af0b4efa59"; 340 File tmpFile = FileUtil.createTempFile("testCalculateMd5", ".txt"); 341 try { 342 FileUtil.writeToFile(source, tmpFile); 343 String actualMd5 = FileUtil.calculateMd5(tmpFile); 344 assertEquals(md5, actualMd5); 345 } finally { 346 FileUtil.deleteFile(tmpFile); 347 } 348 } 349 350 /** 351 * Verify {@link FileUtil#calculateBase64Md5(File)} works. 352 * 353 * @throws IOException 354 */ 355 @Test testCalculateBase64Md5()356 public void testCalculateBase64Md5() throws IOException { 357 final String source = "testtesttesttesttest"; 358 final String base64Md5 = "8xf2gvr+AwnGpCOvC076WQ=="; 359 File tmpFile = FileUtil.createTempFile("testCalculateMd5", ".txt"); 360 try { 361 FileUtil.writeToFile(source, tmpFile); 362 String actualBase64Md5 = FileUtil.calculateBase64Md5(tmpFile); 363 assertEquals(base64Md5, actualBase64Md5); 364 } finally { 365 FileUtil.deleteFile(tmpFile); 366 } 367 } 368 369 /** Test that {@link FileUtil#recursiveSymlink(File, File)} properly simlink files. */ 370 @Test testRecursiveSymlink()371 public void testRecursiveSymlink() throws IOException { 372 File dir1 = null; 373 File dest = null; 374 try { 375 dir1 = FileUtil.createTempDir("orig-dir"); 376 File subdir1 = FileUtil.createTempDir("sub-dir", dir1); 377 File testFile = FileUtil.createTempFile("test", "file", subdir1); 378 dest = FileUtil.createTempDir("dest-dir"); 379 FileUtil.recursiveSymlink(dir1, dest); 380 // check that file is in dest dir 381 assertNotNull(FileUtil.findFile(dest, testFile.getName())); 382 } finally { 383 FileUtil.recursiveDelete(dir1); 384 FileUtil.recursiveDelete(dest); 385 } 386 } 387 388 /** 389 * Test that when a symlink dir is encountered by {@link FileUtil#recursiveDelete(File)}. The 390 * link itself is deleted but not followed. 391 */ 392 @Test testSymlinkDeletion()393 public void testSymlinkDeletion() throws IOException { 394 File dir1 = null; 395 File dest = null; 396 try { 397 dir1 = FileUtil.createTempDir("orig-dir"); 398 File subdir1 = FileUtil.createTempDir("sub-dir", dir1); 399 File testFile = FileUtil.createTempFile("test", "file", subdir1); 400 dest = FileUtil.createTempDir("dest-dir"); 401 dest.delete(); 402 FileUtil.symlinkFile(dir1, dest); 403 // Check that file is in dest dir 404 assertNotNull(FileUtil.findFile(dest, testFile.getName())); 405 // Now delete the symlink 406 FileUtil.recursiveDelete(dest); 407 assertFalse(dest.exists()); 408 // Ensure the orignal directory was not deleted (symlink was not followed). 409 assertTrue(subdir1.exists()); 410 } finally { 411 FileUtil.recursiveDelete(dir1); 412 FileUtil.recursiveDelete(dest); 413 } 414 } 415 416 // Assertions assertUnixPerms(File file, String expPerms, String altExpPerms)417 private String assertUnixPerms(File file, String expPerms, String altExpPerms) { 418 String perms = ls(file.getPath()); 419 assertTrue( 420 String.format( 421 "Expected file %s perms to be '%s' but they were '%s'.", 422 file, expPerms, perms), 423 perms.startsWith(expPerms) || perms.startsWith(altExpPerms)); 424 return perms; 425 } 426 427 // Helpers ls(String path)428 private String ls(String path) { 429 CommandResult result = 430 RunUtil.getDefault().runTimedCmdRetry(10 * 1000, 0, 3, "ls", "-ld", path); 431 return result.getStdout(); 432 } 433 createTempDir(String prefix)434 private File createTempDir(String prefix) throws IOException { 435 return createTempDir(prefix, null); 436 } 437 createTempDir(String prefix, File parentDir)438 private File createTempDir(String prefix, File parentDir) throws IOException { 439 File tempDir = FileUtil.createTempDir(prefix, parentDir); 440 mTempFiles.add(tempDir); 441 return tempDir; 442 } 443 createTempFile(String prefix, String suffix)444 private File createTempFile(String prefix, String suffix) throws IOException { 445 File tempFile = FileUtil.createTempFile(prefix, suffix); 446 mTempFiles.add(tempFile); 447 return tempFile; 448 } 449 createTempFile(String prefix, String suffix, File parentDir)450 private File createTempFile(String prefix, String suffix, File parentDir) throws IOException { 451 File tempFile = FileUtil.createTempFile(prefix, suffix, parentDir); 452 mTempFiles.add(tempFile); 453 return tempFile; 454 } 455 } 456