diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-30 19:39:15 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-30 19:39:15 +0000 |
commit | e611fd66e64564d17865ed19658dc0b56e1ee746 (patch) | |
tree | 0d607ea22b3aed344707f3af3f8e622fe9fab6cf /base/directory_watcher_unittest.cc | |
parent | 022a7edd851ccd3b0e0f5f4e83e44b986085e636 (diff) | |
download | chromium_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.cc | 178 |
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 |