Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / chromeos / file_system_provider / provided_file_system_unittest.cc
blob3c1f14bf66327c627310ba926fdea0a678959559
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.
5 #include "chrome/browser/chromeos/file_system_provider/provided_file_system.h"
7 #include <string>
8 #include <vector>
10 #include "base/files/file.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/run_loop.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/values.h"
17 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
18 #include "chrome/browser/chromeos/file_system_provider/notification_manager.h"
19 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
20 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
21 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_observer.h"
22 #include "chrome/browser/chromeos/file_system_provider/request_manager.h"
23 #include "chrome/browser/chromeos/file_system_provider/watcher.h"
24 #include "chrome/common/extensions/api/file_system_provider.h"
25 #include "chrome/common/extensions/api/file_system_provider_internal.h"
26 #include "chrome/test/base/testing_profile.h"
27 #include "content/public/test/test_browser_thread_bundle.h"
28 #include "extensions/browser/event_router.h"
29 #include "storage/browser/fileapi/watcher_manager.h"
30 #include "testing/gtest/include/gtest/gtest.h"
32 namespace chromeos {
33 namespace file_system_provider {
34 namespace {
36 const char kOrigin[] =
37 "chrome-extension://abcabcabcabcabcabcabcabcabcabcabcabca/";
38 const char kAnotherOrigin[] =
39 "chrome-extension://efgefgefgefgefgefgefgefgefgefgefgefge/";
40 const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
41 const char kFileSystemId[] = "camera-pictures";
42 const char kDisplayName[] = "Camera Pictures";
43 const base::FilePath::CharType kDirectoryPath[] =
44 FILE_PATH_LITERAL("/hello/world");
45 const base::FilePath::CharType kFilePath[] =
46 FILE_PATH_LITERAL("/welcome/to/my/world");
48 // Fake implementation of the event router, mocking out a real extension.
49 // Handles requests and replies with fake answers back to the file system via
50 // the request manager.
51 class FakeEventRouter : public extensions::EventRouter {
52 public:
53 FakeEventRouter(Profile* profile, ProvidedFileSystemInterface* file_system)
54 : EventRouter(profile, NULL),
55 file_system_(file_system),
56 reply_result_(base::File::FILE_OK) {}
57 ~FakeEventRouter() override {}
59 // Handles an event which would normally be routed to an extension. Instead
60 // replies with a hard coded response.
61 void DispatchEventToExtension(const std::string& extension_id,
62 scoped_ptr<extensions::Event> event) override {
63 ASSERT_TRUE(file_system_);
64 std::string file_system_id;
65 const base::DictionaryValue* dictionary_value = NULL;
66 ASSERT_TRUE(event->event_args->GetDictionary(0, &dictionary_value));
67 EXPECT_TRUE(dictionary_value->GetString("fileSystemId", &file_system_id));
68 EXPECT_EQ(kFileSystemId, file_system_id);
69 int request_id = -1;
70 EXPECT_TRUE(dictionary_value->GetInteger("requestId", &request_id));
71 EXPECT_TRUE(event->event_name == extensions::api::file_system_provider::
72 OnAddWatcherRequested::kEventName ||
73 event->event_name == extensions::api::file_system_provider::
74 OnRemoveWatcherRequested::kEventName ||
75 event->event_name == extensions::api::file_system_provider::
76 OnOpenFileRequested::kEventName ||
77 event->event_name == extensions::api::file_system_provider::
78 OnCloseFileRequested::kEventName);
80 if (reply_result_ == base::File::FILE_OK) {
81 base::ListValue value_as_list;
82 value_as_list.Set(0, new base::StringValue(kFileSystemId));
83 value_as_list.Set(1, new base::FundamentalValue(request_id));
84 value_as_list.Set(2, new base::FundamentalValue(0) /* execution_time */);
86 using extensions::api::file_system_provider_internal::
87 OperationRequestedSuccess::Params;
88 scoped_ptr<Params> params(Params::Create(value_as_list));
89 ASSERT_TRUE(params.get());
90 file_system_->GetRequestManager()->FulfillRequest(
91 request_id,
92 RequestValue::CreateForOperationSuccess(params.Pass()),
93 false /* has_more */);
94 } else {
95 file_system_->GetRequestManager()->RejectRequest(
96 request_id, make_scoped_ptr(new RequestValue()), reply_result_);
100 void set_reply_result(base::File::Error result) { reply_result_ = result; }
102 private:
103 ProvidedFileSystemInterface* const file_system_; // Not owned.
104 base::File::Error reply_result_;
105 DISALLOW_COPY_AND_ASSIGN(FakeEventRouter);
108 // Observes the tested file system.
109 class Observer : public ProvidedFileSystemObserver {
110 public:
111 class ChangeEvent {
112 public:
113 ChangeEvent(storage::WatcherManager::ChangeType change_type,
114 const ProvidedFileSystemObserver::Changes& changes)
115 : change_type_(change_type), changes_(changes) {}
116 virtual ~ChangeEvent() {}
118 storage::WatcherManager::ChangeType change_type() const {
119 return change_type_;
121 const ProvidedFileSystemObserver::Changes& changes() const {
122 return changes_;
125 private:
126 const storage::WatcherManager::ChangeType change_type_;
127 const ProvidedFileSystemObserver::Changes changes_;
129 DISALLOW_COPY_AND_ASSIGN(ChangeEvent);
132 Observer() : list_changed_counter_(0), tag_updated_counter_(0) {}
134 // ProvidedFileSystemInterfaceObserver overrides.
135 void OnWatcherChanged(const ProvidedFileSystemInfo& file_system_info,
136 const Watcher& watcher,
137 storage::WatcherManager::ChangeType change_type,
138 const ProvidedFileSystemObserver::Changes& changes,
139 const base::Closure& callback) override {
140 EXPECT_EQ(kFileSystemId, file_system_info.file_system_id());
141 change_events_.push_back(new ChangeEvent(change_type, changes));
142 complete_callback_ = callback;
145 void OnWatcherTagUpdated(const ProvidedFileSystemInfo& file_system_info,
146 const Watcher& watcher) override {
147 EXPECT_EQ(kFileSystemId, file_system_info.file_system_id());
148 ++tag_updated_counter_;
151 void OnWatcherListChanged(const ProvidedFileSystemInfo& file_system_info,
152 const Watchers& watchers) override {
153 EXPECT_EQ(kFileSystemId, file_system_info.file_system_id());
154 ++list_changed_counter_;
157 // Completes handling the OnWatcherChanged event.
158 void CompleteOnWatcherChanged() {
159 DCHECK(!complete_callback_.is_null());
160 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
161 complete_callback_);
162 complete_callback_ = base::Closure();
165 int list_changed_counter() const { return list_changed_counter_; }
166 const ScopedVector<ChangeEvent>& change_events() const {
167 return change_events_;
169 int tag_updated_counter() const { return tag_updated_counter_; }
171 private:
172 ScopedVector<ChangeEvent> change_events_;
173 int list_changed_counter_;
174 int tag_updated_counter_;
175 base::Closure complete_callback_;
177 DISALLOW_COPY_AND_ASSIGN(Observer);
180 // Stub notification manager, which works in unit tests.
181 class StubNotificationManager : public NotificationManagerInterface {
182 public:
183 StubNotificationManager() {}
184 ~StubNotificationManager() override {}
186 // NotificationManagerInterface overrides.
187 void ShowUnresponsiveNotification(
188 int id,
189 const NotificationCallback& callback) override {}
190 void HideUnresponsiveNotification(int id) override {}
192 private:
193 DISALLOW_COPY_AND_ASSIGN(StubNotificationManager);
196 typedef std::vector<base::File::Error> Log;
197 typedef std::vector<storage::WatcherManager::ChangeType> NotificationLog;
198 typedef std::vector<std::pair<int, base::File::Error>> OpenFileLog;
200 // Writes a |result| to the |log| vector.
201 void LogStatus(Log* log, base::File::Error result) {
202 log->push_back(result);
205 // Writes a |change_type| to the |notification_log| vector.
206 void LogNotification(NotificationLog* notification_log,
207 storage::WatcherManager::ChangeType change_type) {
208 notification_log->push_back(change_type);
211 // Writes a |file_handle| and |result| to the |open_file_log| vector.
212 void LogOpenFile(OpenFileLog* open_file_log,
213 int file_handle,
214 base::File::Error result) {
215 open_file_log->push_back(std::make_pair(file_handle, result));
218 } // namespace
220 class FileSystemProviderProvidedFileSystemTest : public testing::Test {
221 protected:
222 FileSystemProviderProvidedFileSystemTest() {}
223 ~FileSystemProviderProvidedFileSystemTest() override {}
225 void SetUp() override {
226 profile_.reset(new TestingProfile);
227 const base::FilePath mount_path =
228 util::GetMountPath(profile_.get(), kExtensionId, kFileSystemId);
229 MountOptions mount_options;
230 mount_options.file_system_id = kFileSystemId;
231 mount_options.display_name = kDisplayName;
232 mount_options.supports_notify_tag = true;
233 mount_options.writable = true;
234 file_system_info_.reset(
235 new ProvidedFileSystemInfo(kExtensionId, mount_options, mount_path));
236 provided_file_system_.reset(
237 new ProvidedFileSystem(profile_.get(), *file_system_info_.get()));
238 event_router_.reset(
239 new FakeEventRouter(profile_.get(), provided_file_system_.get()));
240 event_router_->AddEventListener(extensions::api::file_system_provider::
241 OnAddWatcherRequested::kEventName,
242 NULL,
243 kExtensionId);
244 event_router_->AddEventListener(extensions::api::file_system_provider::
245 OnRemoveWatcherRequested::kEventName,
246 NULL,
247 kExtensionId);
248 event_router_->AddEventListener(
249 extensions::api::file_system_provider::OnOpenFileRequested::kEventName,
250 NULL, kExtensionId);
251 event_router_->AddEventListener(
252 extensions::api::file_system_provider::OnCloseFileRequested::kEventName,
253 NULL, kExtensionId);
254 provided_file_system_->SetEventRouterForTesting(event_router_.get());
255 provided_file_system_->SetNotificationManagerForTesting(
256 make_scoped_ptr(new StubNotificationManager));
259 content::TestBrowserThreadBundle thread_bundle_;
260 scoped_ptr<TestingProfile> profile_;
261 scoped_ptr<FakeEventRouter> event_router_;
262 scoped_ptr<ProvidedFileSystemInfo> file_system_info_;
263 scoped_ptr<ProvidedFileSystem> provided_file_system_;
266 TEST_F(FileSystemProviderProvidedFileSystemTest, AutoUpdater) {
267 Log log;
268 base::Closure firstCallback;
269 base::Closure secondCallback;
272 // Auto updater is ref counted, and bound to all callbacks.
273 scoped_refptr<AutoUpdater> auto_updater(new AutoUpdater(
274 base::Bind(&LogStatus, base::Unretained(&log), base::File::FILE_OK)));
276 firstCallback = auto_updater->CreateCallback();
277 secondCallback = auto_updater->CreateCallback();
280 // Getting out of scope, should not invoke updating if there are pending
281 // callbacks.
282 EXPECT_EQ(0u, log.size());
284 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, firstCallback);
285 base::RunLoop().RunUntilIdle();
286 EXPECT_EQ(0u, log.size());
288 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, secondCallback);
289 base::RunLoop().RunUntilIdle();
290 EXPECT_EQ(1u, log.size());
293 TEST_F(FileSystemProviderProvidedFileSystemTest, AutoUpdater_NoCallbacks) {
294 Log log;
296 scoped_refptr<AutoUpdater> auto_updater(new AutoUpdater(
297 base::Bind(&LogStatus, base::Unretained(&log), base::File::FILE_OK)));
299 EXPECT_EQ(1u, log.size());
302 TEST_F(FileSystemProviderProvidedFileSystemTest, AutoUpdater_CallbackIgnored) {
303 Log log;
305 scoped_refptr<AutoUpdater> auto_updater(new AutoUpdater(
306 base::Bind(&LogStatus, base::Unretained(&log), base::File::FILE_OK)));
307 base::Closure callback = auto_updater->CreateCallback();
308 // The callback gets out of scope, so the ref counted auto updater instance
309 // gets deleted. Still, updating shouldn't be invoked, since the callback
310 // wasn't executed.
312 base::RunLoop().RunUntilIdle();
313 EXPECT_EQ(0u, log.size());
316 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher_NotFound) {
317 Log log;
318 NotificationLog notification_log;
319 Observer observer;
321 provided_file_system_->AddObserver(&observer);
323 // First, set the extension response to an error.
324 event_router_->set_reply_result(base::File::FILE_ERROR_NOT_FOUND);
326 provided_file_system_->AddWatcher(
327 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
328 false /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
329 base::Bind(&LogNotification, base::Unretained(&notification_log)));
330 base::RunLoop().RunUntilIdle();
332 // The directory should not become watched because of an error.
333 ASSERT_EQ(1u, log.size());
334 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, log[0]);
335 EXPECT_EQ(0u, notification_log.size());
337 Watchers* const watchers = provided_file_system_->GetWatchers();
338 EXPECT_EQ(0u, watchers->size());
340 // The observer should not be called.
341 EXPECT_EQ(0, observer.list_changed_counter());
342 EXPECT_EQ(0, observer.tag_updated_counter());
344 provided_file_system_->RemoveObserver(&observer);
347 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher) {
348 Log log;
349 Observer observer;
351 provided_file_system_->AddObserver(&observer);
353 provided_file_system_->AddWatcher(
354 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
355 true /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
356 storage::WatcherManager::NotificationCallback());
357 base::RunLoop().RunUntilIdle();
359 ASSERT_EQ(1u, log.size());
360 EXPECT_EQ(base::File::FILE_OK, log[0]);
361 EXPECT_EQ(1, observer.list_changed_counter());
362 EXPECT_EQ(0, observer.tag_updated_counter());
364 Watchers* const watchers = provided_file_system_->GetWatchers();
365 ASSERT_EQ(1u, watchers->size());
366 const Watcher& watcher = watchers->begin()->second;
367 EXPECT_EQ(FILE_PATH_LITERAL(kDirectoryPath), watcher.entry_path.value());
368 EXPECT_FALSE(watcher.recursive);
369 EXPECT_EQ("", watcher.last_tag);
371 provided_file_system_->RemoveObserver(&observer);
374 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher_PersistentIllegal) {
376 // Adding a persistent watcher with a notification callback is not allowed,
377 // as it's basically impossible to restore the callback after a shutdown.
378 Log log;
379 NotificationLog notification_log;
381 Observer observer;
382 provided_file_system_->AddObserver(&observer);
384 provided_file_system_->AddWatcher(
385 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
386 true /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
387 base::Bind(&LogNotification, base::Unretained(&notification_log)));
388 base::RunLoop().RunUntilIdle();
390 ASSERT_EQ(1u, log.size());
391 EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, log[0]);
392 EXPECT_EQ(0, observer.list_changed_counter());
393 EXPECT_EQ(0, observer.tag_updated_counter());
395 provided_file_system_->RemoveObserver(&observer);
399 // Adding a persistent watcher is not allowed if the file system doesn't
400 // support the notify tag. It's because the notify tag is essential to be
401 // able to recreate notification during shutdown.
402 Log log;
403 Observer observer;
405 // Create a provided file system interface, which does not support a notify
406 // tag, though.
407 const base::FilePath mount_path =
408 util::GetMountPath(profile_.get(), kExtensionId, kFileSystemId);
409 MountOptions mount_options;
410 mount_options.file_system_id = kFileSystemId;
411 mount_options.display_name = kDisplayName;
412 mount_options.supports_notify_tag = false;
413 ProvidedFileSystemInfo file_system_info(
414 kExtensionId, mount_options, mount_path);
415 ProvidedFileSystem simple_provided_file_system(profile_.get(),
416 file_system_info);
417 simple_provided_file_system.SetEventRouterForTesting(event_router_.get());
418 simple_provided_file_system.SetNotificationManagerForTesting(
419 make_scoped_ptr(new StubNotificationManager));
421 simple_provided_file_system.AddObserver(&observer);
423 simple_provided_file_system.AddWatcher(
424 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
425 true /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
426 storage::WatcherManager::NotificationCallback());
427 base::RunLoop().RunUntilIdle();
429 ASSERT_EQ(1u, log.size());
430 EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, log[0]);
431 EXPECT_EQ(0, observer.list_changed_counter());
432 EXPECT_EQ(0, observer.tag_updated_counter());
434 simple_provided_file_system.RemoveObserver(&observer);
438 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher_Exists) {
439 Observer observer;
440 provided_file_system_->AddObserver(&observer);
443 // First watch a directory not recursively.
444 Log log;
445 provided_file_system_->AddWatcher(
446 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
447 true /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
448 storage::WatcherManager::NotificationCallback());
449 base::RunLoop().RunUntilIdle();
451 ASSERT_EQ(1u, log.size());
452 EXPECT_EQ(base::File::FILE_OK, log[0]);
453 EXPECT_EQ(1, observer.list_changed_counter());
454 EXPECT_EQ(0, observer.tag_updated_counter());
456 Watchers* const watchers = provided_file_system_->GetWatchers();
457 ASSERT_TRUE(watchers);
458 ASSERT_EQ(1u, watchers->size());
459 const auto& watcher_it = watchers->find(
460 WatcherKey(base::FilePath(FILE_PATH_LITERAL(kDirectoryPath)),
461 false /* recursive */));
462 ASSERT_NE(watchers->end(), watcher_it);
464 EXPECT_EQ(1u, watcher_it->second.subscribers.size());
465 const auto& subscriber_it =
466 watcher_it->second.subscribers.find(GURL(kOrigin));
467 ASSERT_NE(watcher_it->second.subscribers.end(), subscriber_it);
468 EXPECT_EQ(kOrigin, subscriber_it->second.origin.spec());
469 EXPECT_TRUE(subscriber_it->second.persistent);
473 // Create another non-recursive observer. That should fail.
474 Log log;
475 provided_file_system_->AddWatcher(
476 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
477 true /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
478 storage::WatcherManager::NotificationCallback());
479 base::RunLoop().RunUntilIdle();
481 ASSERT_EQ(1u, log.size());
482 EXPECT_EQ(base::File::FILE_ERROR_EXISTS, log[0]);
483 EXPECT_EQ(1, observer.list_changed_counter()); // No changes on the list.
484 EXPECT_EQ(0, observer.tag_updated_counter());
488 // Lastly, create another recursive observer. That should succeed.
489 Log log;
490 provided_file_system_->AddWatcher(
491 GURL(kOrigin), base::FilePath(kDirectoryPath), true /* recursive */,
492 true /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
493 storage::WatcherManager::NotificationCallback());
494 base::RunLoop().RunUntilIdle();
496 ASSERT_EQ(1u, log.size());
497 EXPECT_EQ(base::File::FILE_OK, log[0]);
498 EXPECT_EQ(2, observer.list_changed_counter());
499 EXPECT_EQ(0, observer.tag_updated_counter());
502 provided_file_system_->RemoveObserver(&observer);
505 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher_MultipleOrigins) {
506 Observer observer;
507 provided_file_system_->AddObserver(&observer);
510 // First watch a directory not recursively.
511 Log log;
512 NotificationLog notification_log;
514 provided_file_system_->AddWatcher(
515 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
516 false /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
517 base::Bind(&LogNotification, base::Unretained(&notification_log)));
518 base::RunLoop().RunUntilIdle();
520 ASSERT_EQ(1u, log.size());
521 EXPECT_EQ(base::File::FILE_OK, log[0]);
522 EXPECT_EQ(1, observer.list_changed_counter());
523 EXPECT_EQ(0, observer.tag_updated_counter());
524 EXPECT_EQ(0u, notification_log.size());
526 Watchers* const watchers = provided_file_system_->GetWatchers();
527 ASSERT_TRUE(watchers);
528 ASSERT_EQ(1u, watchers->size());
529 const auto& watcher_it = watchers->find(
530 WatcherKey(base::FilePath(FILE_PATH_LITERAL(kDirectoryPath)),
531 false /* recursive */));
532 ASSERT_NE(watchers->end(), watcher_it);
534 EXPECT_EQ(1u, watcher_it->second.subscribers.size());
535 const auto& subscriber_it =
536 watcher_it->second.subscribers.find(GURL(kOrigin));
537 ASSERT_NE(watcher_it->second.subscribers.end(), subscriber_it);
538 EXPECT_EQ(kOrigin, subscriber_it->first.spec());
539 EXPECT_EQ(kOrigin, subscriber_it->second.origin.spec());
540 EXPECT_FALSE(subscriber_it->second.persistent);
544 // Create another watcher, but recursive and with a different origin.
545 Log log;
546 NotificationLog notification_log;
548 provided_file_system_->AddWatcher(
549 GURL(kAnotherOrigin), base::FilePath(kDirectoryPath),
550 true /* recursive */, false /* persistent */,
551 base::Bind(&LogStatus, base::Unretained(&log)),
552 base::Bind(&LogNotification, base::Unretained(&notification_log)));
553 base::RunLoop().RunUntilIdle();
555 ASSERT_EQ(1u, log.size());
556 EXPECT_EQ(base::File::FILE_OK, log[0]);
557 EXPECT_EQ(2, observer.list_changed_counter());
558 EXPECT_EQ(0, observer.tag_updated_counter());
559 EXPECT_EQ(0u, notification_log.size());
561 Watchers* const watchers = provided_file_system_->GetWatchers();
562 ASSERT_TRUE(watchers);
563 ASSERT_EQ(2u, watchers->size());
564 const auto& watcher_it = watchers->find(
565 WatcherKey(base::FilePath(FILE_PATH_LITERAL(kDirectoryPath)),
566 false /* recursive */));
567 ASSERT_NE(watchers->end(), watcher_it);
569 EXPECT_EQ(1u, watcher_it->second.subscribers.size());
570 const auto& subscriber_it =
571 watcher_it->second.subscribers.find(GURL(kOrigin));
572 ASSERT_NE(watcher_it->second.subscribers.end(), subscriber_it);
573 EXPECT_EQ(kOrigin, subscriber_it->first.spec());
574 EXPECT_EQ(kOrigin, subscriber_it->second.origin.spec());
575 EXPECT_FALSE(subscriber_it->second.persistent);
579 // Remove the second watcher gracefully.
580 Log log;
581 provided_file_system_->RemoveWatcher(
582 GURL(kAnotherOrigin), base::FilePath(kDirectoryPath),
583 true /* recursive */, base::Bind(&LogStatus, base::Unretained(&log)));
584 base::RunLoop().RunUntilIdle();
586 ASSERT_EQ(1u, log.size());
587 EXPECT_EQ(base::File::FILE_OK, log[0]);
588 EXPECT_EQ(3, observer.list_changed_counter());
589 EXPECT_EQ(0, observer.tag_updated_counter());
591 Watchers* const watchers = provided_file_system_->GetWatchers();
592 ASSERT_TRUE(watchers);
593 EXPECT_EQ(1u, watchers->size());
594 const auto& watcher_it = watchers->find(
595 WatcherKey(base::FilePath(FILE_PATH_LITERAL(kDirectoryPath)),
596 false /* recursive */));
597 ASSERT_NE(watchers->end(), watcher_it);
599 EXPECT_EQ(1u, watcher_it->second.subscribers.size());
600 const auto& subscriber_it =
601 watcher_it->second.subscribers.find(GURL(kOrigin));
602 ASSERT_NE(watcher_it->second.subscribers.end(), subscriber_it);
603 EXPECT_EQ(kOrigin, subscriber_it->first.spec());
604 EXPECT_EQ(kOrigin, subscriber_it->second.origin.spec());
605 EXPECT_FALSE(subscriber_it->second.persistent);
608 provided_file_system_->RemoveObserver(&observer);
611 TEST_F(FileSystemProviderProvidedFileSystemTest, RemoveWatcher) {
612 Observer observer;
613 provided_file_system_->AddObserver(&observer);
616 // First, confirm that removing a watcher which does not exist results in an
617 // error.
618 Log log;
619 provided_file_system_->RemoveWatcher(
620 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
621 base::Bind(&LogStatus, base::Unretained(&log)));
622 base::RunLoop().RunUntilIdle();
624 ASSERT_EQ(1u, log.size());
625 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, log[0]);
626 EXPECT_EQ(0, observer.list_changed_counter());
627 EXPECT_EQ(0, observer.tag_updated_counter());
631 // Watch a directory not recursively.
632 Log log;
633 NotificationLog notification_log;
635 provided_file_system_->AddWatcher(
636 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
637 false /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
638 base::Bind(&LogNotification, base::Unretained(&notification_log)));
639 base::RunLoop().RunUntilIdle();
641 ASSERT_EQ(1u, log.size());
642 EXPECT_EQ(base::File::FILE_OK, log[0]);
643 EXPECT_EQ(1, observer.list_changed_counter());
644 EXPECT_EQ(0, observer.tag_updated_counter());
645 EXPECT_EQ(0u, notification_log.size());
647 Watchers* const watchers = provided_file_system_->GetWatchers();
648 EXPECT_EQ(1u, watchers->size());
652 // Remove a watcher gracefully.
653 Log log;
654 provided_file_system_->RemoveWatcher(
655 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
656 base::Bind(&LogStatus, base::Unretained(&log)));
657 base::RunLoop().RunUntilIdle();
659 ASSERT_EQ(1u, log.size());
660 EXPECT_EQ(base::File::FILE_OK, log[0]);
661 EXPECT_EQ(2, observer.list_changed_counter());
662 EXPECT_EQ(0, observer.tag_updated_counter());
664 Watchers* const watchers = provided_file_system_->GetWatchers();
665 EXPECT_EQ(0u, watchers->size());
669 // Confirm that it's possible to watch it again.
670 Log log;
671 NotificationLog notification_log;
673 provided_file_system_->AddWatcher(
674 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
675 false /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
676 base::Bind(&LogNotification, base::Unretained(&notification_log)));
677 base::RunLoop().RunUntilIdle();
679 ASSERT_EQ(1u, log.size());
680 EXPECT_EQ(base::File::FILE_OK, log[0]);
681 EXPECT_EQ(3, observer.list_changed_counter());
682 EXPECT_EQ(0, observer.tag_updated_counter());
683 EXPECT_EQ(0u, notification_log.size());
685 Watchers* const watchers = provided_file_system_->GetWatchers();
686 EXPECT_EQ(1u, watchers->size());
690 // Finally, remove it, but with an error from extension. That should result
691 // in a removed watcher, anyway. The error code should not be passed.
692 event_router_->set_reply_result(base::File::FILE_ERROR_FAILED);
694 Log log;
695 provided_file_system_->RemoveWatcher(
696 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
697 base::Bind(&LogStatus, base::Unretained(&log)));
698 base::RunLoop().RunUntilIdle();
700 ASSERT_EQ(1u, log.size());
701 EXPECT_EQ(base::File::FILE_OK, log[0]);
702 EXPECT_EQ(4, observer.list_changed_counter());
703 EXPECT_EQ(0, observer.tag_updated_counter());
705 Watchers* const watchers = provided_file_system_->GetWatchers();
706 EXPECT_EQ(0u, watchers->size());
709 provided_file_system_->RemoveObserver(&observer);
712 TEST_F(FileSystemProviderProvidedFileSystemTest, Notify) {
713 Observer observer;
714 provided_file_system_->AddObserver(&observer);
715 NotificationLog notification_log;
718 // Watch a directory.
719 Log log;
721 provided_file_system_->AddWatcher(
722 GURL(kOrigin), base::FilePath(kDirectoryPath), false /* recursive */,
723 false /* persistent */, base::Bind(&LogStatus, base::Unretained(&log)),
724 base::Bind(&LogNotification, base::Unretained(&notification_log)));
725 base::RunLoop().RunUntilIdle();
727 ASSERT_EQ(1u, log.size());
728 EXPECT_EQ(base::File::FILE_OK, log[0]);
729 EXPECT_EQ(1, observer.list_changed_counter());
730 EXPECT_EQ(0, observer.tag_updated_counter());
731 EXPECT_EQ(0u, notification_log.size());
733 Watchers* const watchers = provided_file_system_->GetWatchers();
734 EXPECT_EQ(1u, watchers->size());
735 provided_file_system_->GetWatchers();
736 EXPECT_EQ("", watchers->begin()->second.last_tag);
740 // Notify about a change.
741 const storage::WatcherManager::ChangeType change_type =
742 storage::WatcherManager::CHANGED;
743 const std::string tag = "hello-world";
745 Log log;
746 provided_file_system_->Notify(
747 base::FilePath(kDirectoryPath), false /* recursive */, change_type,
748 make_scoped_ptr(new ProvidedFileSystemObserver::Changes), tag,
749 base::Bind(&LogStatus, base::Unretained(&log)));
750 base::RunLoop().RunUntilIdle();
752 // Confirm that the notification callback was called.
753 ASSERT_EQ(1u, notification_log.size());
754 EXPECT_EQ(change_type, notification_log[0]);
756 // Verify the observer event.
757 ASSERT_EQ(1u, observer.change_events().size());
758 const Observer::ChangeEvent* const change_event =
759 observer.change_events()[0];
760 EXPECT_EQ(change_type, change_event->change_type());
761 EXPECT_EQ(0u, change_event->changes().size());
763 // The tag should not be updated in advance, before all observers handle
764 // the notification.
765 Watchers* const watchers = provided_file_system_->GetWatchers();
766 EXPECT_EQ(1u, watchers->size());
767 provided_file_system_->GetWatchers();
768 EXPECT_EQ("", watchers->begin()->second.last_tag);
770 // Wait until all observers finish handling the notification.
771 observer.CompleteOnWatcherChanged();
772 base::RunLoop().RunUntilIdle();
774 ASSERT_EQ(1u, log.size());
775 EXPECT_EQ(base::File::FILE_OK, log[0]);
777 // Confirm, that the watcher still exists, and that the tag is updated.
778 ASSERT_EQ(1u, watchers->size());
779 EXPECT_EQ(tag, watchers->begin()->second.last_tag);
780 EXPECT_EQ(1, observer.list_changed_counter());
781 EXPECT_EQ(1, observer.tag_updated_counter());
785 // Notify about deleting of the watched entry.
786 const storage::WatcherManager::ChangeType change_type =
787 storage::WatcherManager::DELETED;
788 const ProvidedFileSystemObserver::Changes changes;
789 const std::string tag = "chocolate-disco";
791 Log log;
792 provided_file_system_->Notify(
793 base::FilePath(kDirectoryPath), false /* recursive */, change_type,
794 make_scoped_ptr(new ProvidedFileSystemObserver::Changes), tag,
795 base::Bind(&LogStatus, base::Unretained(&log)));
796 base::RunLoop().RunUntilIdle();
798 // Complete all change events.
799 observer.CompleteOnWatcherChanged();
800 base::RunLoop().RunUntilIdle();
802 ASSERT_EQ(1u, log.size());
803 EXPECT_EQ(base::File::FILE_OK, log[0]);
805 // Confirm that the notification callback was called.
806 ASSERT_EQ(2u, notification_log.size());
807 EXPECT_EQ(change_type, notification_log[1]);
809 // Verify the observer event.
810 ASSERT_EQ(2u, observer.change_events().size());
811 const Observer::ChangeEvent* const change_event =
812 observer.change_events()[1];
813 EXPECT_EQ(change_type, change_event->change_type());
814 EXPECT_EQ(0u, change_event->changes().size());
817 // Confirm, that the watcher is removed.
819 Watchers* const watchers = provided_file_system_->GetWatchers();
820 EXPECT_EQ(0u, watchers->size());
821 EXPECT_EQ(2, observer.list_changed_counter());
822 EXPECT_EQ(2, observer.tag_updated_counter());
825 provided_file_system_->RemoveObserver(&observer);
828 TEST_F(FileSystemProviderProvidedFileSystemTest, OpenedFiles) {
829 Observer observer;
830 provided_file_system_->AddObserver(&observer);
832 OpenFileLog log;
833 provided_file_system_->OpenFile(
834 base::FilePath(kFilePath), OPEN_FILE_MODE_WRITE,
835 base::Bind(LogOpenFile, base::Unretained(&log)));
836 base::RunLoop().RunUntilIdle();
838 ASSERT_EQ(1u, log.size());
839 EXPECT_EQ(base::File::FILE_OK, log[0].second);
840 const int file_handle = log[0].first;
842 const OpenedFiles& opened_files = provided_file_system_->GetOpenedFiles();
843 const auto opened_file_it = opened_files.find(file_handle);
844 ASSERT_NE(opened_files.end(), opened_file_it);
845 EXPECT_EQ(kFilePath, opened_file_it->second.file_path.AsUTF8Unsafe());
846 EXPECT_EQ(OPEN_FILE_MODE_WRITE, opened_file_it->second.mode);
848 Log close_log;
849 provided_file_system_->CloseFile(
850 file_handle, base::Bind(LogStatus, base::Unretained(&close_log)));
851 base::RunLoop().RunUntilIdle();
853 ASSERT_EQ(1u, close_log.size());
854 EXPECT_EQ(base::File::FILE_OK, close_log[0]);
855 EXPECT_EQ(0u, opened_files.size());
857 provided_file_system_->RemoveObserver(&observer);
860 TEST_F(FileSystemProviderProvidedFileSystemTest, OpenedFiles_OpeningFailure) {
861 Observer observer;
862 provided_file_system_->AddObserver(&observer);
864 event_router_->set_reply_result(base::File::FILE_ERROR_NOT_FOUND);
866 OpenFileLog log;
867 provided_file_system_->OpenFile(
868 base::FilePath(kFilePath), OPEN_FILE_MODE_WRITE,
869 base::Bind(LogOpenFile, base::Unretained(&log)));
870 base::RunLoop().RunUntilIdle();
872 ASSERT_EQ(1u, log.size());
873 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, log[0].second);
875 const OpenedFiles& opened_files = provided_file_system_->GetOpenedFiles();
876 EXPECT_EQ(0u, opened_files.size());
878 provided_file_system_->RemoveObserver(&observer);
881 TEST_F(FileSystemProviderProvidedFileSystemTest, OpenedFile_ClosingFailure) {
882 Observer observer;
883 provided_file_system_->AddObserver(&observer);
885 OpenFileLog log;
886 provided_file_system_->OpenFile(
887 base::FilePath(kFilePath), OPEN_FILE_MODE_WRITE,
888 base::Bind(LogOpenFile, base::Unretained(&log)));
889 base::RunLoop().RunUntilIdle();
891 ASSERT_EQ(1u, log.size());
892 EXPECT_EQ(base::File::FILE_OK, log[0].second);
893 const int file_handle = log[0].first;
895 const OpenedFiles& opened_files = provided_file_system_->GetOpenedFiles();
896 const auto opened_file_it = opened_files.find(file_handle);
897 ASSERT_NE(opened_files.end(), opened_file_it);
898 EXPECT_EQ(kFilePath, opened_file_it->second.file_path.AsUTF8Unsafe());
899 EXPECT_EQ(OPEN_FILE_MODE_WRITE, opened_file_it->second.mode);
901 // Simulate an error for closing a file. Still, the file should be closed
902 // in the C++ layer, anyway.
903 event_router_->set_reply_result(base::File::FILE_ERROR_NOT_FOUND);
905 Log close_log;
906 provided_file_system_->CloseFile(
907 file_handle, base::Bind(LogStatus, base::Unretained(&close_log)));
908 base::RunLoop().RunUntilIdle();
910 ASSERT_EQ(1u, close_log.size());
911 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, close_log[0]);
912 EXPECT_EQ(0u, opened_files.size());
914 provided_file_system_->RemoveObserver(&observer);
917 } // namespace file_system_provider
918 } // namespace chromeos