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