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