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