Add missing pnacl libraries and headers and tools.
[chromium-blink-merge.git] / base / files / file_path_watcher_browsertest.cc
blob48d8d0d66ac8a7997710f3aa9daeec0068dad3a2
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/files/file_path_watcher.h"
7 #if defined(OS_WIN)
8 #include <windows.h>
9 #include <aclapi.h>
10 #elif defined(OS_POSIX)
11 #include <sys/stat.h>
12 #endif
14 #include <set>
16 #include "base/basictypes.h"
17 #include "base/bind.h"
18 #include "base/bind_helpers.h"
19 #include "base/compiler_specific.h"
20 #include "base/file_util.h"
21 #include "base/files/file_path.h"
22 #include "base/files/scoped_temp_dir.h"
23 #include "base/message_loop.h"
24 #include "base/message_loop_proxy.h"
25 #include "base/run_loop.h"
26 #include "base/stl_util.h"
27 #include "base/stringprintf.h"
28 #include "base/synchronization/waitable_event.h"
29 #include "base/test/test_file_util.h"
30 #include "base/test/test_timeouts.h"
31 #include "base/threading/thread.h"
32 #include "testing/gtest/include/gtest/gtest.h"
34 namespace base {
36 namespace {
38 class TestDelegate;
40 // Aggregates notifications from the test delegates and breaks the message loop
41 // the test thread is waiting on once they all came in.
42 class NotificationCollector
43 : public base::RefCountedThreadSafe<NotificationCollector> {
44 public:
45 NotificationCollector()
46 : loop_(base::MessageLoopProxy::current()) {}
48 // Called from the file thread by the delegates.
49 void OnChange(TestDelegate* delegate) {
50 loop_->PostTask(FROM_HERE,
51 base::Bind(&NotificationCollector::RecordChange, this,
52 base::Unretained(delegate)));
55 void Register(TestDelegate* delegate) {
56 delegates_.insert(delegate);
59 void Reset() {
60 signaled_.clear();
63 bool Success() {
64 return signaled_ == delegates_;
67 private:
68 friend class base::RefCountedThreadSafe<NotificationCollector>;
69 ~NotificationCollector() {}
71 void RecordChange(TestDelegate* delegate) {
72 // Warning: |delegate| is Unretained. Do not dereference.
73 ASSERT_TRUE(loop_->BelongsToCurrentThread());
74 ASSERT_TRUE(delegates_.count(delegate));
75 signaled_.insert(delegate);
77 // Check whether all delegates have been signaled.
78 if (signaled_ == delegates_)
79 loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
82 // Set of registered delegates.
83 std::set<TestDelegate*> delegates_;
85 // Set of signaled delegates.
86 std::set<TestDelegate*> signaled_;
88 // The loop we should break after all delegates signaled.
89 scoped_refptr<base::MessageLoopProxy> loop_;
92 class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> {
93 public:
94 TestDelegateBase() {}
95 virtual ~TestDelegateBase() {}
97 virtual void OnFileChanged(const FilePath& path, bool error) = 0;
99 private:
100 DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
103 // A mock class for testing. Gmock is not appropriate because it is not
104 // thread-safe for setting expectations. Thus the test code cannot safely
105 // reset expectations while the file watcher is running.
106 // Instead, TestDelegate gets the notifications from FilePathWatcher and uses
107 // NotificationCollector to aggregate the results.
108 class TestDelegate : public TestDelegateBase {
109 public:
110 explicit TestDelegate(NotificationCollector* collector)
111 : collector_(collector) {
112 collector_->Register(this);
114 virtual ~TestDelegate() {}
116 virtual void OnFileChanged(const FilePath& path, bool error) OVERRIDE {
117 if (error)
118 ADD_FAILURE() << "Error " << path.value();
119 else
120 collector_->OnChange(this);
123 private:
124 scoped_refptr<NotificationCollector> collector_;
126 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
129 void SetupWatchCallback(const FilePath& target,
130 FilePathWatcher* watcher,
131 TestDelegateBase* delegate,
132 bool recursive_watch,
133 bool* result,
134 base::WaitableEvent* completion) {
135 *result = watcher->Watch(target, recursive_watch,
136 base::Bind(&TestDelegateBase::OnFileChanged,
137 delegate->AsWeakPtr()));
138 completion->Signal();
141 void QuitLoopWatchCallback(MessageLoop* loop,
142 const FilePath& expected_path,
143 bool expected_error,
144 bool* flag,
145 const FilePath& path,
146 bool error) {
147 ASSERT_TRUE(flag);
148 *flag = true;
149 EXPECT_EQ(expected_path, path);
150 EXPECT_EQ(expected_error, error);
151 loop->PostTask(FROM_HERE, loop->QuitWhenIdleClosure());
154 class FilePathWatcherTest : public testing::Test {
155 public:
156 FilePathWatcherTest()
157 : file_thread_("FilePathWatcherTest") {}
159 virtual ~FilePathWatcherTest() {}
161 protected:
162 virtual void SetUp() OVERRIDE {
163 // Create a separate file thread in order to test proper thread usage.
164 base::Thread::Options options(MessageLoop::TYPE_IO, 0);
165 ASSERT_TRUE(file_thread_.StartWithOptions(options));
166 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
167 collector_ = new NotificationCollector();
170 virtual void TearDown() OVERRIDE {
171 RunLoop().RunUntilIdle();
174 void DeleteDelegateOnFileThread(TestDelegate* delegate) {
175 file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, delegate);
178 FilePath test_file() {
179 return temp_dir_.path().AppendASCII("FilePathWatcherTest");
182 FilePath test_link() {
183 return temp_dir_.path().AppendASCII("FilePathWatcherTest.lnk");
186 // Write |content| to |file|. Returns true on success.
187 bool WriteFile(const FilePath& file, const std::string& content) {
188 int write_size = file_util::WriteFile(file, content.c_str(),
189 content.length());
190 return write_size == static_cast<int>(content.length());
193 bool SetupWatch(const FilePath& target,
194 FilePathWatcher* watcher,
195 TestDelegateBase* delegate,
196 bool recursive_watch) WARN_UNUSED_RESULT;
198 bool WaitForEvents() WARN_UNUSED_RESULT {
199 collector_->Reset();
200 loop_.Run();
201 return collector_->Success();
204 NotificationCollector* collector() { return collector_.get(); }
206 MessageLoop loop_;
207 base::Thread file_thread_;
208 ScopedTempDir temp_dir_;
209 scoped_refptr<NotificationCollector> collector_;
211 DISALLOW_COPY_AND_ASSIGN(FilePathWatcherTest);
214 bool FilePathWatcherTest::SetupWatch(const FilePath& target,
215 FilePathWatcher* watcher,
216 TestDelegateBase* delegate,
217 bool recursive_watch) {
218 base::WaitableEvent completion(false, false);
219 bool result;
220 file_thread_.message_loop_proxy()->PostTask(
221 FROM_HERE,
222 base::Bind(SetupWatchCallback,
223 target, watcher, delegate, recursive_watch, &result,
224 &completion));
225 completion.Wait();
226 return result;
229 // Basic test: Create the file and verify that we notice.
230 TEST_F(FilePathWatcherTest, NewFile) {
231 FilePathWatcher watcher;
232 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
233 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
235 ASSERT_TRUE(WriteFile(test_file(), "content"));
236 ASSERT_TRUE(WaitForEvents());
237 DeleteDelegateOnFileThread(delegate.release());
240 // Verify that modifying the file is caught.
241 TEST_F(FilePathWatcherTest, ModifiedFile) {
242 ASSERT_TRUE(WriteFile(test_file(), "content"));
244 FilePathWatcher watcher;
245 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
246 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
248 // Now make sure we get notified if the file is modified.
249 ASSERT_TRUE(WriteFile(test_file(), "new content"));
250 ASSERT_TRUE(WaitForEvents());
251 DeleteDelegateOnFileThread(delegate.release());
254 // Verify that moving the file into place is caught.
255 TEST_F(FilePathWatcherTest, MovedFile) {
256 FilePath source_file(temp_dir_.path().AppendASCII("source"));
257 ASSERT_TRUE(WriteFile(source_file, "content"));
259 FilePathWatcher watcher;
260 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
261 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
263 // Now make sure we get notified if the file is modified.
264 ASSERT_TRUE(file_util::Move(source_file, test_file()));
265 ASSERT_TRUE(WaitForEvents());
266 DeleteDelegateOnFileThread(delegate.release());
269 TEST_F(FilePathWatcherTest, DeletedFile) {
270 ASSERT_TRUE(WriteFile(test_file(), "content"));
272 FilePathWatcher watcher;
273 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
274 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
276 // Now make sure we get notified if the file is deleted.
277 file_util::Delete(test_file(), false);
278 ASSERT_TRUE(WaitForEvents());
279 DeleteDelegateOnFileThread(delegate.release());
282 // Used by the DeleteDuringNotify test below.
283 // Deletes the FilePathWatcher when it's notified.
284 class Deleter : public TestDelegateBase {
285 public:
286 Deleter(FilePathWatcher* watcher, MessageLoop* loop)
287 : watcher_(watcher),
288 loop_(loop) {
290 virtual ~Deleter() {}
292 virtual void OnFileChanged(const FilePath&, bool) OVERRIDE {
293 watcher_.reset();
294 loop_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
297 FilePathWatcher* watcher() const { return watcher_.get(); }
299 private:
300 scoped_ptr<FilePathWatcher> watcher_;
301 MessageLoop* loop_;
303 DISALLOW_COPY_AND_ASSIGN(Deleter);
306 // Verify that deleting a watcher during the callback doesn't crash.
307 TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
308 FilePathWatcher* watcher = new FilePathWatcher;
309 // Takes ownership of watcher.
310 scoped_ptr<Deleter> deleter(new Deleter(watcher, &loop_));
311 ASSERT_TRUE(SetupWatch(test_file(), watcher, deleter.get(), false));
313 ASSERT_TRUE(WriteFile(test_file(), "content"));
314 ASSERT_TRUE(WaitForEvents());
316 // We win if we haven't crashed yet.
317 // Might as well double-check it got deleted, too.
318 ASSERT_TRUE(deleter->watcher() == NULL);
321 // Verify that deleting the watcher works even if there is a pending
322 // notification.
323 // Flaky on MacOS. http://crbug.com/85930
324 #if defined(OS_MACOSX)
325 #define MAYBE_DestroyWithPendingNotification \
326 DISABLED_DestroyWithPendingNotification
327 #else
328 #define MAYBE_DestroyWithPendingNotification DestroyWithPendingNotification
329 #endif
330 TEST_F(FilePathWatcherTest, MAYBE_DestroyWithPendingNotification) {
331 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
332 FilePathWatcher* watcher = new FilePathWatcher;
333 ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get(), false));
334 ASSERT_TRUE(WriteFile(test_file(), "content"));
335 file_thread_.message_loop_proxy()->DeleteSoon(FROM_HERE, watcher);
336 DeleteDelegateOnFileThread(delegate.release());
339 TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) {
340 FilePathWatcher watcher1, watcher2;
341 scoped_ptr<TestDelegate> delegate1(new TestDelegate(collector()));
342 scoped_ptr<TestDelegate> delegate2(new TestDelegate(collector()));
343 ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get(), false));
344 ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get(), false));
346 ASSERT_TRUE(WriteFile(test_file(), "content"));
347 ASSERT_TRUE(WaitForEvents());
348 DeleteDelegateOnFileThread(delegate1.release());
349 DeleteDelegateOnFileThread(delegate2.release());
352 // Verify that watching a file whose parent directory doesn't exist yet works if
353 // the directory and file are created eventually.
354 TEST_F(FilePathWatcherTest, NonExistentDirectory) {
355 FilePathWatcher watcher;
356 FilePath dir(temp_dir_.path().AppendASCII("dir"));
357 FilePath file(dir.AppendASCII("file"));
358 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
359 ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
361 ASSERT_TRUE(file_util::CreateDirectory(dir));
363 ASSERT_TRUE(WriteFile(file, "content"));
365 VLOG(1) << "Waiting for file creation";
366 ASSERT_TRUE(WaitForEvents());
368 ASSERT_TRUE(WriteFile(file, "content v2"));
369 VLOG(1) << "Waiting for file change";
370 ASSERT_TRUE(WaitForEvents());
372 ASSERT_TRUE(file_util::Delete(file, false));
373 VLOG(1) << "Waiting for file deletion";
374 ASSERT_TRUE(WaitForEvents());
375 DeleteDelegateOnFileThread(delegate.release());
378 // Exercises watch reconfiguration for the case that directories on the path
379 // are rapidly created.
380 TEST_F(FilePathWatcherTest, DirectoryChain) {
381 FilePath path(temp_dir_.path());
382 std::vector<std::string> dir_names;
383 for (int i = 0; i < 20; i++) {
384 std::string dir(base::StringPrintf("d%d", i));
385 dir_names.push_back(dir);
386 path = path.AppendASCII(dir);
389 FilePathWatcher watcher;
390 FilePath file(path.AppendASCII("file"));
391 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
392 ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
394 FilePath sub_path(temp_dir_.path());
395 for (std::vector<std::string>::const_iterator d(dir_names.begin());
396 d != dir_names.end(); ++d) {
397 sub_path = sub_path.AppendASCII(*d);
398 ASSERT_TRUE(file_util::CreateDirectory(sub_path));
400 VLOG(1) << "Create File";
401 ASSERT_TRUE(WriteFile(file, "content"));
402 VLOG(1) << "Waiting for file creation";
403 ASSERT_TRUE(WaitForEvents());
405 ASSERT_TRUE(WriteFile(file, "content v2"));
406 VLOG(1) << "Waiting for file modification";
407 ASSERT_TRUE(WaitForEvents());
408 DeleteDelegateOnFileThread(delegate.release());
411 #if defined(OS_MACOSX)
412 // http://crbug.com/85930
413 #define DisappearingDirectory DISABLED_DisappearingDirectory
414 #endif
415 TEST_F(FilePathWatcherTest, DisappearingDirectory) {
416 FilePathWatcher watcher;
417 FilePath dir(temp_dir_.path().AppendASCII("dir"));
418 FilePath file(dir.AppendASCII("file"));
419 ASSERT_TRUE(file_util::CreateDirectory(dir));
420 ASSERT_TRUE(WriteFile(file, "content"));
421 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
422 ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
424 ASSERT_TRUE(file_util::Delete(dir, true));
425 ASSERT_TRUE(WaitForEvents());
426 DeleteDelegateOnFileThread(delegate.release());
429 // Tests that a file that is deleted and reappears is tracked correctly.
430 TEST_F(FilePathWatcherTest, DeleteAndRecreate) {
431 ASSERT_TRUE(WriteFile(test_file(), "content"));
432 FilePathWatcher watcher;
433 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
434 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
436 ASSERT_TRUE(file_util::Delete(test_file(), false));
437 VLOG(1) << "Waiting for file deletion";
438 ASSERT_TRUE(WaitForEvents());
440 ASSERT_TRUE(WriteFile(test_file(), "content"));
441 VLOG(1) << "Waiting for file creation";
442 ASSERT_TRUE(WaitForEvents());
443 DeleteDelegateOnFileThread(delegate.release());
446 TEST_F(FilePathWatcherTest, WatchDirectory) {
447 FilePathWatcher watcher;
448 FilePath dir(temp_dir_.path().AppendASCII("dir"));
449 FilePath file1(dir.AppendASCII("file1"));
450 FilePath file2(dir.AppendASCII("file2"));
451 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
452 ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get(), false));
454 ASSERT_TRUE(file_util::CreateDirectory(dir));
455 VLOG(1) << "Waiting for directory creation";
456 ASSERT_TRUE(WaitForEvents());
458 ASSERT_TRUE(WriteFile(file1, "content"));
459 VLOG(1) << "Waiting for file1 creation";
460 ASSERT_TRUE(WaitForEvents());
462 #if !defined(OS_MACOSX)
463 // Mac implementation does not detect files modified in a directory.
464 ASSERT_TRUE(WriteFile(file1, "content v2"));
465 VLOG(1) << "Waiting for file1 modification";
466 ASSERT_TRUE(WaitForEvents());
467 #endif // !OS_MACOSX
469 ASSERT_TRUE(file_util::Delete(file1, false));
470 VLOG(1) << "Waiting for file1 deletion";
471 ASSERT_TRUE(WaitForEvents());
473 ASSERT_TRUE(WriteFile(file2, "content"));
474 VLOG(1) << "Waiting for file2 creation";
475 ASSERT_TRUE(WaitForEvents());
476 DeleteDelegateOnFileThread(delegate.release());
479 TEST_F(FilePathWatcherTest, MoveParent) {
480 FilePathWatcher file_watcher;
481 FilePathWatcher subdir_watcher;
482 FilePath dir(temp_dir_.path().AppendASCII("dir"));
483 FilePath dest(temp_dir_.path().AppendASCII("dest"));
484 FilePath subdir(dir.AppendASCII("subdir"));
485 FilePath file(subdir.AppendASCII("file"));
486 scoped_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
487 ASSERT_TRUE(SetupWatch(file, &file_watcher, file_delegate.get(), false));
488 scoped_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
489 ASSERT_TRUE(SetupWatch(subdir, &subdir_watcher, subdir_delegate.get(),
490 false));
492 // Setup a directory hierarchy.
493 ASSERT_TRUE(file_util::CreateDirectory(subdir));
494 ASSERT_TRUE(WriteFile(file, "content"));
495 VLOG(1) << "Waiting for file creation";
496 ASSERT_TRUE(WaitForEvents());
498 // Move the parent directory.
499 file_util::Move(dir, dest);
500 VLOG(1) << "Waiting for directory move";
501 ASSERT_TRUE(WaitForEvents());
502 DeleteDelegateOnFileThread(file_delegate.release());
503 DeleteDelegateOnFileThread(subdir_delegate.release());
506 #if defined(OS_WIN)
507 TEST_F(FilePathWatcherTest, RecursiveWatch) {
508 FilePathWatcher watcher;
509 FilePath dir(temp_dir_.path().AppendASCII("dir"));
510 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
511 ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get(), true));
513 // Main directory("dir") creation.
514 ASSERT_TRUE(file_util::CreateDirectory(dir));
515 ASSERT_TRUE(WaitForEvents());
517 // Create "$dir/file1".
518 FilePath file1(dir.AppendASCII("file1"));
519 ASSERT_TRUE(WriteFile(file1, "content"));
520 ASSERT_TRUE(WaitForEvents());
522 // Create "$dir/subdir".
523 FilePath subdir(dir.AppendASCII("subdir"));
524 ASSERT_TRUE(file_util::CreateDirectory(subdir));
525 ASSERT_TRUE(WaitForEvents());
527 // Create "$dir/subdir/subdir_file1".
528 FilePath subdir_file1(subdir.AppendASCII("subdir_file1"));
529 ASSERT_TRUE(WriteFile(subdir_file1, "content"));
530 ASSERT_TRUE(WaitForEvents());
532 // Create "$dir/subdir/subdir_child_dir".
533 FilePath subdir_child_dir(subdir.AppendASCII("subdir_child_dir"));
534 ASSERT_TRUE(file_util::CreateDirectory(subdir_child_dir));
535 ASSERT_TRUE(WaitForEvents());
537 // Create "$dir/subdir/subdir_child_dir/child_dir_file1".
538 FilePath child_dir_file1(subdir_child_dir.AppendASCII("child_dir_file1"));
539 ASSERT_TRUE(WriteFile(child_dir_file1, "content v2"));
540 ASSERT_TRUE(WaitForEvents());
542 // Write into "$dir/subdir/subdir_child_dir/child_dir_file1".
543 ASSERT_TRUE(WriteFile(child_dir_file1, "content"));
544 ASSERT_TRUE(WaitForEvents());
546 // Modify "$dir/subdir/subdir_child_dir/child_dir_file1" attributes.
547 ASSERT_TRUE(file_util::MakeFileUnreadable(child_dir_file1));
548 ASSERT_TRUE(WaitForEvents());
550 // Delete "$dir/subdir/subdir_file1".
551 ASSERT_TRUE(file_util::Delete(subdir_file1, false));
552 ASSERT_TRUE(WaitForEvents());
554 // Delete "$dir/subdir/subdir_child_dir/child_dir_file1".
555 ASSERT_TRUE(file_util::Delete(child_dir_file1, false));
556 ASSERT_TRUE(WaitForEvents());
557 DeleteDelegateOnFileThread(delegate.release());
559 #else
560 TEST_F(FilePathWatcherTest, RecursiveWatch) {
561 FilePathWatcher watcher;
562 FilePath dir(temp_dir_.path().AppendASCII("dir"));
563 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
564 // Non-Windows implementaion does not support recursive watching.
565 ASSERT_FALSE(SetupWatch(dir, &watcher, delegate.get(), true));
566 DeleteDelegateOnFileThread(delegate.release());
568 #endif
570 TEST_F(FilePathWatcherTest, MoveChild) {
571 FilePathWatcher file_watcher;
572 FilePathWatcher subdir_watcher;
573 FilePath source_dir(temp_dir_.path().AppendASCII("source"));
574 FilePath source_subdir(source_dir.AppendASCII("subdir"));
575 FilePath source_file(source_subdir.AppendASCII("file"));
576 FilePath dest_dir(temp_dir_.path().AppendASCII("dest"));
577 FilePath dest_subdir(dest_dir.AppendASCII("subdir"));
578 FilePath dest_file(dest_subdir.AppendASCII("file"));
580 // Setup a directory hierarchy.
581 ASSERT_TRUE(file_util::CreateDirectory(source_subdir));
582 ASSERT_TRUE(WriteFile(source_file, "content"));
584 scoped_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
585 ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get(), false));
586 scoped_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
587 ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get(),
588 false));
590 // Move the directory into place, s.t. the watched file appears.
591 ASSERT_TRUE(file_util::Move(source_dir, dest_dir));
592 ASSERT_TRUE(WaitForEvents());
593 DeleteDelegateOnFileThread(file_delegate.release());
594 DeleteDelegateOnFileThread(subdir_delegate.release());
597 #if !defined(OS_LINUX)
598 // Linux implementation of FilePathWatcher doesn't catch attribute changes.
599 // http://crbug.com/78043
601 // Verify that changing attributes on a file is caught
602 TEST_F(FilePathWatcherTest, FileAttributesChanged) {
603 ASSERT_TRUE(WriteFile(test_file(), "content"));
604 FilePathWatcher watcher;
605 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
606 ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
608 // Now make sure we get notified if the file is modified.
609 ASSERT_TRUE(file_util::MakeFileUnreadable(test_file()));
610 ASSERT_TRUE(WaitForEvents());
611 DeleteDelegateOnFileThread(delegate.release());
614 #endif // !OS_LINUX
616 #if defined(OS_LINUX)
618 // Verify that creating a symlink is caught.
619 TEST_F(FilePathWatcherTest, CreateLink) {
620 FilePathWatcher watcher;
621 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
622 // Note that we are watching the symlink
623 ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
625 // Now make sure we get notified if the link is created.
626 // Note that test_file() doesn't have to exist.
627 ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
628 ASSERT_TRUE(WaitForEvents());
629 DeleteDelegateOnFileThread(delegate.release());
632 // Verify that deleting a symlink is caught.
633 TEST_F(FilePathWatcherTest, DeleteLink) {
634 // Unfortunately this test case only works if the link target exists.
635 // TODO(craig) fix this as part of crbug.com/91561.
636 ASSERT_TRUE(WriteFile(test_file(), "content"));
637 ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
638 FilePathWatcher watcher;
639 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
640 ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
642 // Now make sure we get notified if the link is deleted.
643 ASSERT_TRUE(file_util::Delete(test_link(), false));
644 ASSERT_TRUE(WaitForEvents());
645 DeleteDelegateOnFileThread(delegate.release());
648 // Verify that modifying a target file that a link is pointing to
649 // when we are watching the link is caught.
650 TEST_F(FilePathWatcherTest, ModifiedLinkedFile) {
651 ASSERT_TRUE(WriteFile(test_file(), "content"));
652 ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
653 FilePathWatcher watcher;
654 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
655 // Note that we are watching the symlink.
656 ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
658 // Now make sure we get notified if the file is modified.
659 ASSERT_TRUE(WriteFile(test_file(), "new content"));
660 ASSERT_TRUE(WaitForEvents());
661 DeleteDelegateOnFileThread(delegate.release());
664 // Verify that creating a target file that a link is pointing to
665 // when we are watching the link is caught.
666 TEST_F(FilePathWatcherTest, CreateTargetLinkedFile) {
667 ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
668 FilePathWatcher watcher;
669 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
670 // Note that we are watching the symlink.
671 ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
673 // Now make sure we get notified if the target file is created.
674 ASSERT_TRUE(WriteFile(test_file(), "content"));
675 ASSERT_TRUE(WaitForEvents());
676 DeleteDelegateOnFileThread(delegate.release());
679 // Verify that deleting a target file that a link is pointing to
680 // when we are watching the link is caught.
681 TEST_F(FilePathWatcherTest, DeleteTargetLinkedFile) {
682 ASSERT_TRUE(WriteFile(test_file(), "content"));
683 ASSERT_TRUE(file_util::CreateSymbolicLink(test_file(), test_link()));
684 FilePathWatcher watcher;
685 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
686 // Note that we are watching the symlink.
687 ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
689 // Now make sure we get notified if the target file is deleted.
690 ASSERT_TRUE(file_util::Delete(test_file(), false));
691 ASSERT_TRUE(WaitForEvents());
692 DeleteDelegateOnFileThread(delegate.release());
695 // Verify that watching a file whose parent directory is a link that
696 // doesn't exist yet works if the symlink is created eventually.
697 TEST_F(FilePathWatcherTest, LinkedDirectoryPart1) {
698 FilePathWatcher watcher;
699 FilePath dir(temp_dir_.path().AppendASCII("dir"));
700 FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
701 FilePath file(dir.AppendASCII("file"));
702 FilePath linkfile(link_dir.AppendASCII("file"));
703 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
704 // dir/file should exist.
705 ASSERT_TRUE(file_util::CreateDirectory(dir));
706 ASSERT_TRUE(WriteFile(file, "content"));
707 // Note that we are watching dir.lnk/file which doesn't exist yet.
708 ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
710 ASSERT_TRUE(file_util::CreateSymbolicLink(dir, link_dir));
711 VLOG(1) << "Waiting for link creation";
712 ASSERT_TRUE(WaitForEvents());
714 ASSERT_TRUE(WriteFile(file, "content v2"));
715 VLOG(1) << "Waiting for file change";
716 ASSERT_TRUE(WaitForEvents());
718 ASSERT_TRUE(file_util::Delete(file, false));
719 VLOG(1) << "Waiting for file deletion";
720 ASSERT_TRUE(WaitForEvents());
721 DeleteDelegateOnFileThread(delegate.release());
724 // Verify that watching a file whose parent directory is a
725 // dangling symlink works if the directory is created eventually.
726 TEST_F(FilePathWatcherTest, LinkedDirectoryPart2) {
727 FilePathWatcher watcher;
728 FilePath dir(temp_dir_.path().AppendASCII("dir"));
729 FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
730 FilePath file(dir.AppendASCII("file"));
731 FilePath linkfile(link_dir.AppendASCII("file"));
732 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
733 // Now create the link from dir.lnk pointing to dir but
734 // neither dir nor dir/file exist yet.
735 ASSERT_TRUE(file_util::CreateSymbolicLink(dir, link_dir));
736 // Note that we are watching dir.lnk/file.
737 ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
739 ASSERT_TRUE(file_util::CreateDirectory(dir));
740 ASSERT_TRUE(WriteFile(file, "content"));
741 VLOG(1) << "Waiting for dir/file creation";
742 ASSERT_TRUE(WaitForEvents());
744 ASSERT_TRUE(WriteFile(file, "content v2"));
745 VLOG(1) << "Waiting for file change";
746 ASSERT_TRUE(WaitForEvents());
748 ASSERT_TRUE(file_util::Delete(file, false));
749 VLOG(1) << "Waiting for file deletion";
750 ASSERT_TRUE(WaitForEvents());
751 DeleteDelegateOnFileThread(delegate.release());
754 // Verify that watching a file with a symlink on the path
755 // to the file works.
756 TEST_F(FilePathWatcherTest, LinkedDirectoryPart3) {
757 FilePathWatcher watcher;
758 FilePath dir(temp_dir_.path().AppendASCII("dir"));
759 FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
760 FilePath file(dir.AppendASCII("file"));
761 FilePath linkfile(link_dir.AppendASCII("file"));
762 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
763 ASSERT_TRUE(file_util::CreateDirectory(dir));
764 ASSERT_TRUE(file_util::CreateSymbolicLink(dir, link_dir));
765 // Note that we are watching dir.lnk/file but the file doesn't exist yet.
766 ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
768 ASSERT_TRUE(WriteFile(file, "content"));
769 VLOG(1) << "Waiting for file creation";
770 ASSERT_TRUE(WaitForEvents());
772 ASSERT_TRUE(WriteFile(file, "content v2"));
773 VLOG(1) << "Waiting for file change";
774 ASSERT_TRUE(WaitForEvents());
776 ASSERT_TRUE(file_util::Delete(file, false));
777 VLOG(1) << "Waiting for file deletion";
778 ASSERT_TRUE(WaitForEvents());
779 DeleteDelegateOnFileThread(delegate.release());
782 #endif // OS_LINUX
784 enum Permission {
785 Read,
786 Write,
787 Execute
790 bool ChangeFilePermissions(const FilePath& path, Permission perm, bool allow) {
791 #if defined(OS_POSIX)
792 struct stat stat_buf;
794 if (stat(path.value().c_str(), &stat_buf) != 0)
795 return false;
797 mode_t mode = 0;
798 switch (perm) {
799 case Read:
800 mode = S_IRUSR | S_IRGRP | S_IROTH;
801 break;
802 case Write:
803 mode = S_IWUSR | S_IWGRP | S_IWOTH;
804 break;
805 case Execute:
806 mode = S_IXUSR | S_IXGRP | S_IXOTH;
807 break;
808 default:
809 ADD_FAILURE() << "unknown perm " << perm;
810 return false;
812 if (allow) {
813 stat_buf.st_mode |= mode;
814 } else {
815 stat_buf.st_mode &= ~mode;
817 return chmod(path.value().c_str(), stat_buf.st_mode) == 0;
819 #elif defined(OS_WIN)
820 PACL old_dacl;
821 PSECURITY_DESCRIPTOR security_descriptor;
822 if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
823 SE_FILE_OBJECT,
824 DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl,
825 NULL, &security_descriptor) != ERROR_SUCCESS)
826 return false;
828 DWORD mode = 0;
829 switch (perm) {
830 case Read:
831 mode = GENERIC_READ;
832 break;
833 case Write:
834 mode = GENERIC_WRITE;
835 break;
836 case Execute:
837 mode = GENERIC_EXECUTE;
838 break;
839 default:
840 ADD_FAILURE() << "unknown perm " << perm;
841 return false;
844 // Deny Read access for the current user.
845 EXPLICIT_ACCESS change;
846 change.grfAccessPermissions = mode;
847 change.grfAccessMode = allow ? GRANT_ACCESS : DENY_ACCESS;
848 change.grfInheritance = 0;
849 change.Trustee.pMultipleTrustee = NULL;
850 change.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
851 change.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
852 change.Trustee.TrusteeType = TRUSTEE_IS_USER;
853 change.Trustee.ptstrName = L"CURRENT_USER";
855 PACL new_dacl;
856 if (SetEntriesInAcl(1, &change, old_dacl, &new_dacl) != ERROR_SUCCESS) {
857 LocalFree(security_descriptor);
858 return false;
861 DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
862 SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
863 NULL, NULL, new_dacl, NULL);
864 LocalFree(security_descriptor);
865 LocalFree(new_dacl);
867 return rc == ERROR_SUCCESS;
868 #else
869 NOTIMPLEMENTED();
870 return false;
871 #endif
874 #if defined(OS_MACOSX)
875 // Linux implementation of FilePathWatcher doesn't catch attribute changes.
876 // http://crbug.com/78043
877 // Windows implementation of FilePathWatcher catches attribute changes that
878 // don't affect the path being watched.
879 // http://crbug.com/78045
881 // Verify that changing attributes on a directory works.
882 TEST_F(FilePathWatcherTest, DirAttributesChanged) {
883 FilePath test_dir1(temp_dir_.path().AppendASCII("DirAttributesChangedDir1"));
884 FilePath test_dir2(test_dir1.AppendASCII("DirAttributesChangedDir2"));
885 FilePath test_file(test_dir2.AppendASCII("DirAttributesChangedFile"));
886 // Setup a directory hierarchy.
887 ASSERT_TRUE(file_util::CreateDirectory(test_dir1));
888 ASSERT_TRUE(file_util::CreateDirectory(test_dir2));
889 ASSERT_TRUE(WriteFile(test_file, "content"));
891 FilePathWatcher watcher;
892 scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
893 ASSERT_TRUE(SetupWatch(test_file, &watcher, delegate.get(), false));
895 // We should not get notified in this case as it hasn't affected our ability
896 // to access the file.
897 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, false));
898 loop_.PostDelayedTask(FROM_HERE,
899 MessageLoop::QuitWhenIdleClosure(),
900 TestTimeouts::tiny_timeout());
901 ASSERT_FALSE(WaitForEvents());
902 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, true));
904 // We should get notified in this case because filepathwatcher can no
905 // longer access the file
906 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, false));
907 ASSERT_TRUE(WaitForEvents());
908 ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, true));
909 DeleteDelegateOnFileThread(delegate.release());
912 #endif // OS_MACOSX
913 } // namespace
915 } // namespace base