1 // Copyright 2013 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 "chrome/browser/chromeos/file_manager/file_watcher.h"
7 #include "base/files/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "content/public/test/test_browser_thread_bundle.h"
12 #include "google_apis/drive/test_util.h"
13 #include "testing/gtest/include/gtest/gtest.h"
15 namespace file_manager
{
18 using google_apis::test_util::CreateQuitCallback
;
19 using google_apis::test_util::CreateCopyResultCallback
;
21 class FileManagerFileWatcherTest
: public testing::Test
{
23 // Use IO_MAINLOOP so FilePathWatcher works in the fake FILE thread, which
24 // is actually shared with the main thread.
25 FileManagerFileWatcherTest()
26 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP
) {
30 content::TestBrowserThreadBundle thread_bundle_
;
33 TEST_F(FileManagerFileWatcherTest
, AddAndRemoveOneExtensionId
) {
34 const base::FilePath kVirtualPath
=
35 base::FilePath::FromUTF8Unsafe("foo/bar.txt");
36 const char kExtensionId
[] = "extension-id";
38 FileWatcher
file_watcher(kVirtualPath
);
39 file_watcher
.AddExtension(kExtensionId
);
40 std::vector
<std::string
> extension_ids
= file_watcher
.GetExtensionIds();
42 ASSERT_EQ(1U, extension_ids
.size());
43 ASSERT_EQ(kExtensionId
, extension_ids
[0]);
45 file_watcher
.RemoveExtension(kExtensionId
);
46 extension_ids
= file_watcher
.GetExtensionIds();
47 ASSERT_EQ(0U, extension_ids
.size());
50 TEST_F(FileManagerFileWatcherTest
, AddAndRemoveMultipleExtensionIds
) {
51 const base::FilePath kVirtualPath
=
52 base::FilePath::FromUTF8Unsafe("foo/bar.txt");
53 const char kExtensionFooId
[] = "extension-foo-id";
54 const char kExtensionBarId
[] = "extension-bar-id";
56 FileWatcher
file_watcher(kVirtualPath
);
57 file_watcher
.AddExtension(kExtensionFooId
);
58 file_watcher
.AddExtension(kExtensionBarId
);
59 std::vector
<std::string
> extension_ids
= file_watcher
.GetExtensionIds();
61 // The list should be sorted.
62 ASSERT_EQ(2U, extension_ids
.size());
63 ASSERT_EQ(kExtensionBarId
, extension_ids
[0]);
64 ASSERT_EQ(kExtensionFooId
, extension_ids
[1]);
66 // Remove Foo. Bar should remain.
67 file_watcher
.RemoveExtension(kExtensionFooId
);
68 extension_ids
= file_watcher
.GetExtensionIds();
69 ASSERT_EQ(1U, extension_ids
.size());
70 ASSERT_EQ(kExtensionBarId
, extension_ids
[0]);
72 // Remove Bar. Nothing should remain.
73 file_watcher
.RemoveExtension(kExtensionBarId
);
74 extension_ids
= file_watcher
.GetExtensionIds();
75 ASSERT_EQ(0U, extension_ids
.size());
78 TEST_F(FileManagerFileWatcherTest
, AddSameExtensionMultipleTimes
) {
79 const base::FilePath kVirtualPath
=
80 base::FilePath::FromUTF8Unsafe("foo/bar.txt");
81 const char kExtensionId
[] = "extension-id";
83 FileWatcher
file_watcher(kVirtualPath
);
85 file_watcher
.AddExtension(kExtensionId
);
86 file_watcher
.AddExtension(kExtensionId
);
87 file_watcher
.AddExtension(kExtensionId
);
89 std::vector
<std::string
> extension_ids
= file_watcher
.GetExtensionIds();
90 ASSERT_EQ(1U, extension_ids
.size());
91 ASSERT_EQ(kExtensionId
, extension_ids
[0]);
94 file_watcher
.RemoveExtension(kExtensionId
);
95 extension_ids
= file_watcher
.GetExtensionIds();
96 ASSERT_EQ(1U, extension_ids
.size());
99 file_watcher
.RemoveExtension(kExtensionId
);
100 extension_ids
= file_watcher
.GetExtensionIds();
101 ASSERT_EQ(1U, extension_ids
.size());
103 // Remove 3rd time. The extension ID should be gone now.
104 file_watcher
.RemoveExtension(kExtensionId
);
105 extension_ids
= file_watcher
.GetExtensionIds();
106 ASSERT_EQ(0U, extension_ids
.size());
109 TEST_F(FileManagerFileWatcherTest
, WatchLocalFile
) {
110 const base::FilePath kVirtualPath
=
111 base::FilePath::FromUTF8Unsafe("foo/bar.txt");
112 const char kExtensionId
[] = "extension-id";
114 // Create a temporary directory.
115 base::ScopedTempDir temp_dir
;
116 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
118 // See the comment at the end of this function for why scoped_ptr is used.
119 scoped_ptr
<FileWatcher
> file_watcher(
120 new FileWatcher(kVirtualPath
));
121 file_watcher
->AddExtension(kExtensionId
);
123 // Start watching changes in the temporary directory.
124 base::FilePath changed_path
;
125 bool watcher_created
= false;
126 bool on_change_error
= false;
127 base::RunLoop run_loop
;
128 file_watcher
->WatchLocalFile(
132 CreateCopyResultCallback(&changed_path
, &on_change_error
)),
133 CreateCopyResultCallback(&watcher_created
));
134 // Spin the message loop so the base::FilePathWatcher is created.
135 base::RunLoop().RunUntilIdle();
136 ASSERT_TRUE(watcher_created
);
138 // Create a temporary file in the temporary directory. The file watcher
139 // should detect the change in the directory.
140 base::FilePath temp_file_path
;
141 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir
.path(), &temp_file_path
));
142 // Wait until the directory change is notified.
144 ASSERT_FALSE(on_change_error
);
145 ASSERT_EQ(temp_dir
.path().value(), changed_path
.value());
147 // This is ugly, but FileWatcher should be deleted explicitly here, and
148 // spin the message loop so the base::FilePathWatcher is deleted.
149 // Otherwise, base::FilePathWatcher may detect a change when the temporary
150 // directory is deleted, which may result in crash.
151 file_watcher
.reset();
152 base::RunLoop().RunUntilIdle();
156 } // namespace file_manager.