diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-18 14:35:58 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-18 14:35:58 +0000 |
commit | 34c70c9f8f89e5293cc9c6de9742adfbba5810bf (patch) | |
tree | 0da65c6ac92bdb7f2f68193a61efb93e8a4646b1 /base/directory_watcher_unittest.cc | |
parent | b8096e69fa183c6facc254b7c7b78cb5099dd770 (diff) | |
download | chromium_src-34c70c9f8f89e5293cc9c6de9742adfbba5810bf.zip chromium_src-34c70c9f8f89e5293cc9c6de9742adfbba5810bf.tar.gz chromium_src-34c70c9f8f89e5293cc9c6de9742adfbba5810bf.tar.bz2 |
Port DirectoryWatcher to Linux using inotify.
Review URL: http://codereview.chromium.org/42037
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11962 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/directory_watcher_unittest.cc')
-rw-r--r-- | base/directory_watcher_unittest.cc | 195 |
1 files changed, 150 insertions, 45 deletions
diff --git a/base/directory_watcher_unittest.cc b/base/directory_watcher_unittest.cc index 21a6269..3b6f645 100644 --- a/base/directory_watcher_unittest.cc +++ b/base/directory_watcher_unittest.cc @@ -12,61 +12,97 @@ #include "base/file_util.h" #include "base/message_loop.h" #include "base/path_service.h" +#include "base/platform_thread.h" #include "base/string_util.h" #if defined(OS_WIN) #include "base/win_util.h" #endif #include "testing/gtest/include/gtest/gtest.h" -// For tests where we wait a bit to verify nothing happened +// TODO(phajdan.jr): Clean up ifdefs in this file when Linux/Windows differences +// get sorted out. + namespace { + +// For tests where we wait a bit to verify nothing happened const int kWaitForEventTime = 500; -} + +// Unfortunately Windows supports only recursive watches and Linux +// only non-recursive ones. +#if defined(OS_WIN) +const bool kDefaultRecursiveValue = true; +#elif defined(OS_LINUX) +const bool kDefaultRecursiveValue = false; +#endif + +} // namespace class DirectoryWatcherTest : public testing::Test, public DirectoryWatcher::Delegate { protected: virtual void SetUp() { // Name a subdirectory of the temp directory. - std::wstring path_str; - ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &path_str)); - test_dir_ = FilePath(path_str).Append( - FILE_PATH_LITERAL("DirectoryWatcherTest")); + FilePath path; + ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &path)); + test_dir_ = path.Append(FILE_PATH_LITERAL("DirectoryWatcherTest")); // Create a fresh, empty copy of this directory. - file_util::Delete(test_dir_.value(), true); - file_util::CreateDirectory(test_dir_.value()); + 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_; - if (directory_mods_ == quit_mod_count_) + // 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() { + // Make sure there are no tasks in the loop. + loop_.RunAllPending(); + // Clean up test directory. - ASSERT_TRUE(file_util::Delete(test_dir_.value(), true)); - ASSERT_FALSE(file_util::PathExists(test_dir_.value())); + ASSERT_TRUE(file_util::Delete(test_dir_, true)); + ASSERT_FALSE(file_util::PathExists(test_dir_)); } // Write |content| to a file under the test directory. void WriteTestDirFile(const FilePath::StringType& filename, const std::string& content) { FilePath path = test_dir_.Append(filename); - - std::ofstream file; - file.open(WideToUTF8(path.value()).c_str()); - file << content; - file.close(); + file_util::WriteFile(path, content.c_str(), content.length()); } - // Run the message loop until we've seen |n| directory modifications. - void LoopUntilModsEqual(int n) { + void SetExpectedNumberOfModifications(int n) { quit_mod_count_ = n; + } + + void VerifyExpectedNumberOfModifications() { + // Check that we get at least the expected number of notifications. + if (quit_mod_count_ - directory_mods_ > 0) + loop_.Run(); + + // Check that we get no more than the expected number of notifications. + loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, + kWaitForEventTime); + loop_.Run(); + EXPECT_EQ(quit_mod_count_, directory_mods_); + } + + // 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(); } @@ -81,63 +117,89 @@ class DirectoryWatcherTest : public testing::Test, // The number of directory mods which, when reached, cause us to quit // our message loop. int quit_mod_count_; + + // Keep track of original thread id to verify that callbacks are called + // on the same thread. + PlatformThreadId original_thread_id_; }; // Basic test: add a file and verify we notice it. TEST_F(DirectoryWatcherTest, NewFile) { DirectoryWatcher watcher; - ASSERT_TRUE(watcher.Watch(test_dir_, this)); + ASSERT_TRUE(watcher.Watch(test_dir_, this, kDefaultRecursiveValue)); + SetExpectedNumberOfModifications(2); WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some content"); - LoopUntilModsEqual(2); + VerifyExpectedNumberOfModifications(); } // Verify that modifying a file is caught. TEST_F(DirectoryWatcherTest, ModifiedFile) { DirectoryWatcher watcher; - ASSERT_TRUE(watcher.Watch(test_dir_, this)); + ASSERT_TRUE(watcher.Watch(test_dir_, this, kDefaultRecursiveValue)); // Write a file to the test dir. + SetExpectedNumberOfModifications(2); WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some content"); - LoopUntilModsEqual(2); + VerifyExpectedNumberOfModifications(); // Now make sure we get notified if the file is modified. WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some new content"); - LoopUntilModsEqual(3); + // 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(); } // Verify that letting the watcher go out of scope stops notifications. TEST_F(DirectoryWatcherTest, Unregister) { { DirectoryWatcher watcher; - ASSERT_TRUE(watcher.Watch(test_dir_, this)); + ASSERT_TRUE(watcher.Watch(test_dir_, this, kDefaultRecursiveValue)); // And then let it fall out of scope, clearing its watch. } // Write a file to the test dir. + SetExpectedNumberOfModifications(0); WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some content"); - - // We won't get a notification, so we just wait around a bit to verify - // that notification doesn't come. - loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, - kWaitForEventTime); - loop_.Run(); - - ASSERT_EQ(directory_mods_, 0); + VerifyExpectedNumberOfModifications(); } -// Verify that modifications to a subdirectory are noticed. TEST_F(DirectoryWatcherTest, SubDir) { FilePath subdir(FILE_PATH_LITERAL("SubDir")); ASSERT_TRUE(file_util::CreateDirectory(test_dir_.Append(subdir))); - DirectoryWatcher watcher; - ASSERT_TRUE(watcher.Watch(test_dir_, this)); - // Write a file to the subdir. - FilePath test_path = subdir.AppendASCII("test_file"); - WriteTestDirFile(test_path.value(), "some content"); - LoopUntilModsEqual(2); +#if defined(OS_WIN) + // TODO(port): Recursive watches are not implemented on Linux. + + // Verify that modifications to a subdirectory are noticed by recursive watch. + { + DirectoryWatcher watcher; + ASSERT_TRUE(watcher.Watch(test_dir_, this, true)); + // Write a file to the subdir. + SetExpectedNumberOfModifications(2); + FilePath test_path = subdir.AppendASCII("test_file"); + WriteTestDirFile(test_path.value(), "some content"); + VerifyExpectedNumberOfModifications(); + } +#endif // defined(OS_WIN) + +#if !defined(OS_WIN) + // TODO: Enable when the root cause of http://crbug.com/5072 is fixed. + + // Verify that modifications to a subdirectory are not noticed + // by a not-recursive watch. + { + DirectoryWatcher watcher; + ASSERT_TRUE(watcher.Watch(test_dir_, this, false)); + // Write a file to the subdir. + SetExpectedNumberOfModifications(0); + FilePath test_path = subdir.AppendASCII("test_file"); + WriteTestDirFile(test_path.value(), "some content"); + VerifyExpectedNumberOfModifications(); + } +#endif // !defined(OS_WIN) } namespace { @@ -145,34 +207,77 @@ namespace { // Deletes the DirectoryWatcher when it's notified. class Deleter : public DirectoryWatcher::Delegate { public: - Deleter(DirectoryWatcher* watcher) : watcher_(watcher) {} + Deleter(DirectoryWatcher* watcher, MessageLoop* loop) + : watcher_(watcher), + loop_(loop) { + } + virtual void OnDirectoryChanged(const FilePath& path) { watcher_.reset(NULL); - MessageLoop::current()->Quit(); + loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); } scoped_ptr<DirectoryWatcher> watcher_; + MessageLoop* loop_; }; } // anonymous namespace // Verify that deleting a watcher during the callback TEST_F(DirectoryWatcherTest, DeleteDuringNotify) { DirectoryWatcher* watcher = new DirectoryWatcher; - Deleter deleter(watcher); // Takes ownership of watcher. - ASSERT_TRUE(watcher->Watch(test_dir_, &deleter)); + Deleter deleter(watcher, &loop_); // Takes ownership of watcher. + ASSERT_TRUE(watcher->Watch(test_dir_, &deleter, kDefaultRecursiveValue)); WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some content"); - LoopUntilModsEqual(2); + loop_.Run(); // We win if we haven't crashed yet. // Might as well double-check it got deleted, too. ASSERT_TRUE(deleter.watcher_.get() == NULL); } +TEST_F(DirectoryWatcherTest, MultipleWatchersSingleFile) { + DirectoryWatcher watcher1, watcher2; + ASSERT_TRUE(watcher1.Watch(test_dir_, this, kDefaultRecursiveValue)); + ASSERT_TRUE(watcher2.Watch(test_dir_, this, kDefaultRecursiveValue)); + + SetExpectedNumberOfModifications(4); // Each watcher should fire twice. + WriteTestDirFile(FILE_PATH_LITERAL("test_file"), "some content"); + VerifyExpectedNumberOfModifications(); +} + +TEST_F(DirectoryWatcherTest, MultipleWatchersDifferentFiles) { + const int kNumberOfWatchers = 5; + DirectoryWatcher watchers[kNumberOfWatchers]; + 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, + kDefaultRecursiveValue)); + } + 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_); + + // Write a file to the subdir. + FilePath test_path = subdirs[i].AppendASCII("test_file"); + SetExpectedNumberOfModifications(2); + WriteTestDirFile(test_path.value(), "some content"); + VerifyExpectedNumberOfModifications(); + + directory_mods_ = 0; + } +} + // Verify that watching a directory that doesn't exist fails, but doesn't // asssert. // 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"), this, + kDefaultRecursiveValue)); } |