Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: content/common/file_path_watcher/file_path_watcher_browsertest.cc

Issue 6825063: Patch for bug 74983 (among others) to be applied to M11 696 branch. (Closed) Base URL: svn://svn.chromium.org/chrome/branches/696/src
Patch Set: intentionally disabled mac tests. tested by hand. Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "chrome/browser/file_path_watcher/file_path_watcher.h" 5 #include "content/common/file_path_watcher/file_path_watcher.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #if defined(OS_WIN)
10 #include <windows.h>
11 #include <aclapi.h>
12 #elif defined(OS_POSIX)
13 #include <sys/stat.h>
14 #endif
15
9 #include "base/basictypes.h" 16 #include "base/basictypes.h"
17 #include "base/compiler_specific.h"
10 #include "base/file_path.h" 18 #include "base/file_path.h"
11 #include "base/file_util.h" 19 #include "base/file_util.h"
12 #include "base/message_loop.h" 20 #include "base/message_loop.h"
13 #include "base/message_loop_proxy.h" 21 #include "base/message_loop_proxy.h"
14 #include "base/path_service.h" 22 #include "base/path_service.h"
15 #include "base/scoped_temp_dir.h" 23 #include "base/scoped_temp_dir.h"
16 #include "base/string_util.h" 24 #include "base/string_util.h"
17 #include "base/stl_util-inl.h" 25 #include "base/stl_util-inl.h"
18 #include "base/synchronization/waitable_event.h" 26 #include "base/synchronization/waitable_event.h"
27 #include "base/test/test_timeouts.h"
28 #include "base/threading/thread.h"
19 #include "testing/gtest/include/gtest/gtest.h" 29 #include "testing/gtest/include/gtest/gtest.h"
20 30
21 #if defined(OS_MACOSX)
22 // TODO(mnissler): There are flakes on Mac (http://crbug.com/54822) at least for
23 // FilePathWatcherTest.MultipleWatchersSingleFile.
24 #define MAYBE(name) FLAKY_ ## name
25 #else
26 #define MAYBE(name) name
27 #endif
28
29 namespace { 31 namespace {
30 32
31 class TestDelegate; 33 class TestDelegate;
32 34
33 // Aggregates notifications from the test delegates and breaks the message loop 35 // Aggregates notifications from the test delegates and breaks the message loop
34 // the test thread is waiting on once they all came in. 36 // the test thread is waiting on once they all came in.
35 class NotificationCollector 37 class NotificationCollector
36 : public base::RefCountedThreadSafe<NotificationCollector> { 38 : public base::RefCountedThreadSafe<NotificationCollector> {
37 public: 39 public:
38 NotificationCollector() 40 NotificationCollector()
39 : loop_(base::MessageLoopProxy::CreateForCurrentThread()) {} 41 : loop_(base::MessageLoopProxy::CreateForCurrentThread()) {}
40 42
41 // Called from the file thread by the delegates. 43 // Called from the file thread by the delegates.
42 void OnChange(TestDelegate* delegate) { 44 void OnChange(TestDelegate* delegate) {
43 loop_->PostTask(FROM_HERE, 45 loop_->PostTask(FROM_HERE,
44 NewRunnableMethod(this, 46 NewRunnableMethod(this,
45 &NotificationCollector::RecordChange, 47 &NotificationCollector::RecordChange,
46 make_scoped_refptr(delegate))); 48 make_scoped_refptr(delegate)));
47 } 49 }
48 50
49 void Register(TestDelegate* delegate) { 51 void Register(TestDelegate* delegate) {
50 delegates_.insert(delegate); 52 delegates_.insert(delegate);
51 } 53 }
52 54
53 void Reset() { 55 void Reset() {
54 signaled_.clear(); 56 signaled_.clear();
55 } 57 }
56 58
59 bool Success() {
60 return signaled_ == delegates_;
61 }
62
57 private: 63 private:
58 void RecordChange(TestDelegate* delegate) { 64 void RecordChange(TestDelegate* delegate) {
59 ASSERT_TRUE(loop_->BelongsToCurrentThread()); 65 ASSERT_TRUE(loop_->BelongsToCurrentThread());
60 ASSERT_TRUE(delegates_.count(delegate)); 66 ASSERT_TRUE(delegates_.count(delegate));
61 signaled_.insert(delegate); 67 signaled_.insert(delegate);
62 68
63 // Check whether all delegates have been signaled. 69 // Check whether all delegates have been signaled.
64 if (signaled_ == delegates_) 70 if (signaled_ == delegates_)
65 loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); 71 loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
66 } 72 }
(...skipping 19 matching lines...) Expand all
86 // guarantee |loop| outlives the file thread on which OnFilePathChanged runs. 92 // guarantee |loop| outlives the file thread on which OnFilePathChanged runs.
87 explicit TestDelegate(NotificationCollector* collector) 93 explicit TestDelegate(NotificationCollector* collector)
88 : collector_(collector) { 94 : collector_(collector) {
89 collector_->Register(this); 95 collector_->Register(this);
90 } 96 }
91 97
92 virtual void OnFilePathChanged(const FilePath&) { 98 virtual void OnFilePathChanged(const FilePath&) {
93 collector_->OnChange(this); 99 collector_->OnChange(this);
94 } 100 }
95 101
102 virtual void OnFilePathError(const FilePath& path) {
103 ADD_FAILURE() << "Error " << path.value();
104 }
105
96 private: 106 private:
97 scoped_refptr<NotificationCollector> collector_; 107 scoped_refptr<NotificationCollector> collector_;
98 108
99 DISALLOW_COPY_AND_ASSIGN(TestDelegate); 109 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
100 }; 110 };
101 111
102 // A helper class for setting up watches on the file thread. 112 // A helper class for setting up watches on the file thread.
103 class SetupWatchTask : public Task { 113 class SetupWatchTask : public Task {
104 public: 114 public:
105 SetupWatchTask(const FilePath& target, 115 SetupWatchTask(const FilePath& target,
(...skipping 17 matching lines...) Expand all
123 FilePathWatcher* watcher_; 133 FilePathWatcher* watcher_;
124 FilePathWatcher::Delegate* delegate_; 134 FilePathWatcher::Delegate* delegate_;
125 bool* result_; 135 bool* result_;
126 base::WaitableEvent* completion_; 136 base::WaitableEvent* completion_;
127 137
128 DISALLOW_COPY_AND_ASSIGN(SetupWatchTask); 138 DISALLOW_COPY_AND_ASSIGN(SetupWatchTask);
129 }; 139 };
130 140
131 class FilePathWatcherTest : public testing::Test { 141 class FilePathWatcherTest : public testing::Test {
132 public: 142 public:
133 // Implementation of FilePathWatcher on Mac requires UI loop.
134 FilePathWatcherTest() 143 FilePathWatcherTest()
135 : loop_(MessageLoop::TYPE_UI), 144 : file_thread_("FilePathWatcherTest") {}
136 ui_thread_(BrowserThread::UI, &loop_) { 145
137 } 146 virtual ~FilePathWatcherTest() {}
138 147
139 protected: 148 protected:
140 virtual void SetUp() { 149 virtual void SetUp() {
141 // Create a separate file thread in order to test proper thread usage. 150 // Create a separate file thread in order to test proper thread usage.
142 file_thread_.reset(new BrowserThread(BrowserThread::FILE)); 151 base::Thread::Options options(MessageLoop::TYPE_IO, 0);
143 file_thread_->Start(); 152 ASSERT_TRUE(file_thread_.StartWithOptions(options));
144 temp_dir_.reset(new ScopedTempDir); 153 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
145 ASSERT_TRUE(temp_dir_->CreateUniqueTempDir());
146 collector_ = new NotificationCollector(); 154 collector_ = new NotificationCollector();
147 } 155 }
148 156
149 virtual void TearDown() { 157 virtual void TearDown() {
150 loop_.RunAllPending(); 158 loop_.RunAllPending();
151 file_thread_.reset();
152 } 159 }
153 160
154 FilePath test_file() { 161 FilePath test_file() {
155 return temp_dir_->path().AppendASCII("FilePathWatcherTest"); 162 return temp_dir_.path().AppendASCII("FilePathWatcherTest");
156 } 163 }
157 164
158 // Write |content| to |file|. Returns true on success. 165 // Write |content| to |file|. Returns true on success.
159 bool WriteFile(const FilePath& file, const std::string& content) { 166 bool WriteFile(const FilePath& file, const std::string& content) {
160 int write_size = file_util::WriteFile(file, content.c_str(), 167 int write_size = file_util::WriteFile(file, content.c_str(),
161 content.length()); 168 content.length());
162 return write_size == static_cast<int>(content.length()); 169 return write_size == static_cast<int>(content.length());
163 } 170 }
164 171
165 void SetupWatch(const FilePath& target, 172 bool SetupWatch(const FilePath& target,
166 FilePathWatcher* watcher, 173 FilePathWatcher* watcher,
167 FilePathWatcher::Delegate* delegate) { 174 FilePathWatcher::Delegate* delegate) WARN_UNUSED_RESULT {
168 base::WaitableEvent completion(false, false); 175 base::WaitableEvent completion(false, false);
169 bool result; 176 bool result;
170 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 177 file_thread_.message_loop_proxy()->PostTask(FROM_HERE,
171 new SetupWatchTask(target, watcher, delegate, &result, &completion)); 178 new SetupWatchTask(target,
179 watcher,
180 delegate,
181 &result,
182 &completion));
172 completion.Wait(); 183 completion.Wait();
173 ASSERT_TRUE(result); 184 return result;
174 } 185 }
175 186
176 void WaitForEvents() { 187 bool WaitForEvents() WARN_UNUSED_RESULT {
177 collector_->Reset(); 188 collector_->Reset();
178 loop_.Run(); 189 loop_.Run();
190 return collector_->Success();
179 } 191 }
180 192
181 NotificationCollector* collector() { return collector_.get(); } 193 NotificationCollector* collector() { return collector_.get(); }
182 194
183 MessageLoop loop_; 195 MessageLoop loop_;
184 BrowserThread ui_thread_; 196 base::Thread file_thread_;
185 scoped_ptr<BrowserThread> file_thread_; 197 ScopedTempDir temp_dir_;
186 scoped_ptr<ScopedTempDir> temp_dir_;
187 scoped_refptr<NotificationCollector> collector_; 198 scoped_refptr<NotificationCollector> collector_;
188 }; 199 };
189 200
190 // Basic test: Create the file and verify that we notice. 201 // Basic test: Create the file and verify that we notice.
191 TEST_F(FilePathWatcherTest, MAYBE(NewFile)) { 202 TEST_F(FilePathWatcherTest, NewFile) {
192 FilePathWatcher watcher; 203 FilePathWatcher watcher;
193 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 204 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
194 SetupWatch(test_file(), &watcher, delegate.get()); 205 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
195 206
196 ASSERT_TRUE(WriteFile(test_file(), "content")); 207 ASSERT_TRUE(WriteFile(test_file(), "content"));
197 WaitForEvents(); 208 ASSERT_TRUE(WaitForEvents());
198 } 209 }
199 210
200 // Verify that modifying the file is caught. 211 // Verify that modifying the file is caught.
201 TEST_F(FilePathWatcherTest, MAYBE(ModifiedFile)) { 212 TEST_F(FilePathWatcherTest, ModifiedFile) {
202 ASSERT_TRUE(WriteFile(test_file(), "content")); 213 ASSERT_TRUE(WriteFile(test_file(), "content"));
203 214
204 FilePathWatcher watcher; 215 FilePathWatcher watcher;
205 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 216 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
206 SetupWatch(test_file(), &watcher, delegate.get()); 217 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
207 218
208 // Now make sure we get notified if the file is modified. 219 // Now make sure we get notified if the file is modified.
209 ASSERT_TRUE(WriteFile(test_file(), "new content")); 220 ASSERT_TRUE(WriteFile(test_file(), "new content"));
210 WaitForEvents(); 221 ASSERT_TRUE(WaitForEvents());
211 } 222 }
212 223
213 // Verify that moving the file into place is caught. 224 // Verify that moving the file into place is caught.
214 TEST_F(FilePathWatcherTest, MAYBE(MovedFile)) { 225 TEST_F(FilePathWatcherTest, MovedFile) {
215 FilePath source_file(temp_dir_->path().AppendASCII("source")); 226 FilePath source_file(temp_dir_.path().AppendASCII("source"));
216 ASSERT_TRUE(WriteFile(source_file, "content")); 227 ASSERT_TRUE(WriteFile(source_file, "content"));
217 228
218 FilePathWatcher watcher; 229 FilePathWatcher watcher;
219 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 230 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
220 SetupWatch(test_file(), &watcher, delegate.get()); 231 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
221 232
222 // Now make sure we get notified if the file is modified. 233 // Now make sure we get notified if the file is modified.
223 ASSERT_TRUE(file_util::Move(source_file, test_file())); 234 ASSERT_TRUE(file_util::Move(source_file, test_file()));
224 WaitForEvents(); 235 ASSERT_TRUE(WaitForEvents());
225 } 236 }
226 237
227 TEST_F(FilePathWatcherTest, MAYBE(DeletedFile)) { 238 TEST_F(FilePathWatcherTest, DeletedFile) {
228 ASSERT_TRUE(WriteFile(test_file(), "content")); 239 ASSERT_TRUE(WriteFile(test_file(), "content"));
229 240
230 FilePathWatcher watcher; 241 FilePathWatcher watcher;
231 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 242 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
232 SetupWatch(test_file(), &watcher, delegate.get()); 243 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
233 244
234 // Now make sure we get notified if the file is deleted. 245 // Now make sure we get notified if the file is deleted.
235 file_util::Delete(test_file(), false); 246 file_util::Delete(test_file(), false);
236 WaitForEvents(); 247 ASSERT_TRUE(WaitForEvents());
237 } 248 }
238 249
239 // Used by the DeleteDuringNotify test below. 250 // Used by the DeleteDuringNotify test below.
240 // Deletes the FilePathWatcher when it's notified. 251 // Deletes the FilePathWatcher when it's notified.
241 class Deleter : public FilePathWatcher::Delegate { 252 class Deleter : public FilePathWatcher::Delegate {
242 public: 253 public:
243 Deleter(FilePathWatcher* watcher, MessageLoop* loop) 254 Deleter(FilePathWatcher* watcher, MessageLoop* loop)
244 : watcher_(watcher), 255 : watcher_(watcher),
245 loop_(loop) { 256 loop_(loop) {
246 } 257 }
247 258
248 virtual void OnFilePathChanged(const FilePath& path) { 259 virtual void OnFilePathChanged(const FilePath& path) {
249 watcher_.reset(NULL); 260 watcher_.reset();
250 loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); 261 loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
251 } 262 }
252 263
253 scoped_ptr<FilePathWatcher> watcher_; 264 scoped_ptr<FilePathWatcher> watcher_;
254 MessageLoop* loop_; 265 MessageLoop* loop_;
255 }; 266 };
256 267
257 // Verify that deleting a watcher during the callback doesn't crash. 268 // Verify that deleting a watcher during the callback doesn't crash.
258 TEST_F(FilePathWatcherTest, DeleteDuringNotify) { 269 TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
259 FilePathWatcher* watcher = new FilePathWatcher; 270 FilePathWatcher* watcher = new FilePathWatcher;
260 // Takes ownership of watcher. 271 // Takes ownership of watcher.
261 scoped_refptr<Deleter> deleter(new Deleter(watcher, &loop_)); 272 scoped_refptr<Deleter> deleter(new Deleter(watcher, &loop_));
262 SetupWatch(test_file(), watcher, deleter.get()); 273 ASSERT_TRUE(SetupWatch(test_file(), watcher, deleter.get()));
263 274
264 ASSERT_TRUE(WriteFile(test_file(), "content")); 275 ASSERT_TRUE(WriteFile(test_file(), "content"));
265 WaitForEvents(); 276 ASSERT_TRUE(WaitForEvents());
266 277
267 // We win if we haven't crashed yet. 278 // We win if we haven't crashed yet.
268 // Might as well double-check it got deleted, too. 279 // Might as well double-check it got deleted, too.
269 ASSERT_TRUE(deleter->watcher_.get() == NULL); 280 ASSERT_TRUE(deleter->watcher_.get() == NULL);
270 } 281 }
271 282
272 // Verify that deleting the watcher works even if there is a pending 283 // Verify that deleting the watcher works even if there is a pending
273 // notification. 284 // notification.
274 TEST_F(FilePathWatcherTest, DestroyWithPendingNotification) { 285 TEST_F(FilePathWatcherTest, DestroyWithPendingNotification) {
275 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 286 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
276 FilePathWatcher* watcher = new FilePathWatcher; 287 FilePathWatcher* watcher = new FilePathWatcher;
277 SetupWatch(test_file(), watcher, delegate.get()); 288 ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get()));
278 ASSERT_TRUE(WriteFile(test_file(), "content")); 289 ASSERT_TRUE(WriteFile(test_file(), "content"));
279 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, watcher); 290 file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
280 } 291 }
281 292
282 TEST_F(FilePathWatcherTest, MAYBE(MultipleWatchersSingleFile)) { 293 TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) {
283 FilePathWatcher watcher1, watcher2; 294 FilePathWatcher watcher1, watcher2;
284 scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector())); 295 scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector()));
285 scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector())); 296 scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector()));
286 SetupWatch(test_file(), &watcher1, delegate1.get()); 297 ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get()));
287 SetupWatch(test_file(), &watcher2, delegate2.get()); 298 ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get()));
288 299
289 ASSERT_TRUE(WriteFile(test_file(), "content")); 300 ASSERT_TRUE(WriteFile(test_file(), "content"));
290 WaitForEvents(); 301 ASSERT_TRUE(WaitForEvents());
291 } 302 }
292 303
293 // Verify that watching a file whose parent directory doesn't exist yet works if 304 // Verify that watching a file whose parent directory doesn't exist yet works if
294 // the directory and file are created eventually. 305 // the directory and file are created eventually.
295 TEST_F(FilePathWatcherTest, NonExistentDirectory) { 306 TEST_F(FilePathWatcherTest, NonExistentDirectory) {
296 FilePathWatcher watcher; 307 FilePathWatcher watcher;
297 FilePath dir(temp_dir_->path().AppendASCII("dir")); 308 FilePath dir(temp_dir_.path().AppendASCII("dir"));
298 FilePath file(dir.AppendASCII("file")); 309 FilePath file(dir.AppendASCII("file"));
299 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 310 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
300 SetupWatch(file, &watcher, delegate.get()); 311 ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get()));
301 312
302 ASSERT_TRUE(file_util::CreateDirectory(dir)); 313 ASSERT_TRUE(file_util::CreateDirectory(dir));
303 314
304 ASSERT_TRUE(WriteFile(file, "content")); 315 ASSERT_TRUE(WriteFile(file, "content"));
316
305 VLOG(1) << "Waiting for file creation"; 317 VLOG(1) << "Waiting for file creation";
306 WaitForEvents(); 318 ASSERT_TRUE(WaitForEvents());
307 319
308 ASSERT_TRUE(WriteFile(file, "content v2")); 320 ASSERT_TRUE(WriteFile(file, "content v2"));
309 VLOG(1) << "Waiting for file change"; 321 VLOG(1) << "Waiting for file change";
310 WaitForEvents(); 322 ASSERT_TRUE(WaitForEvents());
311 323
312 ASSERT_TRUE(file_util::Delete(file, false)); 324 ASSERT_TRUE(file_util::Delete(file, false));
313 VLOG(1) << "Waiting for file deletion"; 325 VLOG(1) << "Waiting for file deletion";
314 WaitForEvents(); 326 ASSERT_TRUE(WaitForEvents());
315 } 327 }
316 328
317 // Exercises watch reconfiguration for the case that directories on the path 329 // Exercises watch reconfiguration for the case that directories on the path
318 // are rapidly created. 330 // are rapidly created.
319 TEST_F(FilePathWatcherTest, DirectoryChain) { 331 TEST_F(FilePathWatcherTest, DirectoryChain) {
320 FilePath path(temp_dir_->path()); 332 FilePath path(temp_dir_.path());
321 std::vector<std::string> dir_names; 333 std::vector<std::string> dir_names;
322 for (int i = 0; i < 20; i++) { 334 for (int i = 0; i < 20; i++) {
323 std::string dir(StringPrintf("d%d", i)); 335 std::string dir(StringPrintf("d%d", i));
324 dir_names.push_back(dir); 336 dir_names.push_back(dir);
325 path = path.AppendASCII(dir); 337 path = path.AppendASCII(dir);
326 } 338 }
327 339
328 FilePathWatcher watcher; 340 FilePathWatcher watcher;
329 FilePath file(path.AppendASCII("file")); 341 FilePath file(path.AppendASCII("file"));
330 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 342 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
331 SetupWatch(file, &watcher, delegate.get()); 343 ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get()));
332 344
333 FilePath sub_path(temp_dir_->path()); 345 FilePath sub_path(temp_dir_.path());
334 for (std::vector<std::string>::const_iterator d(dir_names.begin()); 346 for (std::vector<std::string>::const_iterator d(dir_names.begin());
335 d != dir_names.end(); ++d) { 347 d != dir_names.end(); ++d) {
336 sub_path = sub_path.AppendASCII(*d); 348 sub_path = sub_path.AppendASCII(*d);
337 ASSERT_TRUE(file_util::CreateDirectory(sub_path)); 349 ASSERT_TRUE(file_util::CreateDirectory(sub_path));
338 } 350 }
351 VLOG(1) << "Create File";
339 ASSERT_TRUE(WriteFile(file, "content")); 352 ASSERT_TRUE(WriteFile(file, "content"));
340 VLOG(1) << "Waiting for file creation"; 353 VLOG(1) << "Waiting for file creation";
341 WaitForEvents(); 354 ASSERT_TRUE(WaitForEvents());
342 355
343 ASSERT_TRUE(WriteFile(file, "content v2")); 356 ASSERT_TRUE(WriteFile(file, "content v2"));
344 VLOG(1) << "Waiting for file modification"; 357 VLOG(1) << "Waiting for file modification";
345 WaitForEvents(); 358 ASSERT_TRUE(WaitForEvents());
346 } 359 }
347 360
348 TEST_F(FilePathWatcherTest, DisappearingDirectory) { 361 TEST_F(FilePathWatcherTest, DisappearingDirectory) {
349 FilePathWatcher watcher; 362 FilePathWatcher watcher;
350 FilePath dir(temp_dir_->path().AppendASCII("dir")); 363 FilePath dir(temp_dir_.path().AppendASCII("dir"));
351 FilePath file(dir.AppendASCII("file")); 364 FilePath file(dir.AppendASCII("file"));
352 ASSERT_TRUE(file_util::CreateDirectory(dir)); 365 ASSERT_TRUE(file_util::CreateDirectory(dir));
353 ASSERT_TRUE(WriteFile(file, "content")); 366 ASSERT_TRUE(WriteFile(file, "content"));
354 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 367 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
355 SetupWatch(file, &watcher, delegate.get()); 368 ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get()));
356 369
357 ASSERT_TRUE(file_util::Delete(dir, true)); 370 ASSERT_TRUE(file_util::Delete(dir, true));
358 WaitForEvents(); 371 ASSERT_TRUE(WaitForEvents());
359 } 372 }
360 373
361 // Tests that a file that is deleted and reappears is tracked correctly. 374 // Tests that a file that is deleted and reappears is tracked correctly.
362 TEST_F(FilePathWatcherTest, DeleteAndRecreate) { 375 TEST_F(FilePathWatcherTest, DeleteAndRecreate) {
363 ASSERT_TRUE(WriteFile(test_file(), "content")); 376 ASSERT_TRUE(WriteFile(test_file(), "content"));
364 FilePathWatcher watcher; 377 FilePathWatcher watcher;
365 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 378 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
366 SetupWatch(test_file(), &watcher, delegate.get()); 379 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
367 380
368 ASSERT_TRUE(file_util::Delete(test_file(), false)); 381 ASSERT_TRUE(file_util::Delete(test_file(), false));
369 VLOG(1) << "Waiting for file deletion"; 382 VLOG(1) << "Waiting for file deletion";
370 WaitForEvents(); 383 ASSERT_TRUE(WaitForEvents());
371 384
372 ASSERT_TRUE(WriteFile(test_file(), "content")); 385 ASSERT_TRUE(WriteFile(test_file(), "content"));
373 VLOG(1) << "Waiting for file creation"; 386 VLOG(1) << "Waiting for file creation";
374 WaitForEvents(); 387 ASSERT_TRUE(WaitForEvents());
375 } 388 }
376 389
377 TEST_F(FilePathWatcherTest, WatchDirectory) { 390 TEST_F(FilePathWatcherTest, WatchDirectory) {
378 FilePathWatcher watcher; 391 FilePathWatcher watcher;
379 FilePath dir(temp_dir_->path().AppendASCII("dir")); 392 FilePath dir(temp_dir_.path().AppendASCII("dir"));
380 FilePath file1(dir.AppendASCII("file1")); 393 FilePath file1(dir.AppendASCII("file1"));
381 FilePath file2(dir.AppendASCII("file2")); 394 FilePath file2(dir.AppendASCII("file2"));
382 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 395 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
383 SetupWatch(dir, &watcher, delegate.get()); 396 ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get()));
384 397
385 ASSERT_TRUE(file_util::CreateDirectory(dir)); 398 ASSERT_TRUE(file_util::CreateDirectory(dir));
386 VLOG(1) << "Waiting for directory creation"; 399 VLOG(1) << "Waiting for directory creation";
387 WaitForEvents(); 400 ASSERT_TRUE(WaitForEvents());
388 401
389 ASSERT_TRUE(WriteFile(file1, "content")); 402 ASSERT_TRUE(WriteFile(file1, "content"));
390 VLOG(1) << "Waiting for file1 creation"; 403 VLOG(1) << "Waiting for file1 creation";
391 WaitForEvents(); 404 ASSERT_TRUE(WaitForEvents());
392 405
406 #if !defined(OS_MACOSX)
407 // Mac implementation does not detect files modified in a directory.
393 ASSERT_TRUE(WriteFile(file1, "content v2")); 408 ASSERT_TRUE(WriteFile(file1, "content v2"));
394 VLOG(1) << "Waiting for file1 modification"; 409 VLOG(1) << "Waiting for file1 modification";
395 WaitForEvents(); 410 ASSERT_TRUE(WaitForEvents());
411 #endif // !OS_MACOSX
396 412
397 ASSERT_TRUE(file_util::Delete(file1, false)); 413 ASSERT_TRUE(file_util::Delete(file1, false));
398 VLOG(1) << "Waiting for file1 deletion"; 414 VLOG(1) << "Waiting for file1 deletion";
399 WaitForEvents(); 415 ASSERT_TRUE(WaitForEvents());
400 416
401 ASSERT_TRUE(WriteFile(file2, "content")); 417 ASSERT_TRUE(WriteFile(file2, "content"));
402 VLOG(1) << "Waiting for file2 creation"; 418 VLOG(1) << "Waiting for file2 creation";
403 WaitForEvents(); 419 ASSERT_TRUE(WaitForEvents());
404 } 420 }
405 421
406 TEST_F(FilePathWatcherTest, MoveParent) { 422 TEST_F(FilePathWatcherTest, MoveParent) {
407 FilePathWatcher file_watcher; 423 FilePathWatcher file_watcher;
408 FilePathWatcher subdir_watcher; 424 FilePathWatcher subdir_watcher;
409 FilePath dir(temp_dir_->path().AppendASCII("dir")); 425 FilePath dir(temp_dir_.path().AppendASCII("dir"));
410 FilePath dest(temp_dir_->path().AppendASCII("dest")); 426 FilePath dest(temp_dir_.path().AppendASCII("dest"));
411 FilePath subdir(dir.AppendASCII("subdir")); 427 FilePath subdir(dir.AppendASCII("subdir"));
412 FilePath file(subdir.AppendASCII("file")); 428 FilePath file(subdir.AppendASCII("file"));
413 scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector())); 429 scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
414 SetupWatch(file, &file_watcher, file_delegate.get()); 430 ASSERT_TRUE(SetupWatch(file, &file_watcher, file_delegate.get()));
415 scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector())); 431 scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
416 SetupWatch(subdir, &subdir_watcher, subdir_delegate.get()); 432 ASSERT_TRUE(SetupWatch(subdir, &subdir_watcher, subdir_delegate.get()));
417 433
418 // Setup a directory hierarchy. 434 // Setup a directory hierarchy.
419 ASSERT_TRUE(file_util::CreateDirectory(subdir)); 435 ASSERT_TRUE(file_util::CreateDirectory(subdir));
420 ASSERT_TRUE(WriteFile(file, "content")); 436 ASSERT_TRUE(WriteFile(file, "content"));
421 VLOG(1) << "Waiting for file creation"; 437 VLOG(1) << "Waiting for file creation";
422 WaitForEvents(); 438 ASSERT_TRUE(WaitForEvents());
423 439
424 // Move the parent directory. 440 // Move the parent directory.
425 file_util::Move(dir, dest); 441 file_util::Move(dir, dest);
426 VLOG(1) << "Waiting for directory move"; 442 VLOG(1) << "Waiting for directory move";
427 WaitForEvents(); 443 ASSERT_TRUE(WaitForEvents());
428 } 444 }
429 445
430 TEST_F(FilePathWatcherTest, MoveChild) { 446 TEST_F(FilePathWatcherTest, MoveChild) {
431 FilePathWatcher file_watcher; 447 FilePathWatcher file_watcher;
432 FilePathWatcher subdir_watcher; 448 FilePathWatcher subdir_watcher;
433 FilePath source_dir(temp_dir_->path().AppendASCII("source")); 449 FilePath source_dir(temp_dir_.path().AppendASCII("source"));
434 FilePath source_subdir(source_dir.AppendASCII("subdir")); 450 FilePath source_subdir(source_dir.AppendASCII("subdir"));
435 FilePath source_file(source_subdir.AppendASCII("file")); 451 FilePath source_file(source_subdir.AppendASCII("file"));
436 FilePath dest_dir(temp_dir_->path().AppendASCII("dest")); 452 FilePath dest_dir(temp_dir_.path().AppendASCII("dest"));
437 FilePath dest_subdir(dest_dir.AppendASCII("subdir")); 453 FilePath dest_subdir(dest_dir.AppendASCII("subdir"));
438 FilePath dest_file(dest_subdir.AppendASCII("file")); 454 FilePath dest_file(dest_subdir.AppendASCII("file"));
439 455
440 // Setup a directory hierarchy. 456 // Setup a directory hierarchy.
441 ASSERT_TRUE(file_util::CreateDirectory(source_subdir)); 457 ASSERT_TRUE(file_util::CreateDirectory(source_subdir));
442 ASSERT_TRUE(WriteFile(source_file, "content")); 458 ASSERT_TRUE(WriteFile(source_file, "content"));
443 459
444 scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector())); 460 scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
445 SetupWatch(dest_file, &file_watcher, file_delegate.get()); 461 ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get()));
446 scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector())); 462 scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
447 SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get()); 463 ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get()));
448 464
449 // Move the directory into place, s.t. the watched file appears. 465 // Move the directory into place, s.t. the watched file appears.
450 ASSERT_TRUE(file_util::Move(source_dir, dest_dir)); 466 ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
451 WaitForEvents(); 467 ASSERT_TRUE(WaitForEvents());
452 } 468 }
453 469
470 #if !defined(OS_LINUX)
471 // Linux implementation of FilePathWatcher doesn't catch attribute changes.
472 // http://crbug.com/78043
473
474 // Verify that changing attributes on a file is caught
475 TEST_F(FilePathWatcherTest, FileAttributesChanged) {
476 ASSERT_TRUE(WriteFile(test_file(), "content"));
477 FilePathWatcher watcher;
478 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
479 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
480
481 // Now make sure we get notified if the file is modified.
482 ASSERT_TRUE(file_util::MakeFileUnreadable(test_file()));
483 ASSERT_TRUE(WaitForEvents());
484 }
485
486 #endif // !OS_LINUX
487
488 enum Permission {
489 Read,
490 Write,
491 Execute
492 };
493
494 bool ChangeFilePermissions(const FilePath& path, Permission perm, bool allow) {
495 #if defined(OS_POSIX)
496 struct stat stat_buf;
497
498 if (stat(path.value().c_str(), &stat_buf) != 0)
499 return false;
500
501 mode_t mode = 0;
502 switch (perm) {
503 case Read:
504 mode = S_IRUSR | S_IRGRP | S_IROTH;
505 break;
506 case Write:
507 mode = S_IWUSR | S_IWGRP | S_IWOTH;
508 break;
509 case Execute:
510 mode = S_IXUSR | S_IXGRP | S_IXOTH;
511 break;
512 default:
513 ADD_FAILURE() << "unknown perm " << perm;
514 return false;
515 }
516 if (allow) {
517 stat_buf.st_mode |= mode;
518 } else {
519 stat_buf.st_mode &= ~mode;
520 }
521 return chmod(path.value().c_str(), stat_buf.st_mode) == 0;
522
523 #elif defined(OS_WIN)
524 PACL old_dacl;
525 PSECURITY_DESCRIPTOR security_descriptor;
526 if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
527 SE_FILE_OBJECT,
528 DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl,
529 NULL, &security_descriptor) != ERROR_SUCCESS)
530 return false;
531
532 DWORD mode = 0;
533 switch (perm) {
534 case Read:
535 mode = GENERIC_READ;
536 break;
537 case Write:
538 mode = GENERIC_WRITE;
539 break;
540 case Execute:
541 mode = GENERIC_EXECUTE;
542 break;
543 default:
544 ADD_FAILURE() << "unknown perm " << perm;
545 return false;
546 }
547
548 // Deny Read access for the current user.
549 EXPLICIT_ACCESS change;
550 change.grfAccessPermissions = mode;
551 change.grfAccessMode = allow ? GRANT_ACCESS : DENY_ACCESS;
552 change.grfInheritance = 0;
553 change.Trustee.pMultipleTrustee = NULL;
554 change.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
555 change.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
556 change.Trustee.TrusteeType = TRUSTEE_IS_USER;
557 change.Trustee.ptstrName = L"CURRENT_USER";
558
559 PACL new_dacl;
560 if (SetEntriesInAcl(1, &change, old_dacl, &new_dacl) != ERROR_SUCCESS) {
561 LocalFree(security_descriptor);
562 return false;
563 }
564
565 DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
566 SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
567 NULL, NULL, new_dacl, NULL);
568 LocalFree(security_descriptor);
569 LocalFree(new_dacl);
570
571 return rc == ERROR_SUCCESS;
572 #else
573 NOTIMPLEMENTED();
574 return false;
575 #endif
576 }
577
578 #if defined(OS_MACOSX)
579 // Linux implementation of FilePathWatcher doesn't catch attribute changes.
580 // http://crbug.com/78043
581 // Windows implementation of FilePathWatcher catches attribute changes that
582 // don't affect the path being watched.
583 // http://crbug.com/78045
584
585 // Verify that changing attributes on a directory works.
586 TEST_F(FilePathWatcherTest, DirAttributesChanged) {
587 FilePath test_dir1(temp_dir_.path().AppendASCII("DirAttributesChangedDir1"));
588 FilePath test_dir2(test_dir1.AppendASCII("DirAttributesChangedDir2"));
589 FilePath test_file(test_dir2.AppendASCII("DirAttributesChangedFile"));
590 // Setup a directory hierarchy.
591 ASSERT_TRUE(file_util::CreateDirectory(test_dir1));
592 ASSERT_TRUE(file_util::CreateDirectory(test_dir2));
593 ASSERT_TRUE(WriteFile(test_file, "content"));
594
595 FilePathWatcher watcher;
596 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
597 ASSERT_TRUE(SetupWatch(test_file, &watcher, delegate.get()));
598
599 // We should not get notified in this case as it hasn't affected our ability
600 // to access the file.
601 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, false));
602 loop_.PostDelayedTask(FROM_HERE,
603 new MessageLoop::QuitTask,
604 TestTimeouts::tiny_timeout_ms());
605 ASSERT_FALSE(WaitForEvents());
606 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, true));
607
608 // We should get notified in this case because filepathwatcher can no
609 // longer access the file
610 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, false));
611 ASSERT_TRUE(WaitForEvents());
612 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, true));
613 }
614
615 #endif // OS_MACOSX
454 } // namespace 616 } // namespace
OLDNEW
« no previous file with comments | « content/common/file_path_watcher/file_path_watcher.cc ('k') | content/common/file_path_watcher/file_path_watcher_inotify.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698