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

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: fixed up mattias's grammar nits, and added test 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 #if defined(OS_WIN)
Mark Mentovai 2011/03/31 01:50:35 These should be moved down. http://www.chromium.o
9 #include <windows.h>
10 #include <aclapi.h>
11 #elif defined(OS_POSIX)
12 #include <sys/stat.h>
13 #endif
8 14
9 #include "base/basictypes.h" 15 #include "base/basictypes.h"
10 #include "base/compiler_specific.h" 16 #include "base/compiler_specific.h"
11 #include "base/file_path.h" 17 #include "base/file_path.h"
12 #include "base/file_util.h" 18 #include "base/file_util.h"
13 #include "base/memory/scoped_temp_dir.h" 19 #include "base/memory/scoped_temp_dir.h"
14 #include "base/message_loop.h" 20 #include "base/message_loop.h"
15 #include "base/message_loop_proxy.h" 21 #include "base/message_loop_proxy.h"
16 #include "base/path_service.h" 22 #include "base/path_service.h"
17 #include "base/string_util.h" 23 #include "base/string_util.h"
18 #include "base/stl_util-inl.h" 24 #include "base/stl_util-inl.h"
19 #include "base/synchronization/waitable_event.h" 25 #include "base/synchronization/waitable_event.h"
20 #include "base/test/test_timeouts.h" 26 #include "base/test/test_timeouts.h"
21 #include "base/threading/thread.h" 27 #include "base/threading/thread.h"
22 #include "testing/gtest/include/gtest/gtest.h" 28 #include "testing/gtest/include/gtest/gtest.h"
23 29
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 { 30 namespace {
33 31
34 class TestDelegate; 32 class TestDelegate;
35 33
36 // Aggregates notifications from the test delegates and breaks the message loop 34 // Aggregates notifications from the test delegates and breaks the message loop
37 // the test thread is waiting on once they all came in. 35 // the test thread is waiting on once they all came in.
38 class NotificationCollector 36 class NotificationCollector
39 : public base::RefCountedThreadSafe<NotificationCollector> { 37 : public base::RefCountedThreadSafe<NotificationCollector> {
40 public: 38 public:
41 NotificationCollector() 39 NotificationCollector()
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 DISALLOW_COPY_AND_ASSIGN(TestDelegate); 104 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
107 }; 105 };
108 106
109 // A helper class for setting up watches on the file thread. 107 // A helper class for setting up watches on the file thread.
110 class SetupWatchTask : public Task { 108 class SetupWatchTask : public Task {
111 public: 109 public:
112 SetupWatchTask(const FilePath& target, 110 SetupWatchTask(const FilePath& target,
113 FilePathWatcher* watcher, 111 FilePathWatcher* watcher,
114 FilePathWatcher::Delegate* delegate, 112 FilePathWatcher::Delegate* delegate,
115 bool* result, 113 bool* result,
116 base::WaitableEvent* completion, 114 base::WaitableEvent* completion)
117 base::MessageLoopProxy* mac_run_loop)
118 : target_(target), 115 : target_(target),
119 watcher_(watcher), 116 watcher_(watcher),
120 delegate_(delegate), 117 delegate_(delegate),
121 result_(result), 118 result_(result),
122 completion_(completion), 119 completion_(completion) {}
123 mac_run_loop_(mac_run_loop) {}
124 120
125 void Run() { 121 void Run() {
126 *result_ = watcher_->Watch(target_, delegate_, mac_run_loop_); 122 *result_ = watcher_->Watch(target_, delegate_);
127 completion_->Signal(); 123 completion_->Signal();
128 } 124 }
129 125
130 private: 126 private:
131 const FilePath target_; 127 const FilePath target_;
132 FilePathWatcher* watcher_; 128 FilePathWatcher* watcher_;
133 FilePathWatcher::Delegate* delegate_; 129 FilePathWatcher::Delegate* delegate_;
134 bool* result_; 130 bool* result_;
135 base::WaitableEvent* completion_; 131 base::WaitableEvent* completion_;
136 scoped_refptr<base::MessageLoopProxy> mac_run_loop_;
137 132
138 DISALLOW_COPY_AND_ASSIGN(SetupWatchTask); 133 DISALLOW_COPY_AND_ASSIGN(SetupWatchTask);
139 }; 134 };
140 135
141 class FilePathWatcherTest : public testing::Test { 136 class FilePathWatcherTest : public testing::Test {
142 public: 137 public:
143 FilePathWatcherTest() 138 FilePathWatcherTest()
144 : loop_(MessageLoop::TYPE_UI), 139 : file_thread_("FilePathWatcherTest") { }
145 file_thread_("FilePathWatcherTest") { }
146 140
147 virtual ~FilePathWatcherTest() { } 141 virtual ~FilePathWatcherTest() { }
148 142
149 protected: 143 protected:
150 virtual void SetUp() { 144 virtual void SetUp() {
151 // Create a separate file thread in order to test proper thread usage. 145 // Create a separate file thread in order to test proper thread usage.
152 base::Thread::Options options(MessageLoop::TYPE_IO, 0); 146 base::Thread::Options options(MessageLoop::TYPE_IO, 0);
153 ASSERT_TRUE(file_thread_.StartWithOptions(options)); 147 ASSERT_TRUE(file_thread_.StartWithOptions(options));
154 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 148 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
155 collector_ = new NotificationCollector(); 149 collector_ = new NotificationCollector();
(...skipping 17 matching lines...) Expand all
173 bool SetupWatch(const FilePath& target, 167 bool SetupWatch(const FilePath& target,
174 FilePathWatcher* watcher, 168 FilePathWatcher* watcher,
175 FilePathWatcher::Delegate* delegate) WARN_UNUSED_RESULT { 169 FilePathWatcher::Delegate* delegate) WARN_UNUSED_RESULT {
176 base::WaitableEvent completion(false, false); 170 base::WaitableEvent completion(false, false);
177 bool result; 171 bool result;
178 file_thread_.message_loop_proxy()->PostTask(FROM_HERE, 172 file_thread_.message_loop_proxy()->PostTask(FROM_HERE,
179 new SetupWatchTask(target, 173 new SetupWatchTask(target,
180 watcher, 174 watcher,
181 delegate, 175 delegate,
182 &result, 176 &result,
183 &completion, 177 &completion));
184 base::MessageLoopProxy::CreateForCurrentThread()));
185 completion.Wait(); 178 completion.Wait();
186 return result; 179 return result;
187 } 180 }
188 181
189 bool WaitForEvents() WARN_UNUSED_RESULT { 182 bool WaitForEvents() WARN_UNUSED_RESULT {
190 collector_->Reset(); 183 collector_->Reset();
191 loop_.Run(); 184 loop_.Run();
192 return collector_->Success(); 185 return collector_->Success();
193 } 186 }
194 187
195 NotificationCollector* collector() { return collector_.get(); } 188 NotificationCollector* collector() { return collector_.get(); }
196 189
197 MessageLoop loop_; 190 MessageLoop loop_;
198 base::Thread file_thread_; 191 base::Thread file_thread_;
199 ScopedTempDir temp_dir_; 192 ScopedTempDir temp_dir_;
200 scoped_refptr<NotificationCollector> collector_; 193 scoped_refptr<NotificationCollector> collector_;
201 }; 194 };
202 195
203 // Basic test: Create the file and verify that we notice. 196 // Basic test: Create the file and verify that we notice.
204 TEST_F(FilePathWatcherTest, MAYBE(NewFile)) { 197 TEST_F(FilePathWatcherTest, NewFile) {
205 FilePathWatcher watcher; 198 FilePathWatcher watcher;
206 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 199 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
207 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get())); 200 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
208 201
209 ASSERT_TRUE(WriteFile(test_file(), "content")); 202 ASSERT_TRUE(WriteFile(test_file(), "content"));
210 ASSERT_TRUE(WaitForEvents()); 203 ASSERT_TRUE(WaitForEvents());
211 } 204 }
212 205
213 // Verify that modifying the file is caught. 206 // Verify that modifying the file is caught.
214 TEST_F(FilePathWatcherTest, MAYBE(ModifiedFile)) { 207 TEST_F(FilePathWatcherTest, ModifiedFile) {
215 ASSERT_TRUE(WriteFile(test_file(), "content")); 208 ASSERT_TRUE(WriteFile(test_file(), "content"));
216 209
217 FilePathWatcher watcher; 210 FilePathWatcher watcher;
218 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 211 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
219 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get())); 212 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
220 213
221 // Now make sure we get notified if the file is modified. 214 // Now make sure we get notified if the file is modified.
222 ASSERT_TRUE(WriteFile(test_file(), "new content")); 215 ASSERT_TRUE(WriteFile(test_file(), "new content"));
223 ASSERT_TRUE(WaitForEvents()); 216 ASSERT_TRUE(WaitForEvents());
224 } 217 }
225 218
226 // Verify that moving the file into place is caught. 219 // Verify that moving the file into place is caught.
227 TEST_F(FilePathWatcherTest, MAYBE(MovedFile)) { 220 TEST_F(FilePathWatcherTest, MovedFile) {
228 FilePath source_file(temp_dir_.path().AppendASCII("source")); 221 FilePath source_file(temp_dir_.path().AppendASCII("source"));
229 ASSERT_TRUE(WriteFile(source_file, "content")); 222 ASSERT_TRUE(WriteFile(source_file, "content"));
230 223
231 FilePathWatcher watcher; 224 FilePathWatcher watcher;
232 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 225 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
233 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get())); 226 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
234 227
235 // Now make sure we get notified if the file is modified. 228 // Now make sure we get notified if the file is modified.
236 ASSERT_TRUE(file_util::Move(source_file, test_file())); 229 ASSERT_TRUE(file_util::Move(source_file, test_file()));
237 ASSERT_TRUE(WaitForEvents()); 230 ASSERT_TRUE(WaitForEvents());
238 } 231 }
239 232
240 TEST_F(FilePathWatcherTest, MAYBE(DeletedFile)) { 233 TEST_F(FilePathWatcherTest, DeletedFile) {
241 ASSERT_TRUE(WriteFile(test_file(), "content")); 234 ASSERT_TRUE(WriteFile(test_file(), "content"));
242 235
243 FilePathWatcher watcher; 236 FilePathWatcher watcher;
244 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 237 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
245 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get())); 238 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
246 239
247 // Now make sure we get notified if the file is deleted. 240 // Now make sure we get notified if the file is deleted.
248 file_util::Delete(test_file(), false); 241 file_util::Delete(test_file(), false);
249 ASSERT_TRUE(WaitForEvents()); 242 ASSERT_TRUE(WaitForEvents());
250 } 243 }
(...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 278 // Verify that deleting the watcher works even if there is a pending
286 // notification. 279 // notification.
287 TEST_F(FilePathWatcherTest, DestroyWithPendingNotification) { 280 TEST_F(FilePathWatcherTest, DestroyWithPendingNotification) {
288 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector())); 281 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
289 FilePathWatcher* watcher = new FilePathWatcher; 282 FilePathWatcher* watcher = new FilePathWatcher;
290 ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get())); 283 ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get()));
291 ASSERT_TRUE(WriteFile(test_file(), "content")); 284 ASSERT_TRUE(WriteFile(test_file(), "content"));
292 file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher); 285 file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
293 } 286 }
294 287
295 TEST_F(FilePathWatcherTest, MAYBE(MultipleWatchersSingleFile)) { 288 TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) {
296 FilePathWatcher watcher1, watcher2; 289 FilePathWatcher watcher1, watcher2;
297 scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector())); 290 scoped_refptr<TestDelegate> delegate1(new TestDelegate(collector()));
298 scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector())); 291 scoped_refptr<TestDelegate> delegate2(new TestDelegate(collector()));
299 ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get())); 292 ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get()));
300 ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get())); 293 ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get()));
301 294
302 ASSERT_TRUE(WriteFile(test_file(), "content")); 295 ASSERT_TRUE(WriteFile(test_file(), "content"));
303 ASSERT_TRUE(WaitForEvents()); 296 ASSERT_TRUE(WaitForEvents());
304 } 297 }
305 298
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get())); 391 ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get()));
399 392
400 ASSERT_TRUE(file_util::CreateDirectory(dir)); 393 ASSERT_TRUE(file_util::CreateDirectory(dir));
401 VLOG(1) << "Waiting for directory creation"; 394 VLOG(1) << "Waiting for directory creation";
402 ASSERT_TRUE(WaitForEvents()); 395 ASSERT_TRUE(WaitForEvents());
403 396
404 ASSERT_TRUE(WriteFile(file1, "content")); 397 ASSERT_TRUE(WriteFile(file1, "content"));
405 VLOG(1) << "Waiting for file1 creation"; 398 VLOG(1) << "Waiting for file1 creation";
406 ASSERT_TRUE(WaitForEvents()); 399 ASSERT_TRUE(WaitForEvents());
407 400
401 #if !defined(OS_MACOSX)
402 // Mac implementation does not detect files modified in a directory.
408 ASSERT_TRUE(WriteFile(file1, "content v2")); 403 ASSERT_TRUE(WriteFile(file1, "content v2"));
409 VLOG(1) << "Waiting for file1 modification"; 404 VLOG(1) << "Waiting for file1 modification";
410 ASSERT_TRUE(WaitForEvents()); 405 ASSERT_TRUE(WaitForEvents());
406 #endif // !OS_MACOSX
411 407
412 ASSERT_TRUE(file_util::Delete(file1, false)); 408 ASSERT_TRUE(file_util::Delete(file1, false));
413 VLOG(1) << "Waiting for file1 deletion"; 409 VLOG(1) << "Waiting for file1 deletion";
414 ASSERT_TRUE(WaitForEvents()); 410 ASSERT_TRUE(WaitForEvents());
415 411
416 ASSERT_TRUE(WriteFile(file2, "content")); 412 ASSERT_TRUE(WriteFile(file2, "content"));
417 VLOG(1) << "Waiting for file2 creation"; 413 VLOG(1) << "Waiting for file2 creation";
418 ASSERT_TRUE(WaitForEvents()); 414 ASSERT_TRUE(WaitForEvents());
419 } 415 }
420 416
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector())); 455 scoped_refptr<TestDelegate> file_delegate(new TestDelegate(collector()));
460 ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get())); 456 ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get()));
461 scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector())); 457 scoped_refptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
462 ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get())); 458 ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get()));
463 459
464 // Move the directory into place, s.t. the watched file appears. 460 // Move the directory into place, s.t. the watched file appears.
465 ASSERT_TRUE(file_util::Move(source_dir, dest_dir)); 461 ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
466 ASSERT_TRUE(WaitForEvents()); 462 ASSERT_TRUE(WaitForEvents());
467 } 463 }
468 464
465 // Verify that changing attributes on a file is caught
466 TEST_F(FilePathWatcherTest, FileAttributesChanged) {
467 ASSERT_TRUE(WriteFile(test_file(), "content"));
468 FilePathWatcher watcher;
469 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
470 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get()));
471
472 // Now make sure we get notified if the file is modified.
473 ASSERT_TRUE(file_util::MakeFileUnreadable(test_file()));
474 ASSERT_TRUE(WaitForEvents());
475 }
476
477 enum Permission {
478 Read,
479 Write,
480 Execute
481 };
482
483 bool ChangeFilePermissions(const FilePath& path, Permission perm, bool allow) {
484 #if defined(OS_POSIX)
485 struct stat stat_buf;
486
487 if (stat(path.value().c_str(), &stat_buf) != 0)
488 return false;
489
490 mode_t mode = 0;
491 switch (perm) {
492 case Read:
493 mode = (S_IRUSR | S_IRGRP | S_IROTH);
Mark Mentovai 2011/03/31 01:50:35 You don’t need the (parentheses) in any of these.
494 break;
495 case Write:
496 mode = (S_IWUSR | S_IWGRP | S_IWOTH);
497 break;
498 case Execute:
499 mode = (S_IXUSR | S_IXGRP | S_IXOTH);
500 break;
501 default:
502 ADD_FAILURE() << "unknown perm " << perm;
503 return false;
504 }
505 if (allow) {
506 stat_buf.st_mode |= mode;
507 } else {
508 stat_buf.st_mode &= ~mode;
509 }
510 return chmod(path.value().c_str(), stat_buf.st_mode) == 0;
511
512 #elif defined(OS_WIN)
513 PACL old_dacl;
514 PSECURITY_DESCRIPTOR security_descriptor;
515 if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
516 SE_FILE_OBJECT,
517 DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl,
518 NULL, &security_descriptor) != ERROR_SUCCESS)
519 return false;
520
521 DWORD mode = 0;
522 switch (perm) {
523 case Read:
524 mode = GENERIC_READ;
525 break;
526 case Write:
527 mode = GENERIC_WRITE;
528 break;
529 case Execute:
530 mode = GENERIC_EXECUTE;
531 break;
532 default:
533 ADD_FAILURE() << "unknown perm " << perm;
534 return false;
535 }
536
537 // Deny Read access for the current user.
538 EXPLICIT_ACCESS change;
539 change.grfAccessPermissions = mode;
540 change.grfAccessMode = allow ? GRANT_ACCESS : DENY_ACCESS;
541 change.grfInheritance = 0;
542 change.Trustee.pMultipleTrustee = NULL;
543 change.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
544 change.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
545 change.Trustee.TrusteeType = TRUSTEE_IS_USER;
546 change.Trustee.ptstrName = L"CURRENT_USER";
547
548 PACL new_dacl;
549 if (SetEntriesInAcl(1, &change, old_dacl, &new_dacl) != ERROR_SUCCESS) {
550 LocalFree(security_descriptor);
551 return false;
552 }
553
554 DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
555 SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
556 NULL, NULL, new_dacl, NULL);
557 LocalFree(security_descriptor);
558 LocalFree(new_dacl);
559
560 return rc == ERROR_SUCCESS;
561 #else
562 NOTIMPLEMENTED();
563 return false;
564 #endif
565 }
566
567 // Verify that changing attributes on a directory works.
568 TEST_F(FilePathWatcherTest, DirAttributesChanged) {
569 FilePath test_dir1(temp_dir_.path().AppendASCII("DirAttributesChangedDir1"));
570 FilePath test_dir2(test_dir1.AppendASCII("DirAttributesChangedDir2"));
571 FilePath test_file(test_dir2.AppendASCII("DirAttributesChangedFile"));
572 // Setup a directory hierarchy.
573 ASSERT_TRUE(file_util::CreateDirectory(test_dir1));
574 ASSERT_TRUE(file_util::CreateDirectory(test_dir2));
575 ASSERT_TRUE(WriteFile(test_file, "content"));
576
577 FilePathWatcher watcher;
578 scoped_refptr<TestDelegate> delegate(new TestDelegate(collector()));
579 ASSERT_TRUE(SetupWatch(test_file, &watcher, delegate.get()));
580
581 // We should not get notified in this case as it hasn't affected our ability
582 // to access the file.
583 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, false));
584 loop_.PostDelayedTask(FROM_HERE,
585 new MessageLoop::QuitTask,
586 TestTimeouts::tiny_timeout_ms());
587 ASSERT_FALSE(WaitForEvents());
588 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, true));
589
590 // We should get notified in this case because filepathwatcher can no
591 // longer access the file
592 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, false));
593 ASSERT_TRUE(WaitForEvents());
594 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, true));
595 }
596
469 } // namespace 597 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698