1 /* 2 * Copyright (C) 2008 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 17 package android.os.cts; 18 19 import android.os.FileObserver; 20 import android.test.AndroidTestCase; 21 22 import java.io.File; 23 import java.io.FileOutputStream; 24 import java.util.ArrayList; 25 import java.util.Arrays; 26 import java.util.List; 27 28 public class FileObserverTest extends AndroidTestCase { 29 30 private File mTestFile; 31 private File mTestDir; 32 private File mMoveDestFile; 33 private FileOutputStream mOut; 34 private static final String PATH = "/PATH"; 35 private static final String TEST_FILE = "file_observer_test.txt"; 36 private static final String TEST_DIR = "fileobserver_dir"; 37 private static final int FILE_DATA = 0x20; 38 private static final int UNDEFINED = 0x8000; 39 private static final long DELAY_MSECOND = 2000; 40 41 @Override 42 protected void setUp() throws Exception { 43 super.setUp(); 44 File dir = getContext().getFilesDir(); 45 mTestFile = new File(dir, TEST_FILE); 46 mTestFile.createNewFile(); 47 mTestDir = new File(dir, TEST_DIR); 48 mTestDir.mkdirs(); 49 } 50 51 @Override 52 protected void tearDown() throws Exception { 53 super.tearDown(); 54 if (mTestFile != null && mTestFile.exists()) { 55 mTestFile.delete(); 56 } 57 58 if (mMoveDestFile != null && mMoveDestFile.exists()) { 59 mMoveDestFile.delete(); 60 } 61 62 if (mTestDir != null && mTestDir.exists()) { 63 mTestDir.delete(); 64 } 65 66 if (mOut != null) { 67 mOut.close(); 68 } 69 } 70 71 public void testConstructor() { 72 // new the instance 73 new MockFileObserver(PATH); 74 // new the instance 75 new MockFileObserver(PATH, FileObserver.ACCESS); 76 } 77 78 /* 79 * Test point 80 * 1. Observe a dir, when it's child file have been written and closed, 81 * observer should get modify open-child modify-child and closed-write events. 82 * 2. While stop observer a dir, observer should't get any event while delete it's child file. 83 * 3. Observer a dir, when create delete a child file and delete self, 84 * observer should get create-child close-nowrite delete-child delete-self events. 85 * 4. Observer a file, the file moved from dir and the file moved to dir, move the file, 86 * file observer should get move-self event, 87 * moved from dir observer should get moved-from event, 88 * moved to dir observer should get moved-to event. 89 */ 90 public void testFileObserver() throws Exception { 91 MockFileObserver fileObserver = null; 92 int[] expected = null; 93 FileEvent[] moveEvents = null; 94 95 fileObserver = new MockFileObserver(mTestFile.getParent()); 96 try { 97 fileObserver.startWatching(); 98 mOut = new FileOutputStream(mTestFile); 99 100 mOut.write(FILE_DATA); // modify, open, write, modify 101 mOut.close(); // close_write 102 103 expected = new int[] {FileObserver.MODIFY, FileObserver.OPEN, FileObserver.MODIFY, 104 FileObserver.CLOSE_WRITE}; 105 moveEvents = waitForEvent(fileObserver); 106 assertEventsEquals(expected, moveEvents); 107 108 fileObserver.stopWatching(); 109 110 // action after observer stop watching 111 mTestFile.delete(); // delete 112 113 // should not get any event 114 expected = new int[] {UNDEFINED}; 115 moveEvents = waitForEvent(fileObserver); 116 assertEventsEquals(expected, moveEvents); 117 } finally { 118 fileObserver.stopWatching(); 119 mOut.close(); 120 mOut = null; 121 } 122 123 fileObserver = new MockFileObserver(mTestDir.getPath()); 124 try { 125 fileObserver.startWatching(); 126 mTestFile = new File(mTestDir, TEST_FILE); 127 assertTrue(mTestFile.createNewFile()); 128 assertTrue(mTestFile.exists()); 129 mTestFile.delete(); 130 mTestDir.delete(); 131 132 expected = new int[] {FileObserver.CREATE, 133 FileObserver.OPEN, FileObserver.CLOSE_WRITE, 134 FileObserver.DELETE, FileObserver.DELETE_SELF, UNDEFINED}; 135 moveEvents = waitForEvent(fileObserver); 136 assertEventsEquals(expected, moveEvents); 137 } finally { 138 fileObserver.stopWatching(); 139 } 140 141 File dir = getContext().getFilesDir(); 142 mTestFile = new File(dir, TEST_FILE); 143 mTestFile.createNewFile(); 144 mTestDir = new File(dir, TEST_DIR); 145 mTestDir.mkdirs(); 146 mMoveDestFile = new File(mTestDir, TEST_FILE); 147 MockFileObserver movedFrom = new MockFileObserver(dir.getPath()); 148 MockFileObserver movedTo = new MockFileObserver(mTestDir.getPath()); 149 fileObserver = new MockFileObserver(mTestFile.getPath()); 150 try { 151 movedFrom.startWatching(); 152 movedTo.startWatching(); 153 fileObserver.startWatching(); 154 mTestFile.renameTo(mMoveDestFile); 155 156 expected = new int[] {FileObserver.MOVE_SELF}; 157 moveEvents = waitForEvent(fileObserver); 158 assertEventsEquals(expected, moveEvents); 159 160 expected = new int[] {FileObserver.MOVED_FROM}; 161 moveEvents = waitForEvent(movedFrom); 162 assertEventsEquals(expected, moveEvents); 163 164 expected = new int[] {FileObserver.MOVED_TO}; 165 moveEvents = waitForEvent(movedTo); 166 assertEventsEquals(expected, moveEvents); 167 } finally { 168 fileObserver.stopWatching(); 169 movedTo.stopWatching(); 170 movedFrom.stopWatching(); 171 } 172 173 // Because Javadoc didn't specify when should a event happened, 174 // here ACCESS ATTRIB we found no way to test. 175 } 176 177 private void assertEventsEquals(final int[] expected, final FileEvent[] moveEvents) { 178 List<Integer> expectedEvents = new ArrayList<Integer>(); 179 for (int i = 0; i < expected.length; i++) { 180 expectedEvents.add(expected[i]); 181 } 182 List<FileEvent> actualEvents = Arrays.asList(moveEvents); 183 String message = "Expected: " + expectedEvents + " Actual: " + actualEvents; 184 assertEquals(message, expected.length, moveEvents.length); 185 for (int i = 0; i < expected.length; i++) { 186 assertEquals(message, expected[i], moveEvents[i].event); 187 } 188 } 189 190 private FileEvent[] waitForEvent(MockFileObserver fileObserver) 191 throws InterruptedException { 192 Thread.sleep(DELAY_MSECOND); 193 synchronized (fileObserver) { 194 return fileObserver.getEvents(); 195 } 196 } 197 198 private static class FileEvent { 199 public int event = UNDEFINED; 200 public String path; 201 202 public FileEvent(final int event, final String path) { 203 this.event = event; 204 this.path = path; 205 } 206 207 @Override 208 public String toString() { 209 return Integer.toString(event); 210 } 211 } 212 213 /* 214 * MockFileObserver 215 */ 216 private static class MockFileObserver extends FileObserver { 217 218 private List<FileEvent> mEvents = new ArrayList<FileEvent>(); 219 220 public MockFileObserver(String path) { 221 super(path); 222 } 223 224 public MockFileObserver(String path, int mask) { 225 super(path, mask); 226 } 227 228 @Override 229 public synchronized void onEvent(int event, String path) { 230 mEvents.add(new FileEvent(event, path)); 231 } 232 233 public synchronized FileEvent[] getEvents() { 234 final FileEvent[] events = new FileEvent[mEvents.size()]; 235 mEvents.toArray(events); 236 mEvents.clear(); 237 return events; 238 } 239 } 240 } 241