1 /* 2 * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 4313887 6838333 26 * @summary Unit test for java.nio.file.WatchService 27 * @library .. 28 * @run main/timeout=120 Basic 29 */ 30 31 import java.nio.file.*; 32 import static java.nio.file.StandardWatchEventKind.*; 33 import java.nio.file.attribute.*; 34 import java.io.*; 35 import java.util.*; 36 import java.util.concurrent.TimeUnit; 37 38 /** 39 * Unit test for WatchService that exercises all methods in various scenarios. 40 */ 41 42 public class Basic { 43 44 static void checkKey(WatchKey key, Path dir) { 45 if (!key.isValid()) 46 throw new RuntimeException("Key is not valid"); 47 } 48 49 static void takeExpectedKey(WatchService watcher, WatchKey expected) { 50 System.out.println("take events..."); 51 WatchKey key; 52 try { 53 key = watcher.take(); 54 } catch (InterruptedException x) { 55 // not expected 56 throw new RuntimeException(x); 57 } 58 if (key != expected) 59 throw new RuntimeException("removed unexpected key"); 60 } 61 62 static void checkExpectedEvent(Iterable<WatchEvent<?>> events, 63 WatchEvent.Kind<?> expectedKind, 64 Object expectedContext) 65 { 66 WatchEvent<?> event = events.iterator().next(); 67 System.out.format("got event: type=%s, count=%d, context=%s\n", 68 event.kind(), event.count(), event.context()); 69 if (event.kind() != expectedKind) 70 throw new RuntimeException("unexpected event"); 71 if (!expectedContext.equals(event.context())) 72 throw new RuntimeException("unexpected context"); 73 } 74 75 /** 76 * Simple test of each of the standard events 77 */ 78 static void testEvents(Path dir) throws IOException { 79 System.out.println("-- Standard Events --"); 80 81 FileSystem fs = FileSystems.getDefault(); 82 Path name = fs.getPath("foo"); 83 84 try (WatchService watcher = fs.newWatchService()) { 85 // --- ENTRY_CREATE --- 86 87 // register for event 88 System.out.format("register %s for ENTRY_CREATE\n", dir); 89 WatchKey myKey = dir.register(watcher, 90 new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); 91 checkKey(myKey, dir); 92 93 // create file 94 Path file = dir.resolve("foo"); 95 System.out.format("create %s\n", file); 96 Files.createFile(file); 97 98 // remove key and check that we got the ENTRY_CREATE event 99 takeExpectedKey(watcher, myKey); 100 checkExpectedEvent(myKey.pollEvents(), 101 StandardWatchEventKind.ENTRY_CREATE, name); 102 103 System.out.println("reset key"); 104 if (!myKey.reset()) 105 throw new RuntimeException("key has been cancalled"); 106 107 System.out.println("OKAY"); 108 109 // --- ENTRY_DELETE --- 110 111 System.out.format("register %s for ENTRY_DELETE\n", dir); 112 WatchKey deleteKey = dir.register(watcher, 113 new WatchEvent.Kind<?>[]{ ENTRY_DELETE }); 114 if (deleteKey != myKey) 115 throw new RuntimeException("register did not return existing key"); 116 checkKey(deleteKey, dir); 117 118 System.out.format("delete %s\n", file); 119 Files.delete(file); 120 takeExpectedKey(watcher, myKey); 121 checkExpectedEvent(myKey.pollEvents(), 122 StandardWatchEventKind.ENTRY_DELETE, name); 123 124 System.out.println("reset key"); 125 if (!myKey.reset()) 126 throw new RuntimeException("key has been cancalled"); 127 128 System.out.println("OKAY"); 129 130 // create the file for the next test 131 Files.createFile(file); 132 133 // --- ENTRY_MODIFY --- 134 135 System.out.format("register %s for ENTRY_MODIFY\n", dir); 136 WatchKey newKey = dir.register(watcher, 137 new WatchEvent.Kind<?>[]{ ENTRY_MODIFY }); 138 if (newKey != myKey) 139 throw new RuntimeException("register did not return existing key"); 140 checkKey(newKey, dir); 141 142 System.out.format("update: %s\n", file); 143 try (OutputStream out = Files.newOutputStream(file, StandardOpenOption.APPEND)) { 144 out.write("I am a small file".getBytes("UTF-8")); 145 } 146 147 // remove key and check that we got the ENTRY_MODIFY event 148 takeExpectedKey(watcher, myKey); 149 checkExpectedEvent(myKey.pollEvents(), 150 StandardWatchEventKind.ENTRY_MODIFY, name); 151 System.out.println("OKAY"); 152 153 // done 154 Files.delete(file); 155 } 156 } 157 158 /** 159 * Check that a cancelled key will never be queued 160 */ 161 static void testCancel(Path dir) throws IOException { 162 System.out.println("-- Cancel --"); 163 164 try (WatchService watcher = FileSystems.getDefault().newWatchService()) { 165 166 System.out.format("register %s for events\n", dir); 167 WatchKey myKey = dir.register(watcher, 168 new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); 169 checkKey(myKey, dir); 170 171 System.out.println("cancel key"); 172 myKey.cancel(); 173 174 // create a file in the directory 175 Path file = dir.resolve("mars"); 176 System.out.format("create: %s\n", file); 177 Files.createFile(file); 178 179 // poll for keys - there will be none 180 System.out.println("poll..."); 181 try { 182 WatchKey key = watcher.poll(3000, TimeUnit.MILLISECONDS); 183 if (key != null) 184 throw new RuntimeException("key should not be queued"); 185 } catch (InterruptedException x) { 186 throw new RuntimeException(x); 187 } 188 189 // done 190 Files.delete(file); 191 192 System.out.println("OKAY"); 193 } 194 } 195 196 /** 197 * Check that deleting a registered directory causes the key to be 198 * cancelled and queued. 199 */ 200 static void testAutomaticCancel(Path dir) throws IOException { 201 System.out.println("-- Automatic Cancel --"); 202 203 Path subdir = Files.createDirectory(dir.resolve("bar")); 204 205 try (WatchService watcher = FileSystems.getDefault().newWatchService()) { 206 207 System.out.format("register %s for events\n", subdir); 208 WatchKey myKey = subdir.register(watcher, 209 new WatchEvent.Kind<?>[]{ ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY }); 210 211 System.out.format("delete: %s\n", subdir); 212 Files.delete(subdir); 213 takeExpectedKey(watcher, myKey); 214 215 System.out.println("reset key"); 216 if (myKey.reset()) 217 throw new RuntimeException("Key was not cancelled"); 218 if (myKey.isValid()) 219 throw new RuntimeException("Key is still valid"); 220 221 System.out.println("OKAY"); 222 223 } 224 } 225 226 /** 227 * Asynchronous close of watcher causes blocked threads to wakeup 228 */ 229 static void testWakeup(Path dir) throws IOException { 230 System.out.println("-- Wakeup Tests --"); 231 final WatchService watcher = FileSystems.getDefault().newWatchService(); 232 Runnable r = new Runnable() { 233 public void run() { 234 try { 235 Thread.sleep(5000); 236 System.out.println("close WatchService..."); 237 watcher.close(); 238 } catch (InterruptedException x) { 239 x.printStackTrace(); 240 } catch (IOException x) { 241 x.printStackTrace(); 242 } 243 } 244 }; 245 246 // start thread to close watch service after delay 247 new Thread(r).start(); 248 249 try { 250 System.out.println("take..."); 251 watcher.take(); 252 throw new RuntimeException("ClosedWatchServiceException not thrown"); 253 } catch (InterruptedException x) { 254 throw new RuntimeException(x); 255 } catch (ClosedWatchServiceException x) { 256 System.out.println("ClosedWatchServiceException thrown"); 257 } 258 259 System.out.println("OKAY"); 260 } 261 262 /** 263 * Simple test to check exceptions and other cases 264 */ 265 @SuppressWarnings("unchecked") 266 static void testExceptions(Path dir) throws IOException { 267 System.out.println("-- Exceptions and other simple tests --"); 268 269 WatchService watcher = FileSystems.getDefault().newWatchService(); 270 try { 271 272 // Poll tests 273 274 WatchKey key; 275 System.out.println("poll..."); 276 key = watcher.poll(); 277 if (key != null) 278 throw new RuntimeException("no keys registered"); 279 280 System.out.println("poll with timeout..."); 281 try { 282 long start = System.currentTimeMillis(); 283 key = watcher.poll(3000, TimeUnit.MILLISECONDS); 284 if (key != null) 285 throw new RuntimeException("no keys registered"); 286 long waited = System.currentTimeMillis() - start; 287 if (waited < 2900) 288 throw new RuntimeException("poll was too short"); 289 } catch (InterruptedException x) { 290 throw new RuntimeException(x); 291 } 292 293 // IllegalArgumentException 294 System.out.println("IllegalArgumentException tests..."); 295 try { 296 dir.register(watcher, new WatchEvent.Kind<?>[]{ } ); 297 throw new RuntimeException("IllegalArgumentException not thrown"); 298 } catch (IllegalArgumentException x) { 299 } 300 try { 301 // OVERFLOW is ignored so this is equivalent to the empty set 302 dir.register(watcher, new WatchEvent.Kind<?>[]{ OVERFLOW }); 303 throw new RuntimeException("IllegalArgumentException not thrown"); 304 } catch (IllegalArgumentException x) { 305 } 306 307 // UnsupportedOperationException 308 try { 309 dir.register(watcher, new WatchEvent.Kind<?>[]{ 310 new WatchEvent.Kind<Object>() { 311 @Override public String name() { return "custom"; } 312 @Override public Class<Object> type() { return Object.class; } 313 }}); 314 } catch (UnsupportedOperationException x) { 315 } 316 try { 317 dir.register(watcher, 318 new WatchEvent.Kind<?>[]{ ENTRY_CREATE }, 319 new WatchEvent.Modifier() { 320 @Override public String name() { return "custom"; } 321 }); 322 throw new RuntimeException("UnsupportedOperationException not thrown"); 323 } catch (UnsupportedOperationException x) { 324 } 325 326 // NullPointerException 327 System.out.println("NullPointerException tests..."); 328 try { 329 dir.register(null, new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); 330 throw new RuntimeException("NullPointerException not thrown"); 331 } catch (NullPointerException x) { 332 } 333 try { 334 dir.register(watcher, new WatchEvent.Kind<?>[]{ null }); 335 throw new RuntimeException("NullPointerException not thrown"); 336 } catch (NullPointerException x) { 337 } 338 try { 339 dir.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_CREATE }, 340 (WatchEvent.Modifier)null); 341 throw new RuntimeException("NullPointerException not thrown"); 342 } catch (NullPointerException x) { 343 } 344 } finally { 345 watcher.close(); 346 } 347 348 // -- ClosedWatchServiceException -- 349 350 System.out.println("ClosedWatchServiceException tests..."); 351 352 try { 353 watcher.poll(); 354 throw new RuntimeException("ClosedWatchServiceException not thrown"); 355 } catch (ClosedWatchServiceException x) { 356 } 357 358 // assume that poll throws exception immediately 359 long start = System.currentTimeMillis(); 360 try { 361 watcher.poll(10000, TimeUnit.MILLISECONDS); 362 throw new RuntimeException("ClosedWatchServiceException not thrown"); 363 } catch (InterruptedException x) { 364 throw new RuntimeException(x); 365 } catch (ClosedWatchServiceException x) { 366 long waited = System.currentTimeMillis() - start; 367 if (waited > 5000) 368 throw new RuntimeException("poll was too long"); 369 } 370 371 try { 372 watcher.take(); 373 throw new RuntimeException("ClosedWatchServiceException not thrown"); 374 } catch (InterruptedException x) { 375 throw new RuntimeException(x); 376 } catch (ClosedWatchServiceException x) { 377 } 378 379 try { 380 dir.register(watcher, new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); 381 throw new RuntimeException("ClosedWatchServiceException not thrown"); 382 } catch (ClosedWatchServiceException x) { 383 } 384 385 System.out.println("OKAY"); 386 } 387 388 /** 389 * Test that directory can be registered with more than one watch service 390 * and that events don't interfere with each other 391 */ 392 static void testTwoWatchers(Path dir) throws IOException { 393 System.out.println("-- Two watchers test --"); 394 395 FileSystem fs = FileSystems.getDefault(); 396 WatchService watcher1 = fs.newWatchService(); 397 WatchService watcher2 = fs.newWatchService(); 398 try { 399 Path name1 = fs.getPath("gus1"); 400 Path name2 = fs.getPath("gus2"); 401 402 // create gus1 403 Path file1 = dir.resolve(name1); 404 System.out.format("create %s\n", file1); 405 Files.createFile(file1); 406 407 // register with both watch services (different events) 408 System.out.println("register for different events"); 409 WatchKey key1 = dir.register(watcher1, 410 new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); 411 WatchKey key2 = dir.register(watcher2, 412 new WatchEvent.Kind<?>[]{ ENTRY_DELETE }); 413 414 if (key1 == key2) 415 throw new RuntimeException("keys should be different"); 416 417 // create gus2 418 Path file2 = dir.resolve(name2); 419 System.out.format("create %s\n", file2); 420 Files.createFile(file2); 421 422 // check that key1 got ENTRY_CREATE 423 takeExpectedKey(watcher1, key1); 424 checkExpectedEvent(key1.pollEvents(), 425 StandardWatchEventKind.ENTRY_CREATE, name2); 426 427 // check that key2 got zero events 428 WatchKey key = watcher2.poll(); 429 if (key != null) 430 throw new RuntimeException("key not expected"); 431 432 // delete gus1 433 Files.delete(file1); 434 435 // check that key2 got ENTRY_DELETE 436 takeExpectedKey(watcher2, key2); 437 checkExpectedEvent(key2.pollEvents(), 438 StandardWatchEventKind.ENTRY_DELETE, name1); 439 440 // check that key1 got zero events 441 key = watcher1.poll(); 442 if (key != null) 443 throw new RuntimeException("key not expected"); 444 445 // reset for next test 446 key1.reset(); 447 key2.reset(); 448 449 // change registration with watcher2 so that they are both 450 // registered for the same event 451 System.out.println("register for same event"); 452 key2 = dir.register(watcher2, new WatchEvent.Kind<?>[]{ ENTRY_CREATE }); 453 454 // create file and key2 should be queued 455 System.out.format("create %s\n", file1); 456 Files.createFile(file1); 457 takeExpectedKey(watcher2, key2); 458 checkExpectedEvent(key2.pollEvents(), 459 StandardWatchEventKind.ENTRY_CREATE, name1); 460 461 System.out.println("OKAY"); 462 463 } finally { 464 watcher2.close(); 465 watcher1.close(); 466 } 467 } 468 469 public static void main(String[] args) throws IOException { 470 Path dir = TestUtil.createTemporaryDirectory(); 471 try { 472 473 testEvents(dir); 474 testCancel(dir); 475 testAutomaticCancel(dir); 476 testWakeup(dir); 477 testExceptions(dir); 478 testTwoWatchers(dir); 479 480 } finally { 481 TestUtil.removeAll(dir); 482 } 483 } 484 }