summaryrefslogtreecommitdiffstats
path: root/base/directory_watcher_unittest.cc
diff options
context:
space:
mode:
authorphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-30 19:39:15 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-30 19:39:15 +0000
commite611fd66e64564d17865ed19658dc0b56e1ee746 (patch)
tree0d607ea22b3aed344707f3af3f8e622fe9fab6cf /base/directory_watcher_unittest.cc
parent022a7edd851ccd3b0e0f5f4e83e44b986085e636 (diff)
downloadchromium_src-e611fd66e64564d17865ed19658dc0b56e1ee746.zip
chromium_src-e611fd66e64564d17865ed19658dc0b56e1ee746.tar.gz
chromium_src-e611fd66e64564d17865ed19658dc0b56e1ee746.tar.bz2
Add DirectoryWatcher implementation for Mac.
This uses FSEvents and supports both recursive and non-recursive modes. TEST=Make sure that tests matching DirectoryWatcherTest.* from base_unittests pass on Mac. http://crbug.com/10967 Review URL: http://codereview.chromium.org/99057 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14977 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/directory_watcher_unittest.cc')
-rw-r--r--base/directory_watcher_unittest.cc178
1 files changed, 109 insertions, 69 deletions
diff --git a/base/directory_watcher_unittest.cc b/base/directory_watcher_unittest.cc
index fabd46f..9ca5cda 100644
--- a/base/directory_watcher_unittest.cc
+++ b/base/directory_watcher_unittest.cc
@@ -21,12 +21,20 @@
namespace {
// For tests where we wait a bit to verify nothing happened
-const int kWaitForEventTime = 500;
+const int kWaitForEventTime = 1000;
-} // namespace
+class DirectoryWatcherTest : public testing::Test {
+ public:
+ // Implementation of DirectoryWatcher on Mac requires UI loop.
+ DirectoryWatcherTest() : loop_(MessageLoop::TYPE_UI) {
+ }
+
+ void OnTestDelegateFirstNotification(const FilePath& path) {
+ notified_delegates_++;
+ if (notified_delegates_ >= expected_notified_delegates_)
+ MessageLoop::current()->Quit();
+ }
-class DirectoryWatcherTest : public testing::Test,
- public DirectoryWatcher::Delegate {
protected:
virtual void SetUp() {
// Name a subdirectory of the temp directory.
@@ -37,20 +45,6 @@ class DirectoryWatcherTest : public testing::Test,
// Create a fresh, empty copy of this directory.
file_util::Delete(test_dir_, true);
file_util::CreateDirectory(test_dir_);
-
- directory_mods_ = 0;
- quit_mod_count_ = 0;
-
- original_thread_id_ = PlatformThread::CurrentId();
- }
-
- virtual void OnDirectoryChanged(const FilePath& path) {
- EXPECT_EQ(original_thread_id_, PlatformThread::CurrentId());
- ++directory_mods_;
- // The exact number is verified by VerifyExpectedNumberOfModifications.
- // Sometimes we don't want such check, see WaitForFirstNotification.
- if (directory_mods_ >= quit_mod_count_)
- MessageLoop::current()->Quit();
}
virtual void TearDown() {
@@ -69,29 +63,31 @@ class DirectoryWatcherTest : public testing::Test,
file_util::WriteFile(path, content.c_str(), content.length());
}
- void SetExpectedNumberOfModifications(int n) {
- quit_mod_count_ = n;
+ void SetExpectedNumberOfNotifiedDelegates(int n) {
+ notified_delegates_ = 0;
+ expected_notified_delegates_ = n;
}
- void VerifyExpectedNumberOfModifications() {
- // Check that we get at least the expected number of notifications.
- if (quit_mod_count_ - directory_mods_ > 0)
+ void VerifyExpectedNumberOfNotifiedDelegates() {
+ // Check that we get at least the expected number of notified delegates.
+ if (expected_notified_delegates_ - notified_delegates_ > 0)
loop_.Run();
- // Check that we get no more than the expected number of notifications.
+ // Check that we get no more than the expected number of notified delegates.
loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask,
kWaitForEventTime);
loop_.Run();
- EXPECT_EQ(quit_mod_count_, directory_mods_);
+ EXPECT_EQ(expected_notified_delegates_, notified_delegates_);
}
- // Only use this function if you don't care about getting
- // too many notifications. Useful for tests where you get
- // different number of notifications on different platforms.
- void WaitForFirstNotification() {
- directory_mods_ = 0;
- SetExpectedNumberOfModifications(1);
- loop_.Run();
+ // We need this function for reliable tests on Mac OS X. FSEvents API
+ // has a latency interval and can merge multiple events into one,
+ // and we need a clear distinction between events triggered by test setup code
+ // and test code.
+ void SyncIfPOSIX() {
+#if defined(OS_POSIX)
+ sync();
+#endif // defined(OS_POSIX)
}
MessageLoop loop_;
@@ -99,12 +95,42 @@ class DirectoryWatcherTest : public testing::Test,
// The path to a temporary directory used for testing.
FilePath test_dir_;
- // The number of times a directory modification has been observed.
- int directory_mods_;
+ // The number of test delegates which received their notification.
+ int notified_delegates_;
+
+ // The number of notified test delegates after which we quit the message loop.
+ int expected_notified_delegates_;
+};
- // The number of directory mods which, when reached, cause us to quit
- // our message loop.
- int quit_mod_count_;
+class TestDelegate : public DirectoryWatcher::Delegate {
+ public:
+ TestDelegate(DirectoryWatcherTest* test)
+ : test_(test),
+ got_notification_(false),
+ original_thread_id_(PlatformThread::CurrentId()) {
+ }
+
+ bool got_notification() const {
+ return got_notification_;
+ }
+
+ void reset() {
+ got_notification_ = false;
+ }
+
+ virtual void OnDirectoryChanged(const FilePath& path) {
+ EXPECT_EQ(original_thread_id_, PlatformThread::CurrentId());
+ if (!got_notification_)
+ test_->OnTestDelegateFirstNotification(path);
+ got_notification_ = true;
+ }
+
+ private:
+ // Hold a pointer to current test fixture to inform it on first notification.
+ DirectoryWatcherTest* test_;
+
+ // Set to true after first notification.
+ bool got_notification_;
// Keep track of original thread id to verify that callbacks are called
// on the same thread.
@@ -114,63 +140,68 @@ class DirectoryWatcherTest : public testing::Test,
// Basic test: add a file and verify we notice it.
TEST_F(DirectoryWatcherTest, NewFile) {
DirectoryWatcher watcher;
- ASSERT_TRUE(watcher.Watch(test_dir_, this, false));
+ TestDelegate delegate(this);
+ ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, false));
- SetExpectedNumberOfModifications(2);
+ SetExpectedNumberOfNotifiedDelegates(1);
WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some content");
- VerifyExpectedNumberOfModifications();
+ VerifyExpectedNumberOfNotifiedDelegates();
}
// Verify that modifying a file is caught.
TEST_F(DirectoryWatcherTest, ModifiedFile) {
- DirectoryWatcher watcher;
- ASSERT_TRUE(watcher.Watch(test_dir_, this, false));
-
// Write a file to the test dir.
- SetExpectedNumberOfModifications(2);
WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some content");
- VerifyExpectedNumberOfModifications();
+
+ SyncIfPOSIX();
+
+ DirectoryWatcher watcher;
+ TestDelegate delegate(this);
+ ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, false));
// Now make sure we get notified if the file is modified.
+ SetExpectedNumberOfNotifiedDelegates(1);
WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some new content");
- // Use a more forgiving function to check because on Linux you will get
- // 1 notification, and on Windows 2 (and nothing seems to convince it to
- // send less notifications).
- WaitForFirstNotification();
+ VerifyExpectedNumberOfNotifiedDelegates();
}
// Verify that letting the watcher go out of scope stops notifications.
TEST_F(DirectoryWatcherTest, Unregister) {
+ TestDelegate delegate(this);
+
{
DirectoryWatcher watcher;
- ASSERT_TRUE(watcher.Watch(test_dir_, this, false));
+ ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, false));
// And then let it fall out of scope, clearing its watch.
}
// Write a file to the test dir.
- SetExpectedNumberOfModifications(0);
+ SetExpectedNumberOfNotifiedDelegates(0);
WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some content");
- VerifyExpectedNumberOfModifications();
+ VerifyExpectedNumberOfNotifiedDelegates();
}
TEST_F(DirectoryWatcherTest, SubDirRecursive) {
FilePath subdir(FILE_PATH_LITERAL("SubDir"));
ASSERT_TRUE(file_util::CreateDirectory(test_dir_.Append(subdir)));
-#if !defined(OS_WIN)
+#if defined(OS_LINUX)
// TODO(port): Recursive watches are not implemented on Linux.
return;
#endif // !defined(OS_WIN)
+ SyncIfPOSIX();
+
// Verify that modifications to a subdirectory are noticed by recursive watch.
+ TestDelegate delegate(this);
DirectoryWatcher watcher;
- ASSERT_TRUE(watcher.Watch(test_dir_, this, true));
+ ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, true));
// Write a file to the subdir.
- SetExpectedNumberOfModifications(2);
+ SetExpectedNumberOfNotifiedDelegates(1);
FilePath test_path = subdir.AppendASCII("test_file");
WriteTestDirFile(test_path.value(), "some content");
- VerifyExpectedNumberOfModifications();
+ VerifyExpectedNumberOfNotifiedDelegates();
}
TEST_F(DirectoryWatcherTest, SubDirNonRecursive) {
@@ -189,15 +220,18 @@ TEST_F(DirectoryWatcherTest, SubDirNonRecursive) {
FilePath test_path = subdir.AppendASCII("test_file");
WriteTestDirFile(test_path.value(), "some content");
+ SyncIfPOSIX();
+
// Verify that modifications to a subdirectory are not noticed
// by a not-recursive watch.
DirectoryWatcher watcher;
- ASSERT_TRUE(watcher.Watch(test_dir_, this, false));
+ TestDelegate delegate(this);
+ ASSERT_TRUE(watcher.Watch(test_dir_, &delegate, false));
// Modify the test file. There should be no notifications.
- SetExpectedNumberOfModifications(0);
+ SetExpectedNumberOfNotifiedDelegates(0);
WriteTestDirFile(test_path.value(), "some other content");
- VerifyExpectedNumberOfModifications();
+ VerifyExpectedNumberOfNotifiedDelegates();
}
namespace {
@@ -236,37 +270,41 @@ TEST_F(DirectoryWatcherTest, DeleteDuringNotify) {
TEST_F(DirectoryWatcherTest, MultipleWatchersSingleFile) {
DirectoryWatcher watcher1, watcher2;
- ASSERT_TRUE(watcher1.Watch(test_dir_, this, false));
- ASSERT_TRUE(watcher2.Watch(test_dir_, this, false));
+ TestDelegate delegate1(this), delegate2(this);
+ ASSERT_TRUE(watcher1.Watch(test_dir_, &delegate1, false));
+ ASSERT_TRUE(watcher2.Watch(test_dir_, &delegate2, false));
- SetExpectedNumberOfModifications(4); // Each watcher should fire twice.
+ SetExpectedNumberOfNotifiedDelegates(2);
WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some content");
- VerifyExpectedNumberOfModifications();
+ VerifyExpectedNumberOfNotifiedDelegates();
}
TEST_F(DirectoryWatcherTest, MultipleWatchersDifferentFiles) {
const int kNumberOfWatchers = 5;
DirectoryWatcher watchers[kNumberOfWatchers];
+ TestDelegate delegates[kNumberOfWatchers] = {this, this, this, this, this};
FilePath subdirs[kNumberOfWatchers];
for (int i = 0; i < kNumberOfWatchers; i++) {
subdirs[i] = FilePath(FILE_PATH_LITERAL("Dir")).AppendASCII(IntToString(i));
ASSERT_TRUE(file_util::CreateDirectory(test_dir_.Append(subdirs[i])));
- ASSERT_TRUE(watchers[i].Watch(test_dir_.Append(subdirs[i]), this, false));
+ ASSERT_TRUE(watchers[i].Watch(test_dir_.Append(subdirs[i]), &delegates[i],
+ false));
}
for (int i = 0; i < kNumberOfWatchers; i++) {
// Verify that we only get modifications from one watcher (each watcher has
// different directory).
- ASSERT_EQ(0, directory_mods_);
+ for (int j = 0; j < kNumberOfWatchers; j++)
+ delegates[j].reset();
// Write a file to the subdir.
FilePath test_path = subdirs[i].AppendASCII("test_file");
- SetExpectedNumberOfModifications(2);
+ SetExpectedNumberOfNotifiedDelegates(1);
WriteTestDirFile(test_path.value(), "some content");
- VerifyExpectedNumberOfModifications();
+ VerifyExpectedNumberOfNotifiedDelegates();
- directory_mods_ = 0;
+ loop_.RunAllPending();
}
}
@@ -275,6 +313,8 @@ TEST_F(DirectoryWatcherTest, MultipleWatchersDifferentFiles) {
// Basic test: add a file and verify we notice it.
TEST_F(DirectoryWatcherTest, NonExistentDirectory) {
DirectoryWatcher watcher;
- ASSERT_FALSE(watcher.Watch(test_dir_.AppendASCII("does-not-exist"), this,
+ ASSERT_FALSE(watcher.Watch(test_dir_.AppendASCII("does-not-exist"), NULL,
false));
}
+
+} // namespace