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-03-18 14:35:58 +0000
committerphajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-18 14:35:58 +0000
commit34c70c9f8f89e5293cc9c6de9742adfbba5810bf (patch)
tree0da65c6ac92bdb7f2f68193a61efb93e8a4646b1 /base/directory_watcher_unittest.cc
parentb8096e69fa183c6facc254b7c7b78cb5099dd770 (diff)
downloadchromium_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.cc195
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));
}