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

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

Issue 6731064: kqueue implementation of FilePathWatcher on Mac. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix up parens 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) 2011 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 "content/common/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"
10 #include "base/compiler_specific.h" 17 #include "base/compiler_specific.h"
11 #include "base/file_path.h" 18 #include "base/file_path.h"
12 #include "base/file_util.h" 19 #include "base/file_util.h"
13 #include "base/memory/scoped_temp_dir.h" 20 #include "base/memory/scoped_temp_dir.h"
14 #include "base/message_loop.h" 21 #include "base/message_loop.h"
15 #include "base/message_loop_proxy.h" 22 #include "base/message_loop_proxy.h"
16 #include "base/path_service.h" 23 #include "base/path_service.h"
17 #include "base/string_util.h" 24 #include "base/string_util.h"
18 #include "base/stl_util-inl.h" 25 #include "base/stl_util-inl.h"
19 #include "base/synchronization/waitable_event.h" 26 #include "base/synchronization/waitable_event.h"
20 #include "base/test/test_timeouts.h" 27 #include "base/test/test_timeouts.h"
21 #include "base/threading/thread.h" 28 #include "base/threading/thread.h"
22 #include "testing/gtest/include/gtest/gtest.h" 29 #include "testing/gtest/include/gtest/gtest.h"
23 30
24 #if defined(OS_MACOSX)
25 // TODO(mnissler): There are flakes on Mac (http://crbug.com/54822) at least for
26 // FilePathWatcherTest.MultipleWatchersSingleFile.
27 #define MAYBE(name) FLAKY_ ## name
28 #else
29 #define MAYBE(name) name
30 #endif
31
32 namespace { 31 namespace {
33 32
34 class TestDelegate; 33 class TestDelegate;
35 34
36 // Aggregates notifications from the test delegates and breaks the message loop 35 // Aggregates notifications from the test delegates and breaks the message loop
37 // the test thread is waiting on once they all came in. 36 // the test thread is waiting on once they all came in.
38 class NotificationCollector 37 class NotificationCollector
39 : public base::RefCountedThreadSafe<NotificationCollector> { 38 : public base::RefCountedThreadSafe<NotificationCollector> {
40 public: 39 public:
41 NotificationCollector() 40 NotificationCollector()
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 // guarantee |loop| outlives the file thread on which OnFilePathChanged runs. 92 // guarantee |loop| outlives the file thread on which OnFilePathChanged runs.
94 explicit TestDelegate(NotificationCollector* collector) 93 explicit TestDelegate(NotificationCollector* collector)
95 : collector_(collector) { 94 : collector_(collector) {
96 collector_->Register(this); 95 collector_->Register(this);
97 } 96 }
98 97
99 virtual void OnFilePathChanged(const FilePath&) { 98 virtual void OnFilePathChanged(const FilePath&) {
100 collector_->OnChange(this); 99 collector_->OnChange(this);
101 } 100 }
102 101
102 virtual void OnFilePathError(const FilePath& path) {
103 ADD_FAILURE() << "Error " << path.value();
104 }
105
103 private: 106 private:
104 scoped_refptr<NotificationCollector> collector_; 107 scoped_refptr<NotificationCollector> collector_;
105 108
106 DISALLOW_COPY_AND_ASSIGN(TestDelegate); 109 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
107 }; 110 };
108 111
109 // A helper class for setting up watches on the file thread. 112 // A helper class for setting up watches on the file thread.
110 class SetupWatchTask : public Task { 113 class SetupWatchTask : public Task {
111 public: 114 public:
112 SetupWatchTask(const FilePath& target, 115 SetupWatchTask(const FilePath& target,
113 FilePathWatcher* watcher, 116 FilePathWatcher* watcher,
114 FilePathWatcher::Delegate* delegate, 117 FilePathWatcher::Delegate* delegate,
115 bool* result, 118 bool* result,
116 base::WaitableEvent* completion, 119 base::WaitableEvent* completion)
117 base::MessageLoopProxy* mac_run_loop)
118 : target_(target), 120 : target_(target),
119 watcher_(watcher), 121 watcher_(watcher),
120 delegate_(delegate), 122 delegate_(delegate),
121 result_(result), 123 result_(result),
122 completion_(completion), 124 completion_(completion) {}
123 mac_run_loop_(mac_run_loop) {}
124 125
125 void Run() { 126 void Run() {
126 *result_ = watcher_->Watch(target_, delegate_, mac_run_loop_); 127 *result_ = watcher_->Watch(target_, delegate_);
127 completion_->Signal(); 128 completion_->Signal();
128 } 129 }
129 130
130 private: 131 private:
131 const FilePath target_; 132 const FilePath target_;
132 FilePathWatcher* watcher_; 133 FilePathWatcher* watcher_;
133 FilePathWatcher::Delegate* delegate_; 134 FilePathWatcher::Delegate* delegate_;
134 bool* result_; 135 bool* result_;
135 base::WaitableEvent* completion_; 136 base::WaitableEvent* completion_;
136 scoped_refptr<base::MessageLoopProxy> mac_run_loop_;
137 137
138 DISALLOW_COPY_AND_ASSIGN(SetupWatchTask); 138 DISALLOW_COPY_AND_ASSIGN(SetupWatchTask);
139 }; 139 };
140 140
141 class FilePathWatcherTest : public testing::Test { 141 class FilePathWatcherTest : public testing::Test {
142 public: 142 public:
143 FilePathWatcherTest() 143 FilePathWatcherTest()
144 : loop_(MessageLoop::TYPE_UI), 144 : file_thread_("FilePathWatcherTest") {}
145 file_thread_("FilePathWatcherTest") { }
146 145
147 virtual ~FilePathWatcherTest() { } 146 virtual ~FilePathWatcherTest() {}
148 147
149 protected: 148 protected:
150 virtual void SetUp() { 149 virtual void SetUp() {
151 // 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.
152 base::Thread::Options options(MessageLoop::TYPE_IO, 0); 151 base::Thread::Options options(MessageLoop::TYPE_IO, 0);
153 ASSERT_TRUE(file_thread_.StartWithOptions(options)); 152 ASSERT_TRUE(file_thread_.StartWithOptions(options));
154 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 153 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
155 collector_ = new NotificationCollector(); 154 collector_ = new NotificationCollector();
156 } 155 }
157 156
(...skipping 15 matching lines...) Expand all
173 bool SetupWatch(const FilePath& target, 172 bool SetupWatch(const FilePath& target,
174 FilePathWatcher* watcher, 173 FilePathWatcher* watcher,
175 FilePathWatcher::Delegate* delegate) WARN_UNUSED_RESULT { 174 FilePathWatcher::Delegate* delegate) WARN_UNUSED_RESULT {
176 base::WaitableEvent completion(false, false); 175 base::WaitableEvent completion(false, false);
177 bool result; 176 bool result;
178 file_thread_.message_loop_proxy()->PostTask(FROM_HERE, 177 file_thread_.message_loop_proxy()->PostTask(FROM_HERE,
179 new SetupWatchTask(target, 178 new SetupWatchTask(target,
180 watcher, 179 watcher,
181 delegate, 180 delegate,
182 &result, 181 &result,
183 &completion, 182 &completion));
184 base::MessageLoopProxy::CreateForCurrentThread()));
185 completion.Wait(); 183 completion.Wait();
186 return result; 184 return result;
187 } 185 }
188 186
189 bool WaitForEvents() WARN_UNUSED_RESULT { 187 bool WaitForEvents() WARN_UNUSED_RESULT {
190 collector_->Reset(); 188 collector_->Reset();
191 loop_.Run(); 189 loop_.Run();
192 return collector_->Success(); 190 return collector_->Success();
193 } 191 }
194 192
195 NotificationCollector* collector() { return collector_.get(); } 193 NotificationCollector* collector() { return collector_.get(); }
196 194
197 MessageLoop loop_; 195 MessageLoop loop_;
198 base::Thread file_thread_; 196 base::Thread file_thread_;
199 ScopedTempDir temp_dir_; 197 ScopedTempDir temp_dir_;
200 scoped_refptr<NotificationCollector> collector_; 198 scoped_refptr<NotificationCollector> collector_;
201 }; 199 };
202 200
203 // Basic test: Create the file and verify that we notice. 201 // Basic test: Create the file and verify that we notice.
204 TEST_F(FilePathWatcherTest, MAYBE(NewFile)) { 202 TEST_F(FilePathWatcherTest, NewFile) {
205 FilePathWatcher watcher; 203 FilePathWatcher watcher;
206 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 204 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
207 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get())); 205 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
208 206
209 ASSERT_TRUE(WriteFile(test_file(), "content")); 207 ASSERT_TRUE(WriteFile(test_file(), "content"));
210 ASSERT_TRUE(WaitForEvents()); 208 ASSERT_TRUE(WaitForEvents());
211 } 209 }
212 210
213 // Verify that modifying the file is caught. 211 // Verify that modifying the file is caught.
214 TEST_F(FilePathWatcherTest, MAYBE(ModifiedFile)) { 212 TEST_F(FilePathWatcherTest, ModifiedFile) {
215 ASSERT_TRUE(WriteFile(test_file(), "content")); 213 ASSERT_TRUE(WriteFile(test_file(), "content"));
216 214
217 FilePathWatcher watcher; 215 FilePathWatcher watcher;
218 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 216 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
219 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get())); 217 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
220 218
221 // Now make sure we get notified if the file is modified. 219 // Now make sure we get notified if the file is modified.
222 ASSERT_TRUE(WriteFile(test_file(), "new content")); 220 ASSERT_TRUE(WriteFile(test_file(), "new content"));
223 ASSERT_TRUE(WaitForEvents()); 221 ASSERT_TRUE(WaitForEvents());
224 } 222 }
225 223
226 // Verify that moving the file into place is caught. 224 // Verify that moving the file into place is caught.
227 TEST_F(FilePathWatcherTest, MAYBE(MovedFile)) { 225 TEST_F(FilePathWatcherTest, MovedFile) {
228 FilePath source_file(temp_dir_.path().AppendASCII("source")); 226 FilePath source_file(temp_dir_.path().AppendASCII("source"));
229 ASSERT_TRUE(WriteFile(source_file, "content")); 227 ASSERT_TRUE(WriteFile(source_file, "content"));
230 228
231 FilePathWatcher watcher; 229 FilePathWatcher watcher;
232 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 230 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
233 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get())); 231 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
234 232
235 // Now make sure we get notified if the file is modified. 233 // Now make sure we get notified if the file is modified.
236 ASSERT_TRUE(file_util::Move(source_file, test_file())); 234 ASSERT_TRUE(file_util::Move(source_file, test_file()));
237 ASSERT_TRUE(WaitForEvents()); 235 ASSERT_TRUE(WaitForEvents());
238 } 236 }
239 237
240 TEST_F(FilePathWatcherTest, MAYBE(DeletedFile)) { 238 TEST_F(FilePathWatcherTest, DeletedFile) {
241 ASSERT_TRUE(WriteFile(test_file(), "content")); 239 ASSERT_TRUE(WriteFile(test_file(), "content"));
242 240
243 FilePathWatcher watcher; 241 FilePathWatcher watcher;
244 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 242 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
245 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get())); 243 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
246 244
247 // Now make sure we get notified if the file is deleted. 245 // Now make sure we get notified if the file is deleted.
248 file_util::Delete(test_file(), false); 246 file_util::Delete(test_file(), false);
249 ASSERT_TRUE(WaitForEvents()); 247 ASSERT_TRUE(WaitForEvents());
250 } 248 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 // 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
286 // notification. 284 // notification.
287 TEST_F(FilePathWatcherTest, DestroyWithPendingNotification) { 285 TEST_F(FilePathWatcherTest, DestroyWithPendingNotification) {
288 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 286 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
289 FilePathWatcher* watcher = new FilePathWatcher; 287 FilePathWatcher* watcher = new FilePathWatcher;
290 ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get())); 288 ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get()));
291 ASSERT_TRUE(WriteFile(test_file(), "content")); 289 ASSERT_TRUE(WriteFile(test_file(), "content"));
292 file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher); 290 file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
293 } 291 }
294 292
295 TEST_F(FilePathWatcherTest, MAYBE(MultipleWatchersSingleFile)) { 293 TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) {
296 FilePathWatcher watcher1, watcher2; 294 FilePathWatcher watcher1, watcher2;
297 scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector())); 295 scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector()));
298 scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector())); 296 scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector()));
299 ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get())); 297 ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get()));
300 ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get())); 298 ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get()));
301 299
302 ASSERT_TRUE(WriteFile(test_file(), "content")); 300 ASSERT_TRUE(WriteFile(test_file(), "content"));
303 ASSERT_TRUE(WaitForEvents()); 301 ASSERT_TRUE(WaitForEvents());
304 } 302 }
305 303
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get())); 396 ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get()));
399 397
400 ASSERT_TRUE(file_util::CreateDirectory(dir)); 398 ASSERT_TRUE(file_util::CreateDirectory(dir));
401 VLOG(1) << "Waiting for directory creation"; 399 VLOG(1) << "Waiting for directory creation";
402 ASSERT_TRUE(WaitForEvents()); 400 ASSERT_TRUE(WaitForEvents());
403 401
404 ASSERT_TRUE(WriteFile(file1, "content")); 402 ASSERT_TRUE(WriteFile(file1, "content"));
405 VLOG(1) << "Waiting for file1 creation"; 403 VLOG(1) << "Waiting for file1 creation";
406 ASSERT_TRUE(WaitForEvents()); 404 ASSERT_TRUE(WaitForEvents());
407 405
406 #if !defined(OS_MACOSX)
407 // Mac implementation does not detect files modified in a directory.
408 ASSERT_TRUE(WriteFile(file1, "content v2")); 408 ASSERT_TRUE(WriteFile(file1, "content v2"));
409 VLOG(1) << "Waiting for file1 modification"; 409 VLOG(1) << "Waiting for file1 modification";
410 ASSERT_TRUE(WaitForEvents()); 410 ASSERT_TRUE(WaitForEvents());
411 #endif // !OS_MACOSX
411 412
412 ASSERT_TRUE(file_util::Delete(file1, false)); 413 ASSERT_TRUE(file_util::Delete(file1, false));
413 VLOG(1) << "Waiting for file1 deletion"; 414 VLOG(1) << "Waiting for file1 deletion";
414 ASSERT_TRUE(WaitForEvents()); 415 ASSERT_TRUE(WaitForEvents());
415 416
416 ASSERT_TRUE(WriteFile(file2, "content")); 417 ASSERT_TRUE(WriteFile(file2, "content"));
417 VLOG(1) << "Waiting for file2 creation"; 418 VLOG(1) << "Waiting for file2 creation";
418 ASSERT_TRUE(WaitForEvents()); 419 ASSERT_TRUE(WaitForEvents());
419 } 420 }
420 421
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector())); 460 scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
460 ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get())); 461 ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get()));
461 scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector())); 462 scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
462 ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get())); 463 ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get()));
463 464
464 // Move the directory into place, s.t. the watched file appears. 465 // Move the directory into place, s.t. the watched file appears.
465 ASSERT_TRUE(file_util::Move(source_dir, dest_dir)); 466 ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
466 ASSERT_TRUE(WaitForEvents()); 467 ASSERT_TRUE(WaitForEvents());
467 } 468 }
468 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
469 } // 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