| OLD | NEW |
| 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/file_watcher.h" | 5 #include "chrome/browser/file_watcher.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 10 #include "base/file_path.h" | 10 #include "base/file_path.h" |
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "base/path_service.h" | 13 #include "base/path_service.h" |
| 14 #include "base/platform_thread.h" | 14 #include "base/platform_thread.h" |
| 15 #include "base/scoped_temp_dir.h" | 15 #include "base/scoped_temp_dir.h" |
| 16 #include "base/string_util.h" | 16 #include "base/string_util.h" |
| 17 #include "base/thread.h" | 17 #include "base/thread.h" |
| 18 #if defined(OS_WIN) | |
| 19 #include "base/win_util.h" | |
| 20 #endif // defined(OS_WIN) | |
| 21 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
| 22 | 19 |
| 23 namespace { | 20 namespace { |
| 24 | 21 |
| 25 // For tests where we wait a bit to verify nothing happened | 22 // For tests where we wait a bit to verify nothing happened |
| 26 const int kWaitForEventTime = 500; | 23 const int kWaitForEventTime = 500; |
| 27 | 24 |
| 28 class FileWatcherTest : public testing::Test { | 25 class FileWatcherTest : public testing::Test { |
| 29 public: | 26 public: |
| 30 // Implementation of FileWatcher on Mac requires UI loop. | 27 // Implementation of FileWatcher on Mac requires UI loop. |
| 31 FileWatcherTest() | 28 FileWatcherTest() |
| 32 : loop_(MessageLoop::TYPE_UI), | 29 : loop_(MessageLoop::TYPE_UI), |
| 30 ui_thread_(ChromeThread::UI, &loop_), |
| 31 file_thread_(ChromeThread::FILE, &loop_), |
| 33 notified_delegates_(0), | 32 notified_delegates_(0), |
| 34 expected_notified_delegates_(0) { | 33 expected_notified_delegates_(0) { |
| 35 } | 34 } |
| 36 | 35 |
| 37 void OnTestDelegateFirstNotification() { | 36 void OnTestDelegateFirstNotification() { |
| 38 notified_delegates_++; | 37 notified_delegates_++; |
| 39 if (notified_delegates_ >= expected_notified_delegates_) | 38 if (notified_delegates_ >= expected_notified_delegates_) |
| 40 MessageLoop::current()->Quit(); | 39 MessageLoop::current()->Quit(); |
| 41 } | 40 } |
| 42 | 41 |
| 43 protected: | 42 protected: |
| 44 virtual void SetUp() { | 43 virtual void SetUp() { |
| 45 temp_dir_.reset(new ScopedTempDir); | 44 temp_dir_.reset(new ScopedTempDir); |
| 46 ASSERT_TRUE(temp_dir_->CreateUniqueTempDir()); | 45 ASSERT_TRUE(temp_dir_->CreateUniqueTempDir()); |
| 47 } | 46 } |
| 48 | 47 |
| 49 FilePath test_file() { | 48 FilePath test_file() { |
| 50 return temp_dir_->path().AppendASCII("FileWatcherTest"); | 49 return temp_dir_->path().AppendASCII("FileWatcherTest"); |
| 51 } | 50 } |
| 52 | 51 |
| 53 virtual void TearDown() { | |
| 54 // Make sure there are no tasks in the loop. | |
| 55 loop_.RunAllPending(); | |
| 56 } | |
| 57 | |
| 58 // Write |content| to the test file. Returns true on success. | 52 // Write |content| to the test file. Returns true on success. |
| 59 bool WriteTestFile(const std::string& content) { | 53 bool WriteTestFile(const std::string& content) { |
| 60 int write_size = file_util::WriteFile(test_file(), content.c_str(), | 54 int write_size = file_util::WriteFile(test_file(), content.c_str(), |
| 61 content.length()); | 55 content.length()); |
| 62 return write_size == static_cast<int>(content.length()); | 56 return write_size == static_cast<int>(content.length()); |
| 63 } | 57 } |
| 64 | 58 |
| 65 void SetExpectedNumberOfNotifiedDelegates(int n) { | 59 void SetExpectedNumberOfNotifiedDelegates(int n) { |
| 66 notified_delegates_ = 0; | 60 notified_delegates_ = 0; |
| 67 expected_notified_delegates_ = n; | 61 expected_notified_delegates_ = n; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 86 // has a latency interval and can merge multiple events into one, | 80 // has a latency interval and can merge multiple events into one, |
| 87 // and we need a clear distinction between events triggered by test setup code | 81 // and we need a clear distinction between events triggered by test setup code |
| 88 // and test code. | 82 // and test code. |
| 89 void SyncIfPOSIX() { | 83 void SyncIfPOSIX() { |
| 90 #if defined(OS_POSIX) | 84 #if defined(OS_POSIX) |
| 91 sync(); | 85 sync(); |
| 92 #endif // defined(OS_POSIX) | 86 #endif // defined(OS_POSIX) |
| 93 } | 87 } |
| 94 | 88 |
| 95 MessageLoop loop_; | 89 MessageLoop loop_; |
| 90 ChromeThread ui_thread_; |
| 91 ChromeThread file_thread_; |
| 96 scoped_ptr<ScopedTempDir> temp_dir_; | 92 scoped_ptr<ScopedTempDir> temp_dir_; |
| 97 | 93 |
| 98 // The number of test delegates which received their notification. | 94 // The number of test delegates which received their notification. |
| 99 int notified_delegates_; | 95 int notified_delegates_; |
| 100 | 96 |
| 101 // The number of notified test delegates after which we quit the message loop. | 97 // The number of notified test delegates after which we quit the message loop. |
| 102 int expected_notified_delegates_; | 98 int expected_notified_delegates_; |
| 103 }; | 99 }; |
| 104 | 100 |
| 105 class TestDelegate : public FileWatcher::Delegate { | 101 class TestDelegate : public FileWatcher::Delegate { |
| 106 public: | 102 public: |
| 107 explicit TestDelegate(FileWatcherTest* test) | 103 explicit TestDelegate(FileWatcherTest* test) |
| 108 : test_(test), | 104 : test_(test), |
| 109 got_notification_(false), | 105 got_notification_(false) { |
| 110 original_thread_id_(PlatformThread::CurrentId()) { | |
| 111 } | 106 } |
| 112 | 107 |
| 113 bool got_notification() const { | 108 bool got_notification() const { |
| 114 return got_notification_; | 109 return got_notification_; |
| 115 } | 110 } |
| 116 | 111 |
| 117 void reset() { | 112 void reset() { |
| 118 got_notification_ = false; | 113 got_notification_ = false; |
| 119 } | 114 } |
| 120 | 115 |
| 121 virtual void OnFileChanged(const FilePath& path) { | 116 virtual void OnFileChanged(const FilePath& path) { |
| 122 EXPECT_EQ(original_thread_id_, PlatformThread::CurrentId()); | 117 EXPECT_TRUE(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 123 if (!got_notification_) | 118 if (!got_notification_) |
| 124 test_->OnTestDelegateFirstNotification(); | 119 test_->OnTestDelegateFirstNotification(); |
| 125 got_notification_ = true; | 120 got_notification_ = true; |
| 126 } | 121 } |
| 127 | 122 |
| 128 private: | 123 private: |
| 129 // Hold a pointer to current test fixture to inform it on first notification. | 124 // Hold a pointer to current test fixture to inform it on first notification. |
| 130 FileWatcherTest* test_; | 125 FileWatcherTest* test_; |
| 131 | 126 |
| 132 // Set to true after first notification. | 127 // Set to true after first notification. |
| 133 bool got_notification_; | 128 bool got_notification_; |
| 134 | |
| 135 // Keep track of original thread id to verify that callbacks are called | |
| 136 // on the same thread. | |
| 137 PlatformThreadId original_thread_id_; | |
| 138 }; | 129 }; |
| 139 | 130 |
| 140 // Basic test: Create the file and verify that we notice. | 131 // Basic test: Create the file and verify that we notice. |
| 141 TEST_F(FileWatcherTest, NewFile) { | 132 TEST_F(FileWatcherTest, NewFile) { |
| 142 FileWatcher watcher; | 133 FileWatcher watcher; |
| 143 TestDelegate delegate(this); | 134 TestDelegate delegate(this); |
| 144 ASSERT_TRUE(watcher.Watch(test_file(), &delegate, NULL)); | 135 ASSERT_TRUE(watcher.Watch(test_file(), &delegate)); |
| 145 | 136 |
| 146 SetExpectedNumberOfNotifiedDelegates(1); | 137 SetExpectedNumberOfNotifiedDelegates(1); |
| 147 ASSERT_TRUE(WriteTestFile("content")); | 138 ASSERT_TRUE(WriteTestFile("content")); |
| 148 VerifyExpectedNumberOfNotifiedDelegates(); | 139 VerifyExpectedNumberOfNotifiedDelegates(); |
| 149 } | 140 } |
| 150 | 141 |
| 151 // Verify that modifying the file is caught. | 142 // Verify that modifying the file is caught. |
| 152 TEST_F(FileWatcherTest, ModifiedFile) { | 143 TEST_F(FileWatcherTest, ModifiedFile) { |
| 153 ASSERT_TRUE(WriteTestFile("content")); | 144 ASSERT_TRUE(WriteTestFile("content")); |
| 154 SyncIfPOSIX(); | 145 SyncIfPOSIX(); |
| 155 | 146 |
| 156 FileWatcher watcher; | 147 FileWatcher watcher; |
| 157 TestDelegate delegate(this); | 148 TestDelegate delegate(this); |
| 158 ASSERT_TRUE(watcher.Watch(test_file(), &delegate, NULL)); | 149 ASSERT_TRUE(watcher.Watch(test_file(), &delegate)); |
| 159 | 150 |
| 160 // Now make sure we get notified if the file is modified. | 151 // Now make sure we get notified if the file is modified. |
| 161 SetExpectedNumberOfNotifiedDelegates(1); | 152 SetExpectedNumberOfNotifiedDelegates(1); |
| 162 ASSERT_TRUE(WriteTestFile("new content")); | 153 ASSERT_TRUE(WriteTestFile("new content")); |
| 163 VerifyExpectedNumberOfNotifiedDelegates(); | 154 VerifyExpectedNumberOfNotifiedDelegates(); |
| 164 } | 155 } |
| 165 | 156 |
| 166 TEST_F(FileWatcherTest, DeletedFile) { | 157 TEST_F(FileWatcherTest, DeletedFile) { |
| 167 ASSERT_TRUE(WriteTestFile("content")); | 158 ASSERT_TRUE(WriteTestFile("content")); |
| 168 SyncIfPOSIX(); | 159 SyncIfPOSIX(); |
| 169 | 160 |
| 170 FileWatcher watcher; | 161 FileWatcher watcher; |
| 171 TestDelegate delegate(this); | 162 TestDelegate delegate(this); |
| 172 ASSERT_TRUE(watcher.Watch(test_file(), &delegate, NULL)); | 163 ASSERT_TRUE(watcher.Watch(test_file(), &delegate)); |
| 173 | 164 |
| 174 // Now make sure we get notified if the file is deleted. | 165 // Now make sure we get notified if the file is deleted. |
| 175 SetExpectedNumberOfNotifiedDelegates(1); | 166 SetExpectedNumberOfNotifiedDelegates(1); |
| 176 file_util::Delete(test_file(), false); | 167 file_util::Delete(test_file(), false); |
| 177 VerifyExpectedNumberOfNotifiedDelegates(); | 168 VerifyExpectedNumberOfNotifiedDelegates(); |
| 178 } | 169 } |
| 179 | 170 |
| 180 // Verify that letting the watcher go out of scope stops notifications. | 171 // Verify that letting the watcher go out of scope stops notifications. |
| 181 TEST_F(FileWatcherTest, Unregister) { | 172 TEST_F(FileWatcherTest, Unregister) { |
| 182 TestDelegate delegate(this); | 173 TestDelegate delegate(this); |
| 183 | 174 |
| 184 { | 175 { |
| 185 FileWatcher watcher; | 176 FileWatcher watcher; |
| 186 ASSERT_TRUE(watcher.Watch(test_file(), &delegate, NULL)); | 177 ASSERT_TRUE(watcher.Watch(test_file(), &delegate)); |
| 187 | 178 |
| 188 // And then let it fall out of scope, clearing its watch. | 179 // And then let it fall out of scope, clearing its watch. |
| 189 } | 180 } |
| 190 | 181 |
| 191 // Write a file to the test dir. | 182 // Write a file to the test dir. |
| 192 SetExpectedNumberOfNotifiedDelegates(0); | 183 SetExpectedNumberOfNotifiedDelegates(0); |
| 193 ASSERT_TRUE(WriteTestFile("content")); | 184 ASSERT_TRUE(WriteTestFile("content")); |
| 194 VerifyExpectedNumberOfNotifiedDelegates(); | 185 VerifyExpectedNumberOfNotifiedDelegates(); |
| 195 VerifyNoExtraNotifications(); | 186 VerifyNoExtraNotifications(); |
| 196 } | 187 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 213 | 204 |
| 214 scoped_ptr<FileWatcher> watcher_; | 205 scoped_ptr<FileWatcher> watcher_; |
| 215 MessageLoop* loop_; | 206 MessageLoop* loop_; |
| 216 }; | 207 }; |
| 217 } // anonymous namespace | 208 } // anonymous namespace |
| 218 | 209 |
| 219 // Verify that deleting a watcher during the callback doesn't crash. | 210 // Verify that deleting a watcher during the callback doesn't crash. |
| 220 TEST_F(FileWatcherTest, DeleteDuringNotify) { | 211 TEST_F(FileWatcherTest, DeleteDuringNotify) { |
| 221 FileWatcher* watcher = new FileWatcher; | 212 FileWatcher* watcher = new FileWatcher; |
| 222 Deleter deleter(watcher, &loop_); // Takes ownership of watcher. | 213 Deleter deleter(watcher, &loop_); // Takes ownership of watcher. |
| 223 ASSERT_TRUE(watcher->Watch(test_file(), &deleter, NULL)); | 214 ASSERT_TRUE(watcher->Watch(test_file(), &deleter)); |
| 224 | 215 |
| 225 ASSERT_TRUE(WriteTestFile("content")); | 216 ASSERT_TRUE(WriteTestFile("content")); |
| 226 loop_.Run(); | 217 loop_.Run(); |
| 227 | 218 |
| 228 // We win if we haven't crashed yet. | 219 // We win if we haven't crashed yet. |
| 229 // Might as well double-check it got deleted, too. | 220 // Might as well double-check it got deleted, too. |
| 230 ASSERT_TRUE(deleter.watcher_.get() == NULL); | 221 ASSERT_TRUE(deleter.watcher_.get() == NULL); |
| 231 } | 222 } |
| 232 | 223 |
| 233 TEST_F(FileWatcherTest, BackendLoop) { | |
| 234 base::Thread thread("test"); | |
| 235 ASSERT_TRUE(thread.Start()); | |
| 236 | |
| 237 FileWatcher watcher; | |
| 238 TestDelegate delegate(this); | |
| 239 ASSERT_TRUE(watcher.Watch(test_file(), &delegate, thread.message_loop())); | |
| 240 } | |
| 241 | |
| 242 TEST_F(FileWatcherTest, MultipleWatchersSingleFile) { | 224 TEST_F(FileWatcherTest, MultipleWatchersSingleFile) { |
| 243 FileWatcher watcher1, watcher2; | 225 FileWatcher watcher1, watcher2; |
| 244 TestDelegate delegate1(this), delegate2(this); | 226 TestDelegate delegate1(this), delegate2(this); |
| 245 ASSERT_TRUE(watcher1.Watch(test_file(), &delegate1, NULL)); | 227 ASSERT_TRUE(watcher1.Watch(test_file(), &delegate1)); |
| 246 ASSERT_TRUE(watcher2.Watch(test_file(), &delegate2, NULL)); | 228 ASSERT_TRUE(watcher2.Watch(test_file(), &delegate2)); |
| 247 | 229 |
| 248 SetExpectedNumberOfNotifiedDelegates(2); | 230 SetExpectedNumberOfNotifiedDelegates(2); |
| 249 ASSERT_TRUE(WriteTestFile("content")); | 231 ASSERT_TRUE(WriteTestFile("content")); |
| 250 VerifyExpectedNumberOfNotifiedDelegates(); | 232 VerifyExpectedNumberOfNotifiedDelegates(); |
| 251 } | 233 } |
| 252 | 234 |
| 253 // Verify that watching a file who's parent directory doesn't exist | 235 // Verify that watching a file who's parent directory doesn't exist |
| 254 // fails, but doesn't asssert. | 236 // fails, but doesn't asssert. |
| 255 TEST_F(FileWatcherTest, NonExistentDirectory) { | 237 TEST_F(FileWatcherTest, NonExistentDirectory) { |
| 256 FileWatcher watcher; | 238 FileWatcher watcher; |
| 257 ASSERT_FALSE(watcher.Watch(test_file().AppendASCII("FileToWatch"), | 239 ASSERT_FALSE(watcher.Watch(test_file().AppendASCII("FileToWatch"), NULL)); |
| 258 NULL, NULL)); | |
| 259 } | 240 } |
| 260 | 241 |
| 261 } // namespace | 242 } // namespace |
| OLD | NEW |