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