Split up tests and add some heartbeats to try to make them not timeout. BUG= R=nweiz@google.com Review URL: https://codereview.chromium.org//18877005 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/watcher@24978 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkgs/watcher/lib/src/directory_watcher.dart b/pkgs/watcher/lib/src/directory_watcher.dart index 0f297ba..61bf6c5 100644 --- a/pkgs/watcher/lib/src/directory_watcher.dart +++ b/pkgs/watcher/lib/src/directory_watcher.dart
@@ -42,13 +42,24 @@ Future get ready => _ready.future; Completer _ready = new Completer(); + /// The amount of time the watcher pauses between successive polls of the + /// directory contents. + final Duration pollingDelay; + /// The previous status of the files in the directory. /// /// Used to tell which files have been modified. final _statuses = new Map<String, _FileStatus>(); /// Creates a new [DirectoryWatcher] monitoring [directory]. - DirectoryWatcher(this.directory) { + /// + /// If [pollingDelay] is passed, it specifies the amount of time the watcher + /// will pause between successive polls of the directory contents. Making + /// this shorter will give more immediate feedback at the expense of doing + /// more IO and higher CPU usage. Defaults to one second. + DirectoryWatcher(this.directory, {Duration pollingDelay}) + : pollingDelay = pollingDelay != null ? pollingDelay : + new Duration(seconds: 1) { _events = new StreamController<WatchEvent>.broadcast(onListen: () { _state = _state.listen(this); }, onCancel: () { @@ -93,7 +104,7 @@ // restarting just so that we don't whale on the file system. // TODO(rnystrom): Tune this and/or make it tunable? if (_state.shouldNotify) { - return new Future.delayed(new Duration(seconds: 1)); + return new Future.delayed(pollingDelay); } }).then((_) { // Make sure we haven't transitioned to a non-watching state during the
diff --git a/pkgs/watcher/test/directory_watcher_test.dart b/pkgs/watcher/test/directory_watcher_test.dart index 635f7ee..800d54d 100644 --- a/pkgs/watcher/test/directory_watcher_test.dart +++ b/pkgs/watcher/test/directory_watcher_test.dart
@@ -90,150 +90,4 @@ writeFile("a/b/c/d/file.txt"); expectAddEvent("a/b/c/d/file.txt"); }); - - test('does not notify for changes when there were no subscribers', () { - // Note that this test doesn't rely as heavily on the test functions in - // utils.dart because it needs to be very explicit about when the event - // stream is and is not subscribed. - var watcher = createWatcher(); - - // Subscribe to the events. - var completer = new Completer(); - var subscription = watcher.events.listen((event) { - expect(event.type, equals(ChangeType.ADD)); - expect(event.path, endsWith("file.txt")); - completer.complete(); - }); - - writeFile("file.txt"); - - // Then wait until we get an event for it. - schedule(() => completer.future); - - // Unsubscribe. - schedule(() { - subscription.cancel(); - }); - - // Now write a file while we aren't listening. - writeFile("unwatched.txt"); - - // Then start listening again. - schedule(() { - completer = new Completer(); - subscription = watcher.events.listen((event) { - // We should get an event for the third file, not the one added while - // we weren't subscribed. - expect(event.type, equals(ChangeType.ADD)); - expect(event.path, endsWith("added.txt")); - completer.complete(); - }); - }); - - // The watcher will have been cancelled and then resumed in the middle of - // its pause between polling loops. That means the second scan to skip - // what changed while we were unsubscribed won't happen until after that - // delay is done. Wait long enough for that to happen. - schedule(() => new Future.delayed(new Duration(seconds: 1))); - - // And add a third file. - writeFile("added.txt"); - - // Wait until we get an event for the third file. - schedule(() => completer.future); - - schedule(() { - subscription.cancel(); - }); - }); - - - test('ready does not complete until after subscription', () { - var watcher = createWatcher(waitForReady: false); - - var ready = false; - watcher.ready.then((_) { - ready = true; - }); - - // Should not be ready yet. - schedule(() { - expect(ready, isFalse); - }); - - // Subscribe to the events. - schedule(() { - var subscription = watcher.events.listen((event) {}); - - currentSchedule.onComplete.schedule(() { - subscription.cancel(); - }); - }); - - // Should eventually be ready. - schedule(() => watcher.ready); - - schedule(() { - expect(ready, isTrue); - }); - }); - - test('ready completes immediately when already ready', () { - var watcher = createWatcher(waitForReady: false); - - // Subscribe to the events. - schedule(() { - var subscription = watcher.events.listen((event) {}); - - currentSchedule.onComplete.schedule(() { - subscription.cancel(); - }); - }); - - // Should eventually be ready. - schedule(() => watcher.ready); - - // Now ready should be a future that immediately completes. - var ready = false; - schedule(() { - watcher.ready.then((_) { - ready = true; - }); - }); - - schedule(() { - expect(ready, isTrue); - }); - }); - - test('ready returns a future that does not complete after unsubscribing', () { - var watcher = createWatcher(waitForReady: false); - - // Subscribe to the events. - var subscription; - schedule(() { - subscription = watcher.events.listen((event) {}); - }); - - var ready = false; - - // Wait until ready. - schedule(() => watcher.ready); - - // Now unsubscribe. - schedule(() { - subscription.cancel(); - - // Track when it's ready again. - ready = false; - watcher.ready.then((_) { - ready = true; - }); - }); - - // Should be back to not ready. - schedule(() { - expect(ready, isFalse); - }); - }); }
diff --git a/pkgs/watcher/test/no_subscription_test.dart b/pkgs/watcher/test/no_subscription_test.dart new file mode 100644 index 0000000..e9cb4e3 --- /dev/null +++ b/pkgs/watcher/test/no_subscription_test.dart
@@ -0,0 +1,73 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'package:scheduled_test/scheduled_test.dart'; +import 'package:watcher/watcher.dart'; + +import 'utils.dart'; + +main() { + initConfig(); + + setUp(createSandbox); + + test('does not notify for changes when there were no subscribers', () { + // Note that this test doesn't rely as heavily on the test functions in + // utils.dart because it needs to be very explicit about when the event + // stream is and is not subscribed. + var watcher = createWatcher(); + + // Subscribe to the events. + var completer = new Completer(); + var subscription = watcher.events.listen((event) { + expect(event.type, equals(ChangeType.ADD)); + expect(event.path, endsWith("file.txt")); + completer.complete(); + }); + + writeFile("file.txt"); + + // Then wait until we get an event for it. + schedule(() => completer.future); + + // Unsubscribe. + schedule(() { + subscription.cancel(); + }); + + // Now write a file while we aren't listening. + writeFile("unwatched.txt"); + + // Then start listening again. + schedule(() { + completer = new Completer(); + subscription = watcher.events.listen((event) { + // We should get an event for the third file, not the one added while + // we weren't subscribed. + expect(event.type, equals(ChangeType.ADD)); + expect(event.path, endsWith("added.txt")); + completer.complete(); + }); + }); + + // The watcher will have been cancelled and then resumed in the middle of + // its pause between polling loops. That means the second scan to skip + // what changed while we were unsubscribed won't happen until after that + // delay is done. Wait long enough for that to happen. + schedule(() => new Future.delayed(new Duration(seconds: 1))); + + // And add a third file. + writeFile("added.txt"); + + // Wait until we get an event for the third file. + schedule(() => completer.future); + + schedule(() { + subscription.cancel(); + }); + }); +}
diff --git a/pkgs/watcher/test/ready_test.dart b/pkgs/watcher/test/ready_test.dart new file mode 100644 index 0000000..dd799ce --- /dev/null +++ b/pkgs/watcher/test/ready_test.dart
@@ -0,0 +1,106 @@ +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; + +import 'package:scheduled_test/scheduled_test.dart'; +import 'package:watcher/watcher.dart'; + +import 'utils.dart'; + +main() { + initConfig(); + + setUp(createSandbox); + + test('ready does not complete until after subscription', () { + var watcher = createWatcher(waitForReady: false); + + var ready = false; + watcher.ready.then((_) { + ready = true; + }); + + // Should not be ready yet. + schedule(() { + expect(ready, isFalse); + }); + + // Subscribe to the events. + schedule(() { + var subscription = watcher.events.listen((event) {}); + + currentSchedule.onComplete.schedule(() { + subscription.cancel(); + }); + }); + + // Should eventually be ready. + schedule(() => watcher.ready); + + schedule(() { + expect(ready, isTrue); + }); + }); + + test('ready completes immediately when already ready', () { + var watcher = createWatcher(waitForReady: false); + + // Subscribe to the events. + schedule(() { + var subscription = watcher.events.listen((event) {}); + + currentSchedule.onComplete.schedule(() { + subscription.cancel(); + }); + }); + + // Should eventually be ready. + schedule(() => watcher.ready); + + // Now ready should be a future that immediately completes. + var ready = false; + schedule(() { + watcher.ready.then((_) { + ready = true; + }); + }); + + schedule(() { + expect(ready, isTrue); + }); + }); + + test('ready returns a future that does not complete after unsubscribing', () { + var watcher = createWatcher(waitForReady: false); + + // Subscribe to the events. + var subscription; + schedule(() { + subscription = watcher.events.listen((event) {}); + }); + + var ready = false; + + // Wait until ready. + schedule(() => watcher.ready); + + // Now unsubscribe. + schedule(() { + subscription.cancel(); + + // Track when it's ready again. + ready = false; + watcher.ready.then((_) { + ready = true; + }); + }); + + // Should be back to not ready. + schedule(() { + expect(ready, isFalse); + }); + }); +}
diff --git a/pkgs/watcher/test/utils.dart b/pkgs/watcher/test/utils.dart index 7b3da02..5a22e60 100644 --- a/pkgs/watcher/test/utils.dart +++ b/pkgs/watcher/test/utils.dart
@@ -77,7 +77,9 @@ /// and is polling for changes. If you pass `false` for [waitForReady], it will /// not schedule this delay. DirectoryWatcher createWatcher({bool waitForReady}) { - _watcher = new DirectoryWatcher(_sandboxDir); + // Use a short delay to make the tests run quickly. + _watcher = new DirectoryWatcher(_sandboxDir, + pollingDelay: new Duration(milliseconds: 100)); // Wait until the scan is finished so that we don't miss changes to files // that could occur before the scan completes.