summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authormnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-15 17:04:47 +0000
committermnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-15 17:04:47 +0000
commit738f732e605b8e66d11a47e06674848406a52d63 (patch)
treeb73cec8b639fb22fffe176750e0d4203dffa6d56 /chrome
parent1e9bbd23e23395eb4d0566b768452f90530de638 (diff)
downloadchromium_src-738f732e605b8e66d11a47e06674848406a52d63.zip
chromium_src-738f732e605b8e66d11a47e06674848406a52d63.tar.gz
chromium_src-738f732e605b8e66d11a47e06674848406a52d63.tar.bz2
Cut down timeouts in FilePathWatcherTest.
Make the test continue immediately when a notification is received and remove all tests that check for the absence of notifications, the FilePathWatcher code may generate spurious notifications anyway. Move the tests over to browser_tests so they can run in a separate process. This avoid tinkering with the message loop to catch timeouts but just uses the built-in browser_tests timeouts. BUG=56868 TEST=Running FilePathWatcherTest should take only a few seconds instead of up to a minute. Review URL: http://codereview.chromium.org/3555016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62748 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/file_path_watcher_browsertest.cc (renamed from chrome/browser/file_path_watcher_unittest.cc)249
-rw-r--r--chrome/browser/file_path_watcher_win.cc1
-rw-r--r--chrome/chrome_tests.gypi2
3 files changed, 121 insertions, 131 deletions
diff --git a/chrome/browser/file_path_watcher_unittest.cc b/chrome/browser/file_path_watcher_browsertest.cc
index c01a2af..0ae4fc1 100644
--- a/chrome/browser/file_path_watcher_unittest.cc
+++ b/chrome/browser/file_path_watcher_browsertest.cc
@@ -4,18 +4,18 @@
#include "chrome/browser/file_path_watcher.h"
-#include <limits>
+#include <set>
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
-#include "base/lock.h"
#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
#include "base/path_service.h"
#include "base/platform_thread.h"
#include "base/scoped_temp_dir.h"
#include "base/string_util.h"
-#include "base/thread.h"
+#include "base/stl_util-inl.h"
#include "base/waitable_event.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -29,44 +29,73 @@
namespace {
-// The time we wait for events to happen. It should be large enough to be
-// reasonably sure all notifications sent in response to file system
-// modifications made by the test are processed. This must also accomodate for
-// the latency interval we pass to the Mac FSEvents API.
-const int kWaitForEventTime = 1000;
+class TestDelegate;
+
+// Aggregates notifications from the test delegates and breaks the message loop
+// the test thread is waiting on once they all came in.
+class NotificationCollector
+ : public base::RefCountedThreadSafe<NotificationCollector> {
+ public:
+ NotificationCollector()
+ : loop_(base::MessageLoopProxy::CreateForCurrentThread()) {}
+
+ // Called from the file thread by the delegates.
+ void OnChange(TestDelegate* delegate) {
+ loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &NotificationCollector::RecordChange,
+ delegate));
+ }
+
+ void Register(TestDelegate* delegate) {
+ delegates_.insert(delegate);
+ }
+
+ void Reset() {
+ signaled_.clear();
+ }
+
+ private:
+ void RecordChange(TestDelegate* delegate) {
+ ASSERT_TRUE(loop_->BelongsToCurrentThread());
+ ASSERT_TRUE(delegates_.count(delegate));
+ signaled_.insert(delegate);
+
+ // Check whether all delegates have been signaled.
+ if (signaled_ == delegates_)
+ loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ }
+
+ // Set of registered delegates.
+ std::set<TestDelegate*> delegates_;
+
+ // Set of signaled delegates.
+ std::set<TestDelegate*> signaled_;
+
+ // The loop we should break after all delegates signaled.
+ scoped_refptr<base::MessageLoopProxy> loop_;
+};
// A mock FilePathWatcher::Delegate for testing. I'd rather use gmock, but it's
// not thread safe for setting expectations, so the test code couldn't safely
// reset expectations while the file watcher is running. In order to allow this,
-// we implement simple thread safe call counters in TestDelegate.
+// we keep simple thread safe status flags in TestDelegate.
class TestDelegate : public FilePathWatcher::Delegate {
public:
- TestDelegate()
- : change_count_(0),
- error_count_(0) {}
-
- virtual void OnFilePathChanged(const FilePath&) {
- AutoLock lock(lock_);
- ++change_count_;
- }
-
- virtual void OnError() {
- AutoLock lock(lock_);
- ++error_count_;
+ // The message loop specified by |loop| will be quit if a notification is
+ // received while the delegate is |armed_|. Note that the testing code must
+ // guarantee |loop| outlives the file thread on which OnFilePathChanged runs.
+ explicit TestDelegate(NotificationCollector* collector)
+ : collector_(collector) {
+ collector_->Register(this);
}
- void GetCountsAndReset(int* changes, int* errors) {
- AutoLock lock(lock_);
- *errors = error_count_;
- *changes = change_count_;
- error_count_ = 0;
- change_count_ = 0;
+ virtual void OnFilePathChanged(const FilePath&) {
+ collector_->OnChange(this);
}
private:
- Lock lock_;
- int change_count_;
- int error_count_;
+ scoped_refptr<NotificationCollector> collector_;
DISALLOW_COPY_AND_ASSIGN(TestDelegate);
};
@@ -115,6 +144,7 @@ class FilePathWatcherTest : public testing::Test {
file_thread_->Start();
temp_dir_.reset(new ScopedTempDir);
ASSERT_TRUE(temp_dir_->CreateUniqueTempDir());
+ collector_ = new NotificationCollector();
}
virtual void TearDown() {
@@ -130,7 +160,6 @@ class FilePathWatcherTest : public testing::Test {
bool WriteFile(const FilePath& file, const std::string& content) {
int write_size = file_util::WriteFile(file, content.c_str(),
content.length());
- SyncIfPOSIX();
return write_size == static_cast<int>(content.length());
}
@@ -145,42 +174,28 @@ class FilePathWatcherTest : public testing::Test {
ASSERT_TRUE(result);
}
- int WaitForEvents(TestDelegate* delegate) {
- // Wait for events and check the expectations of the delegate.
- loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask,
- kWaitForEventTime);
+ void WaitForEvents() {
+ collector_->Reset();
loop_.Run();
- int errors;
- int changes;
- delegate->GetCountsAndReset(&changes, &errors);
- EXPECT_EQ(0, errors);
- return changes;
}
- // 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)
- }
+ NotificationCollector* collector() { return collector_.get(); }
MessageLoop loop_;
BrowserThread ui_thread_;
scoped_ptr<BrowserThread> file_thread_;
scoped_ptr<ScopedTempDir> temp_dir_;
+ scoped_refptr<NotificationCollector> collector_;
};
// Basic test: Create the file and verify that we notice.
TEST_F(FilePathWatcherTest, MAYBE(NewFile)) {
FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
SetupWatch(test_file(), &watcher, delegate.get());
ASSERT_TRUE(WriteFile(test_file(), "content"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ WaitForEvents();
}
// Verify that modifying the file is caught.
@@ -188,12 +203,12 @@ TEST_F(FilePathWatcherTest, MAYBE(ModifiedFile)) {
ASSERT_TRUE(WriteFile(test_file(), "content"));
FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
SetupWatch(test_file(), &watcher, delegate.get());
// Now make sure we get notified if the file is modified.
ASSERT_TRUE(WriteFile(test_file(), "new content"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ WaitForEvents();
}
// Verify that moving the file into place is caught.
@@ -202,44 +217,26 @@ TEST_F(FilePathWatcherTest, MAYBE(MovedFile)) {
ASSERT_TRUE(WriteFile(source_file, "content"));
FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
SetupWatch(test_file(), &watcher, delegate.get());
// Now make sure we get notified if the file is modified.
ASSERT_TRUE(file_util::Move(source_file, test_file()));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ WaitForEvents();
}
TEST_F(FilePathWatcherTest, MAYBE(DeletedFile)) {
ASSERT_TRUE(WriteFile(test_file(), "content"));
FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
SetupWatch(test_file(), &watcher, delegate.get());
// Now make sure we get notified if the file is deleted.
file_util::Delete(test_file(), false);
- SyncIfPOSIX();
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ WaitForEvents();
}
-// Verify that letting the watcher go out of scope stops notifications.
-TEST_F(FilePathWatcherTest, Unregister) {
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
-
- {
- FilePathWatcher watcher;
- SetupWatch(test_file(), &watcher, delegate.get());
-
- // And then let it fall out of scope, clearing its watch.
- }
-
- // Write a file to the test dir.
- ASSERT_TRUE(WriteFile(test_file(), "content"));
- EXPECT_EQ(0, WaitForEvents(delegate.get()));
-}
-
-namespace {
// Used by the DeleteDuringNotify test below.
// Deletes the FilePathWatcher when it's notified.
class Deleter : public FilePathWatcher::Delegate {
@@ -257,7 +254,6 @@ class Deleter : public FilePathWatcher::Delegate {
scoped_ptr<FilePathWatcher> watcher_;
MessageLoop* loop_;
};
-} // anonymous namespace
// Verify that deleting a watcher during the callback doesn't crash.
TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
@@ -267,7 +263,7 @@ TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
SetupWatch(test_file(), watcher, deleter.get());
ASSERT_TRUE(WriteFile(test_file(), "content"));
- loop_.Run();
+ WaitForEvents();
// We win if we haven't crashed yet.
// Might as well double-check it got deleted, too.
@@ -277,25 +273,22 @@ TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
// Verify that deleting the watcher works even if there is a pending
// notification.
TEST_F(FilePathWatcherTest, DestroyWithPendingNotification) {
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
FilePathWatcher* watcher = new FilePathWatcher;
SetupWatch(test_file(), watcher, delegate.get());
ASSERT_TRUE(WriteFile(test_file(), "content"));
BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, watcher);
- // Success if there is no crash or DCHECK when running the callback.
- WaitForEvents(delegate.get());
}
TEST_F(FilePathWatcherTest, MAYBE(MultipleWatchersSingleFile)) {
FilePathWatcher watcher1, watcher2;
- scoped_refptr<TestDelegate> delegate1(new TestDelegate);
- scoped_refptr<TestDelegate> delegate2(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector()));
+ scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector()));
SetupWatch(test_file(), &watcher1, delegate1.get());
SetupWatch(test_file(), &watcher2, delegate2.get());
ASSERT_TRUE(WriteFile(test_file(), "content"));
- EXPECT_LE(1, WaitForEvents(delegate1.get()));
- EXPECT_LE(1, WaitForEvents(delegate2.get()));
+ WaitForEvents();
}
// Verify that watching a file whose parent directory doesn't exist yet works if
@@ -304,20 +297,22 @@ TEST_F(FilePathWatcherTest, NonExistentDirectory) {
FilePathWatcher watcher;
FilePath dir(temp_dir_->path().AppendASCII("dir"));
FilePath file(dir.AppendASCII("file"));
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
SetupWatch(file, &watcher, delegate.get());
ASSERT_TRUE(file_util::CreateDirectory(dir));
- EXPECT_EQ(0, WaitForEvents(delegate.get()));
ASSERT_TRUE(WriteFile(file, "content"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file creation";
+ WaitForEvents();
ASSERT_TRUE(WriteFile(file, "content v2"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file change";
+ WaitForEvents();
ASSERT_TRUE(file_util::Delete(file, false));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file deletion";
+ WaitForEvents();
}
// Exercises watch reconfiguration for the case that directories on the path
@@ -333,7 +328,7 @@ TEST_F(FilePathWatcherTest, DirectoryChain) {
FilePathWatcher watcher;
FilePath file(path.AppendASCII("file"));
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
SetupWatch(file, &watcher, delegate.get());
FilePath sub_path(temp_dir_->path());
@@ -343,10 +338,12 @@ TEST_F(FilePathWatcherTest, DirectoryChain) {
ASSERT_TRUE(file_util::CreateDirectory(sub_path));
}
ASSERT_TRUE(WriteFile(file, "content"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file creation";
+ WaitForEvents();
ASSERT_TRUE(WriteFile(file, "content v2"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file modification";
+ WaitForEvents();
}
TEST_F(FilePathWatcherTest, DisappearingDirectory) {
@@ -355,31 +352,27 @@ TEST_F(FilePathWatcherTest, DisappearingDirectory) {
FilePath file(dir.AppendASCII("file"));
ASSERT_TRUE(file_util::CreateDirectory(dir));
ASSERT_TRUE(WriteFile(file, "content"));
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
SetupWatch(file, &watcher, delegate.get());
ASSERT_TRUE(file_util::Delete(dir, true));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
-
- ASSERT_TRUE(file_util::CreateDirectory(dir));
- EXPECT_EQ(0, WaitForEvents(delegate.get()));
-
- ASSERT_TRUE(WriteFile(file, "content v2"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ WaitForEvents();
}
// Tests that a file that is deleted and reappears is tracked correctly.
TEST_F(FilePathWatcherTest, DeleteAndRecreate) {
ASSERT_TRUE(WriteFile(test_file(), "content"));
FilePathWatcher watcher;
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
SetupWatch(test_file(), &watcher, delegate.get());
ASSERT_TRUE(file_util::Delete(test_file(), false));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file deletion";
+ WaitForEvents();
ASSERT_TRUE(WriteFile(test_file(), "content"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file creation";
+ WaitForEvents();
}
TEST_F(FilePathWatcherTest, WatchDirectory) {
@@ -387,24 +380,28 @@ TEST_F(FilePathWatcherTest, WatchDirectory) {
FilePath dir(temp_dir_->path().AppendASCII("dir"));
FilePath file1(dir.AppendASCII("file1"));
FilePath file2(dir.AppendASCII("file2"));
- scoped_refptr<TestDelegate> delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
SetupWatch(dir, &watcher, delegate.get());
ASSERT_TRUE(file_util::CreateDirectory(dir));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for directory creation";
+ WaitForEvents();
ASSERT_TRUE(WriteFile(file1, "content"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file1 creation";
+ WaitForEvents();
ASSERT_TRUE(WriteFile(file1, "content v2"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file1 modification";
+ WaitForEvents();
ASSERT_TRUE(file_util::Delete(file1, false));
- SyncIfPOSIX();
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file1 deletion";
+ WaitForEvents();
ASSERT_TRUE(WriteFile(file2, "content"));
- EXPECT_LE(1, WaitForEvents(delegate.get()));
+ LOG(INFO) << "Waiting for file2 creation";
+ WaitForEvents();
}
TEST_F(FilePathWatcherTest, MoveParent) {
@@ -414,27 +411,21 @@ TEST_F(FilePathWatcherTest, MoveParent) {
FilePath dest(temp_dir_->path().AppendASCII("dest"));
FilePath subdir(dir.AppendASCII("subdir"));
FilePath file(subdir.AppendASCII("file"));
- scoped_refptr<TestDelegate> file_delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
SetupWatch(file, &file_watcher, file_delegate.get());
- scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate);
+ scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
SetupWatch(subdir, &subdir_watcher, subdir_delegate.get());
// Setup a directory hierarchy.
ASSERT_TRUE(file_util::CreateDirectory(subdir));
ASSERT_TRUE(WriteFile(file, "content"));
- EXPECT_LE(1, WaitForEvents(file_delegate.get()));
- EXPECT_LE(1, WaitForEvents(subdir_delegate.get()));
+ LOG(INFO) << "Waiting for file creation";
+ WaitForEvents();
// Move the parent directory.
file_util::Move(dir, dest);
- EXPECT_LE(1, WaitForEvents(file_delegate.get()));
- EXPECT_LE(1, WaitForEvents(subdir_delegate.get()));
-
- // Recreate the hierarchy.
- ASSERT_TRUE(file_util::CreateDirectory(subdir));
- ASSERT_TRUE(WriteFile(file, "content"));
- EXPECT_LE(1, WaitForEvents(file_delegate.get()));
- EXPECT_LE(1, WaitForEvents(subdir_delegate.get()));
+ LOG(INFO) << "Waiting for directory move";
+ WaitForEvents();
}
TEST_F(FilePathWatcherTest, MoveChild) {
@@ -446,21 +437,19 @@ TEST_F(FilePathWatcherTest, MoveChild) {
FilePath dest_dir(temp_dir_->path().AppendASCII("dest"));
FilePath dest_subdir(dest_dir.AppendASCII("subdir"));
FilePath dest_file(dest_subdir.AppendASCII("file"));
- scoped_refptr<TestDelegate> file_delegate(new TestDelegate);
- SetupWatch(dest_file, &file_watcher, file_delegate.get());
- scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate);
- SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get());
// Setup a directory hierarchy.
ASSERT_TRUE(file_util::CreateDirectory(source_subdir));
ASSERT_TRUE(WriteFile(source_file, "content"));
- EXPECT_EQ(0, WaitForEvents(file_delegate.get()));
- EXPECT_EQ(0, WaitForEvents(subdir_delegate.get()));
+
+ scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+ SetupWatch(dest_file, &file_watcher, file_delegate.get());
+ scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+ SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get());
// Move the directory into place, s.t. the watched file appears.
ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
- EXPECT_LE(1, WaitForEvents(file_delegate.get()));
- EXPECT_LE(1, WaitForEvents(subdir_delegate.get()));
+ WaitForEvents();
}
} // namespace
diff --git a/chrome/browser/file_path_watcher_win.cc b/chrome/browser/file_path_watcher_win.cc
index 61879e7..7e1f4ec 100644
--- a/chrome/browser/file_path_watcher_win.cc
+++ b/chrome/browser/file_path_watcher_win.cc
@@ -170,6 +170,7 @@ bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
if (error_code != ERROR_FILE_NOT_FOUND &&
error_code != ERROR_PATH_NOT_FOUND &&
error_code != ERROR_ACCESS_DENIED &&
+ error_code != ERROR_SHARING_VIOLATION &&
error_code != ERROR_DIRECTORY) {
PLOG(ERROR) << "FindFirstChangeNotification failed for "
<< dir.value();
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 736a2aa..b34daff 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1265,7 +1265,6 @@
'browser/extensions/sandboxed_extension_unpacker_unittest.cc',
'browser/extensions/user_script_listener_unittest.cc',
'browser/extensions/user_script_master_unittest.cc',
- 'browser/file_path_watcher_unittest.cc',
'browser/find_backend_unittest.cc',
'browser/first_run/first_run_unittest.cc',
'browser/geolocation/fake_access_token_store.h',
@@ -1976,6 +1975,7 @@
'browser/extensions/permissions_apitest.cc',
'browser/extensions/stubs_apitest.cc',
'browser/extensions/window_open_apitest.cc',
+ 'browser/file_path_watcher_browsertest.cc',
'browser/find_bar_host_browsertest.cc',
'browser/first_run/first_run_browsertest.cc',
'browser/geolocation/access_token_store_browsertest.cc',