1// Copyright 2014 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. 4 5#include "chrome/browser/extensions/api/file_system/entry_watcher_service.h" 6 7#include <string> 8#include <vector> 9 10#include "base/files/file.h" 11#include "base/files/file_path.h" 12#include "base/files/scoped_temp_dir.h" 13#include "base/memory/scoped_vector.h" 14#include "base/run_loop.h" 15#include "chrome/common/extensions/api/file_system.h" 16#include "chrome/test/base/testing_profile.h" 17#include "content/public/test/test_browser_thread_bundle.h" 18#include "content/public/test/test_file_system_context.h" 19#include "extensions/browser/event_router.h" 20#include "storage/browser/fileapi/file_system_url.h" 21#include "storage/common/fileapi/file_system_types.h" 22 23namespace extensions { 24namespace { 25 26const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj"; 27 28void LogStatus(std::vector<base::File::Error>* log, base::File::Error status) { 29 log->push_back(status); 30} 31 32} // namespace 33 34class EntryWatcherServiceTest : public testing::Test { 35 protected: 36 EntryWatcherServiceTest() {} 37 virtual ~EntryWatcherServiceTest() {} 38 39 virtual void SetUp() OVERRIDE { 40 profile_.reset(new TestingProfile); 41 ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); 42 file_system_context_ = 43 content::CreateFileSystemContextForTesting(NULL, data_dir_.path()); 44 service_.reset(new EntryWatcherService(profile_.get())); 45 service_->SetDispatchEventImplForTesting(base::Bind( 46 &EntryWatcherServiceTest::DispatchEventImpl, base::Unretained(this))); 47 service_->SetGetFileSystemContextImplForTesting( 48 base::Bind(&EntryWatcherServiceTest::GetFileSystemContextImpl, 49 base::Unretained(this))); 50 testing_url_ = file_system_context_->CreateCrackedFileSystemURL( 51 GURL(std::string("chrome-extension://") + kExtensionId), 52 storage::kFileSystemTypeTest, 53 base::FilePath::FromUTF8Unsafe("/x/y/z")); 54 } 55 56 virtual void TearDown() OVERRIDE { 57 dispatch_event_log_targets_.clear(); 58 dispatch_event_log_events_.clear(); 59 } 60 61 void DispatchEventImpl(const std::string& extension_id, 62 scoped_ptr<Event> event) { 63 dispatch_event_log_targets_.push_back(extension_id); 64 dispatch_event_log_events_.push_back(event.release()); 65 } 66 67 storage::FileSystemContext* GetFileSystemContextImpl( 68 const std::string& extension_id, 69 content::BrowserContext* context) { 70 EXPECT_EQ(kExtensionId, extension_id); 71 EXPECT_EQ(profile_.get(), context); 72 return file_system_context_.get(); 73 } 74 75 content::TestBrowserThreadBundle thread_bundle_; 76 scoped_ptr<TestingProfile> profile_; 77 base::ScopedTempDir data_dir_; 78 scoped_refptr<storage::FileSystemContext> file_system_context_; 79 scoped_ptr<EntryWatcherService> service_; 80 storage::FileSystemURL testing_url_; 81 std::vector<std::string> dispatch_event_log_targets_; 82 ScopedVector<Event> dispatch_event_log_events_; 83}; 84 85TEST_F(EntryWatcherServiceTest, GetWatchedEntries) { 86 std::vector<base::File::Error> log; 87 88 const bool recursive = false; 89 service_->WatchDirectory( 90 kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log)); 91 base::RunLoop().RunUntilIdle(); 92 93 ASSERT_EQ(1u, log.size()); 94 EXPECT_EQ(base::File::FILE_OK, log[0]); 95 96 { 97 const std::vector<storage::FileSystemURL> watched_entries = 98 service_->GetWatchedEntries(kExtensionId); 99 ASSERT_EQ(1u, watched_entries.size()); 100 EXPECT_EQ(testing_url_, watched_entries[0]); 101 } 102 103 { 104 const std::string wrong_extension_id = "abcabcabcabcabcabcabcabcabcabcab"; 105 const std::vector<storage::FileSystemURL> watched_entries = 106 service_->GetWatchedEntries(wrong_extension_id); 107 EXPECT_EQ(0u, watched_entries.size()); 108 } 109} 110 111TEST_F(EntryWatcherServiceTest, WatchDirectory) { 112 std::vector<base::File::Error> log; 113 114 const bool recursive = false; 115 service_->WatchDirectory( 116 kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log)); 117 base::RunLoop().RunUntilIdle(); 118 119 ASSERT_EQ(1u, log.size()); 120 EXPECT_EQ(base::File::FILE_OK, log[0]); 121 122 // The testing WatcherManager implementation emits two hard-coded fake 123 // notifications as soon as the watcher is set properly. See: 124 // TestWatcherManager::WatchDirectory() for details. 125 ASSERT_LE(1u, dispatch_event_log_targets_.size()); 126 ASSERT_LE(1u, dispatch_event_log_events_.size()); 127 128 EXPECT_EQ(kExtensionId, dispatch_event_log_targets_[0]); 129 EXPECT_EQ(api::file_system::OnEntryChanged::kEventName, 130 dispatch_event_log_events_[0]->event_name); 131 132 ASSERT_LE(2u, dispatch_event_log_targets_.size()); 133 ASSERT_LE(2u, dispatch_event_log_events_.size()); 134 EXPECT_EQ(kExtensionId, dispatch_event_log_targets_[1]); 135 EXPECT_EQ(api::file_system::OnEntryRemoved::kEventName, 136 dispatch_event_log_events_[1]->event_name); 137 138 // No unexpected events. 139 ASSERT_EQ(2u, dispatch_event_log_targets_.size()); 140 ASSERT_EQ(2u, dispatch_event_log_events_.size()); 141 142 const std::vector<storage::FileSystemURL> watched_entries = 143 service_->GetWatchedEntries(kExtensionId); 144 ASSERT_EQ(1u, watched_entries.size()); 145 EXPECT_EQ(testing_url_, watched_entries[0]); 146} 147 148TEST_F(EntryWatcherServiceTest, WatchDirectory_AlreadyExists) { 149 std::vector<base::File::Error> log; 150 151 const bool recursive = false; 152 service_->WatchDirectory( 153 kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log)); 154 base::RunLoop().RunUntilIdle(); 155 156 ASSERT_EQ(1u, log.size()); 157 EXPECT_EQ(base::File::FILE_OK, log[0]); 158 159 ASSERT_EQ(2u, dispatch_event_log_targets_.size()); 160 ASSERT_EQ(2u, dispatch_event_log_events_.size()); 161 162 { 163 const std::vector<storage::FileSystemURL> watched_entries = 164 service_->GetWatchedEntries(kExtensionId); 165 EXPECT_EQ(1u, watched_entries.size()); 166 } 167 168 service_->WatchDirectory( 169 kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log)); 170 base::RunLoop().RunUntilIdle(); 171 172 ASSERT_EQ(2u, log.size()); 173 EXPECT_EQ(base::File::FILE_ERROR_EXISTS, log[1]); 174 175 // No new unexpected events. 176 ASSERT_EQ(2u, dispatch_event_log_targets_.size()); 177 ASSERT_EQ(2u, dispatch_event_log_events_.size()); 178 179 { 180 const std::vector<storage::FileSystemURL> watched_entries = 181 service_->GetWatchedEntries(kExtensionId); 182 EXPECT_EQ(1u, watched_entries.size()); 183 } 184} 185 186TEST_F(EntryWatcherServiceTest, WatchDirectory_Recursive) { 187 std::vector<base::File::Error> log; 188 189 const bool recursive = true; 190 service_->WatchDirectory( 191 kExtensionId, testing_url_, recursive, base::Bind(&LogStatus, &log)); 192 base::RunLoop().RunUntilIdle(); 193 194 // Recursive watchers are not supported yet. 195 ASSERT_EQ(1u, log.size()); 196 EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, log[0]); 197 198 // No unexpected events. 199 ASSERT_EQ(0u, dispatch_event_log_targets_.size()); 200 ASSERT_EQ(0u, dispatch_event_log_events_.size()); 201 202 const std::vector<storage::FileSystemURL> watched_entries = 203 service_->GetWatchedEntries(kExtensionId); 204 EXPECT_EQ(0u, watched_entries.size()); 205} 206 207TEST_F(EntryWatcherServiceTest, UnwatchEntry) { 208 std::vector<base::File::Error> watch_log; 209 210 const bool recursive = false; 211 service_->WatchDirectory(kExtensionId, 212 testing_url_, 213 recursive, 214 base::Bind(&LogStatus, &watch_log)); 215 base::RunLoop().RunUntilIdle(); 216 217 ASSERT_EQ(1u, watch_log.size()); 218 EXPECT_EQ(base::File::FILE_OK, watch_log[0]); 219 220 ASSERT_EQ(2u, dispatch_event_log_targets_.size()); 221 ASSERT_EQ(2u, dispatch_event_log_events_.size()); 222 223 { 224 const std::vector<storage::FileSystemURL> watched_entries = 225 service_->GetWatchedEntries(kExtensionId); 226 EXPECT_EQ(1u, watched_entries.size()); 227 } 228 229 std::vector<base::File::Error> unwatch_log; 230 service_->UnwatchEntry( 231 kExtensionId, testing_url_, base::Bind(&LogStatus, &unwatch_log)); 232 base::RunLoop().RunUntilIdle(); 233 234 ASSERT_EQ(1u, unwatch_log.size()); 235 EXPECT_EQ(base::File::FILE_OK, unwatch_log[0]); 236 237 { 238 const std::vector<storage::FileSystemURL> watched_entries = 239 service_->GetWatchedEntries(kExtensionId); 240 EXPECT_EQ(0u, watched_entries.size()); 241 } 242} 243 244TEST_F(EntryWatcherServiceTest, UnwatchEntry_NotFound) { 245 std::vector<base::File::Error> log; 246 service_->UnwatchEntry( 247 kExtensionId, testing_url_, base::Bind(&LogStatus, &log)); 248 base::RunLoop().RunUntilIdle(); 249 250 ASSERT_EQ(1u, log.size()); 251 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, log[0]); 252} 253 254} // namespace extensions 255