1bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// found in the LICENSE file.
4bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/chromeos/file_manager/file_watcher.h"
6bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
8bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/files/scoped_temp_dir.h"
9bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/message_loop/message_loop.h"
10bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/run_loop.h"
11bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "content/public/test/test_browser_thread_bundle.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/test_util.h"
13bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "testing/gtest/include/gtest/gtest.h"
14bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
15bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace file_manager {
16bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace {
17bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
18bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochusing google_apis::test_util::CreateQuitCallback;
19bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochusing google_apis::test_util::CreateCopyResultCallback;
20bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
21bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochclass FileManagerFileWatcherTest : public testing::Test {
22bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch public:
23bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Use IO_MAINLOOP so FilePathWatcher works in the fake FILE thread, which
24bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // is actually shared with the main thread.
25bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  FileManagerFileWatcherTest()
26bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
27bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  }
28bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
29bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch private:
30bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  content::TestBrowserThreadBundle thread_bundle_;
31bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch};
32bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
33bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(FileManagerFileWatcherTest, AddAndRemoveOneExtensionId) {
34bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const base::FilePath kVirtualPath =
35bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      base::FilePath::FromUTF8Unsafe("foo/bar.txt");
36bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const char kExtensionId[] = "extension-id";
37bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
38bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  FileWatcher file_watcher(kVirtualPath);
39bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.AddExtension(kExtensionId);
40bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  std::vector<std::string> extension_ids = file_watcher.GetExtensionIds();
41bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
42bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(1U, extension_ids.size());
43bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(kExtensionId, extension_ids[0]);
44bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
45bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.RemoveExtension(kExtensionId);
46bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  extension_ids = file_watcher.GetExtensionIds();
47bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(0U, extension_ids.size());
48bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
49bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
50bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(FileManagerFileWatcherTest, AddAndRemoveMultipleExtensionIds) {
51bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const base::FilePath kVirtualPath =
52bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      base::FilePath::FromUTF8Unsafe("foo/bar.txt");
53bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const char kExtensionFooId[] = "extension-foo-id";
54bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const char kExtensionBarId[] = "extension-bar-id";
55bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
56bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  FileWatcher file_watcher(kVirtualPath);
57bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.AddExtension(kExtensionFooId);
58bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.AddExtension(kExtensionBarId);
59bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  std::vector<std::string> extension_ids = file_watcher.GetExtensionIds();
60bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
61bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // The list should be sorted.
62bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(2U, extension_ids.size());
63bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(kExtensionBarId, extension_ids[0]);
64bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(kExtensionFooId, extension_ids[1]);
65bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
66bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Remove Foo. Bar should remain.
67bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.RemoveExtension(kExtensionFooId);
68bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  extension_ids = file_watcher.GetExtensionIds();
69bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(1U, extension_ids.size());
70bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(kExtensionBarId, extension_ids[0]);
71bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
72bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Remove Bar. Nothing should remain.
73bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.RemoveExtension(kExtensionBarId);
74bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  extension_ids = file_watcher.GetExtensionIds();
75bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(0U, extension_ids.size());
76bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
77bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
78bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(FileManagerFileWatcherTest, AddSameExtensionMultipleTimes) {
79bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const base::FilePath kVirtualPath =
80bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      base::FilePath::FromUTF8Unsafe("foo/bar.txt");
81bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const char kExtensionId[] = "extension-id";
82bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
83bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  FileWatcher file_watcher(kVirtualPath);
84bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Add three times.
85bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.AddExtension(kExtensionId);
86bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.AddExtension(kExtensionId);
87bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.AddExtension(kExtensionId);
88bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
89bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  std::vector<std::string> extension_ids = file_watcher.GetExtensionIds();
90bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(1U, extension_ids.size());
91bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(kExtensionId, extension_ids[0]);
92bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
93bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Remove 1st time.
94bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.RemoveExtension(kExtensionId);
95bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  extension_ids = file_watcher.GetExtensionIds();
96bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(1U, extension_ids.size());
97bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
98bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Remove 2nd time.
99bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.RemoveExtension(kExtensionId);
100bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  extension_ids = file_watcher.GetExtensionIds();
101bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(1U, extension_ids.size());
102bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
103bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Remove 3rd time. The extension ID should be gone now.
104bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.RemoveExtension(kExtensionId);
105bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  extension_ids = file_watcher.GetExtensionIds();
106bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(0U, extension_ids.size());
107bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
108bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
109bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochTEST_F(FileManagerFileWatcherTest, WatchLocalFile) {
110bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const base::FilePath kVirtualPath =
111bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      base::FilePath::FromUTF8Unsafe("foo/bar.txt");
112bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const char kExtensionId[] = "extension-id";
113bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
114bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Create a temporary directory.
115bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::ScopedTempDir temp_dir;
116bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
117bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
118bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // See the comment at the end of this function for why scoped_ptr is used.
119bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  scoped_ptr<FileWatcher> file_watcher(
120bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      new FileWatcher(kVirtualPath));
121bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher->AddExtension(kExtensionId);
122bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
123bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Start watching changes in the temporary directory.
124bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::FilePath changed_path;
125bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  bool watcher_created = false;
126bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  bool on_change_error = false;
127bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::RunLoop run_loop;
128bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher->WatchLocalFile(
129bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      temp_dir.path(),
130bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      CreateQuitCallback(
131bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          &run_loop,
132bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch          CreateCopyResultCallback(&changed_path, &on_change_error)),
133bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      CreateCopyResultCallback(&watcher_created));
134bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Spin the message loop so the base::FilePathWatcher is created.
135bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::RunLoop().RunUntilIdle();
136bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_TRUE(watcher_created);
137bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
138bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Create a temporary file in the temporary directory. The file watcher
139bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // should detect the change in the directory.
140bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::FilePath temp_file_path;
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file_path));
142bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Wait until the directory change is notified.
143bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  run_loop.Run();
144bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_FALSE(on_change_error);
145bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  ASSERT_EQ(temp_dir.path().value(), changed_path.value());
146bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
147bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // This is ugly, but FileWatcher should be deleted explicitly here, and
148bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // spin the message loop so the base::FilePathWatcher is deleted.
149bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // Otherwise, base::FilePathWatcher may detect a change when the temporary
150bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  // directory is deleted, which may result in crash.
151bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  file_watcher.reset();
152bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::RunLoop().RunUntilIdle();
153bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
154bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
155bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}  // namespace
156bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}  // namespace file_manager.
157