Roll src/third_party/WebKit 8b42d1d:744641d (svn 186770:186771)
[chromium-blink-merge.git] / chrome / browser / chromeos / file_system_provider / provided_file_system_unittest.cc
blob649e1ac68fa042faf6ac59443de8649285e796d7
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[] = "/hello/world";
45 // Fake implementation of the event router, mocking out a real extension.
46 // Handles requests and replies with fake answers back to the file system via
47 // the request manager.
48 class FakeEventRouter : public extensions::EventRouter {
49 public:
50 FakeEventRouter(Profile* profile, ProvidedFileSystemInterface* file_system)
51 : EventRouter(profile, NULL),
52 file_system_(file_system),
53 reply_result_(base::File::FILE_OK) {}
54 virtual ~FakeEventRouter() {}
56 // Handles an event which would normally be routed to an extension. Instead
57 // replies with a hard coded response.
58 virtual void DispatchEventToExtension(
59 const std::string& extension_id,
60 scoped_ptr<extensions::Event> event) override {
61 ASSERT_TRUE(file_system_);
62 std::string file_system_id;
63 const base::DictionaryValue* dictionary_value = NULL;
64 ASSERT_TRUE(event->event_args->GetDictionary(0, &dictionary_value));
65 EXPECT_TRUE(dictionary_value->GetString("fileSystemId", &file_system_id));
66 EXPECT_EQ(kFileSystemId, file_system_id);
67 int request_id = -1;
68 EXPECT_TRUE(dictionary_value->GetInteger("requestId", &request_id));
69 EXPECT_TRUE(event->event_name == extensions::api::file_system_provider::
70 OnAddWatcherRequested::kEventName ||
71 event->event_name == extensions::api::file_system_provider::
72 OnRemoveWatcherRequested::kEventName);
74 if (reply_result_ == base::File::FILE_OK) {
75 base::ListValue value_as_list;
76 value_as_list.Set(0, new base::StringValue(kFileSystemId));
77 value_as_list.Set(1, new base::FundamentalValue(request_id));
78 value_as_list.Set(2, new base::FundamentalValue(0) /* execution_time */);
80 using extensions::api::file_system_provider_internal::
81 OperationRequestedSuccess::Params;
82 scoped_ptr<Params> params(Params::Create(value_as_list));
83 ASSERT_TRUE(params.get());
84 file_system_->GetRequestManager()->FulfillRequest(
85 request_id,
86 RequestValue::CreateForOperationSuccess(params.Pass()),
87 false /* has_more */);
88 } else {
89 file_system_->GetRequestManager()->RejectRequest(
90 request_id, make_scoped_ptr(new RequestValue()), reply_result_);
94 void set_reply_result(base::File::Error result) { reply_result_ = result; }
96 private:
97 ProvidedFileSystemInterface* const file_system_; // Not owned.
98 base::File::Error reply_result_;
99 DISALLOW_COPY_AND_ASSIGN(FakeEventRouter);
102 // Observes the tested file system.
103 class Observer : public ProvidedFileSystemObserver {
104 public:
105 class ChangeEvent {
106 public:
107 ChangeEvent(storage::WatcherManager::ChangeType change_type,
108 const ProvidedFileSystemObserver::Changes& changes)
109 : change_type_(change_type), changes_(changes) {}
110 virtual ~ChangeEvent() {}
112 storage::WatcherManager::ChangeType change_type() const {
113 return change_type_;
115 const ProvidedFileSystemObserver::Changes& changes() const {
116 return changes_;
119 private:
120 const storage::WatcherManager::ChangeType change_type_;
121 const ProvidedFileSystemObserver::Changes changes_;
123 DISALLOW_COPY_AND_ASSIGN(ChangeEvent);
126 Observer() : list_changed_counter_(0), tag_updated_counter_(0) {}
128 // ProvidedFileSystemInterfaceObserver overrides.
129 virtual void OnWatcherChanged(
130 const ProvidedFileSystemInfo& file_system_info,
131 const Watcher& watcher,
132 storage::WatcherManager::ChangeType change_type,
133 const ProvidedFileSystemObserver::Changes& changes,
134 const base::Closure& callback) override {
135 EXPECT_EQ(kFileSystemId, file_system_info.file_system_id());
136 change_events_.push_back(new ChangeEvent(change_type, changes));
137 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
140 virtual void OnWatcherTagUpdated(
141 const ProvidedFileSystemInfo& file_system_info,
142 const Watcher& watcher) override {
143 EXPECT_EQ(kFileSystemId, file_system_info.file_system_id());
144 ++tag_updated_counter_;
147 virtual void OnWatcherListChanged(
148 const ProvidedFileSystemInfo& file_system_info,
149 const Watchers& watchers) override {
150 EXPECT_EQ(kFileSystemId, file_system_info.file_system_id());
151 ++list_changed_counter_;
154 int list_changed_counter() const { return list_changed_counter_; }
155 const ScopedVector<ChangeEvent>& change_events() const {
156 return change_events_;
158 int tag_updated_counter() const { return tag_updated_counter_; }
160 private:
161 ScopedVector<ChangeEvent> change_events_;
162 int list_changed_counter_;
163 int tag_updated_counter_;
165 DISALLOW_COPY_AND_ASSIGN(Observer);
168 // Stub notification manager, which works in unit tests.
169 class StubNotificationManager : public NotificationManagerInterface {
170 public:
171 StubNotificationManager() {}
172 virtual ~StubNotificationManager() {}
174 // NotificationManagerInterface overrides.
175 virtual void ShowUnresponsiveNotification(
176 int id,
177 const NotificationCallback& callback) override {}
178 virtual void HideUnresponsiveNotification(int id) override {}
180 private:
181 DISALLOW_COPY_AND_ASSIGN(StubNotificationManager);
184 typedef std::vector<base::File::Error> Log;
185 typedef std::vector<storage::WatcherManager::ChangeType> NotificationLog;
187 // Writes a |result| to the |log| vector.
188 void LogStatus(Log* log, base::File::Error result) {
189 log->push_back(result);
192 // Writes an |change_type| to the |notification_log| vector.
193 void LogNotification(NotificationLog* notification_log,
194 storage::WatcherManager::ChangeType change_type) {
195 notification_log->push_back(change_type);
198 } // namespace
200 class FileSystemProviderProvidedFileSystemTest : public testing::Test {
201 protected:
202 FileSystemProviderProvidedFileSystemTest() {}
203 virtual ~FileSystemProviderProvidedFileSystemTest() {}
205 virtual void SetUp() override {
206 profile_.reset(new TestingProfile);
207 const base::FilePath mount_path =
208 util::GetMountPath(profile_.get(), kExtensionId, kFileSystemId);
209 MountOptions mount_options;
210 mount_options.file_system_id = kFileSystemId;
211 mount_options.display_name = kDisplayName;
212 mount_options.supports_notify_tag = true;
213 file_system_info_.reset(
214 new ProvidedFileSystemInfo(kExtensionId, mount_options, mount_path));
215 provided_file_system_.reset(
216 new ProvidedFileSystem(profile_.get(), *file_system_info_.get()));
217 event_router_.reset(
218 new FakeEventRouter(profile_.get(), provided_file_system_.get()));
219 event_router_->AddEventListener(extensions::api::file_system_provider::
220 OnAddWatcherRequested::kEventName,
221 NULL,
222 kExtensionId);
223 event_router_->AddEventListener(extensions::api::file_system_provider::
224 OnRemoveWatcherRequested::kEventName,
225 NULL,
226 kExtensionId);
227 provided_file_system_->SetEventRouterForTesting(event_router_.get());
228 provided_file_system_->SetNotificationManagerForTesting(
229 make_scoped_ptr(new StubNotificationManager));
232 content::TestBrowserThreadBundle thread_bundle_;
233 scoped_ptr<TestingProfile> profile_;
234 scoped_ptr<FakeEventRouter> event_router_;
235 scoped_ptr<ProvidedFileSystemInfo> file_system_info_;
236 scoped_ptr<ProvidedFileSystem> provided_file_system_;
239 TEST_F(FileSystemProviderProvidedFileSystemTest, AutoUpdater) {
240 Log log;
241 base::Closure firstCallback;
242 base::Closure secondCallback;
245 // Auto updater is ref counted, and bound to all callbacks.
246 scoped_refptr<AutoUpdater> auto_updater(new AutoUpdater(
247 base::Bind(&LogStatus, base::Unretained(&log), base::File::FILE_OK)));
249 firstCallback = auto_updater->CreateCallback();
250 secondCallback = auto_updater->CreateCallback();
253 // Getting out of scope, should not invoke updating if there are pending
254 // callbacks.
255 EXPECT_EQ(0u, log.size());
257 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, firstCallback);
258 base::RunLoop().RunUntilIdle();
259 EXPECT_EQ(0u, log.size());
261 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, secondCallback);
262 base::RunLoop().RunUntilIdle();
263 EXPECT_EQ(1u, log.size());
266 TEST_F(FileSystemProviderProvidedFileSystemTest, AutoUpdater_NoCallbacks) {
267 Log log;
269 scoped_refptr<AutoUpdater> auto_updater(new AutoUpdater(
270 base::Bind(&LogStatus, base::Unretained(&log), base::File::FILE_OK)));
272 EXPECT_EQ(1u, log.size());
275 TEST_F(FileSystemProviderProvidedFileSystemTest, AutoUpdater_CallbackIgnored) {
276 Log log;
278 scoped_refptr<AutoUpdater> auto_updater(new AutoUpdater(
279 base::Bind(&LogStatus, base::Unretained(&log), base::File::FILE_OK)));
280 base::Closure callback = auto_updater->CreateCallback();
281 // The callback gets out of scope, so the ref counted auto updater instance
282 // gets deleted. Still, updating shouldn't be invoked, since the callback
283 // wasn't executed.
285 base::RunLoop().RunUntilIdle();
286 EXPECT_EQ(0u, log.size());
289 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher_NotFound) {
290 Log log;
291 NotificationLog notification_log;
292 Observer observer;
294 provided_file_system_->AddObserver(&observer);
296 // First, set the extension response to an error.
297 event_router_->set_reply_result(base::File::FILE_ERROR_NOT_FOUND);
299 provided_file_system_->AddWatcher(
300 GURL(kOrigin),
301 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
302 false /* recursive */,
303 false /* persistent */,
304 base::Bind(&LogStatus, base::Unretained(&log)),
305 base::Bind(&LogNotification, base::Unretained(&notification_log)));
306 base::RunLoop().RunUntilIdle();
308 // The directory should not become watched because of an error.
309 ASSERT_EQ(1u, log.size());
310 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, log[0]);
311 EXPECT_EQ(0u, notification_log.size());
313 Watchers* const watchers = provided_file_system_->GetWatchers();
314 EXPECT_EQ(0u, watchers->size());
316 // The observer should not be called.
317 EXPECT_EQ(0, observer.list_changed_counter());
318 EXPECT_EQ(0, observer.tag_updated_counter());
320 provided_file_system_->RemoveObserver(&observer);
323 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher) {
324 Log log;
325 Observer observer;
327 provided_file_system_->AddObserver(&observer);
329 provided_file_system_->AddWatcher(
330 GURL(kOrigin),
331 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
332 false /* recursive */,
333 true /* persistent */,
334 base::Bind(&LogStatus, base::Unretained(&log)),
335 storage::WatcherManager::NotificationCallback());
336 base::RunLoop().RunUntilIdle();
338 ASSERT_EQ(1u, log.size());
339 EXPECT_EQ(base::File::FILE_OK, log[0]);
340 EXPECT_EQ(1, observer.list_changed_counter());
341 EXPECT_EQ(0, observer.tag_updated_counter());
343 Watchers* const watchers = provided_file_system_->GetWatchers();
344 ASSERT_EQ(1u, watchers->size());
345 const Watcher& watcher = watchers->begin()->second;
346 EXPECT_EQ(FILE_PATH_LITERAL(kDirectoryPath), watcher.entry_path.value());
347 EXPECT_FALSE(watcher.recursive);
348 EXPECT_EQ("", watcher.last_tag);
350 provided_file_system_->RemoveObserver(&observer);
353 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher_PersistentIllegal) {
355 // Adding a persistent watcher with a notification callback is not allowed,
356 // as it's basically impossible to restore the callback after a shutdown.
357 Log log;
358 NotificationLog notification_log;
360 Observer observer;
361 provided_file_system_->AddObserver(&observer);
363 provided_file_system_->AddWatcher(
364 GURL(kOrigin),
365 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
366 false /* recursive */,
367 true /* persistent */,
368 base::Bind(&LogStatus, base::Unretained(&log)),
369 base::Bind(&LogNotification, base::Unretained(&notification_log)));
370 base::RunLoop().RunUntilIdle();
372 ASSERT_EQ(1u, log.size());
373 EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, log[0]);
374 EXPECT_EQ(0, observer.list_changed_counter());
375 EXPECT_EQ(0, observer.tag_updated_counter());
377 provided_file_system_->RemoveObserver(&observer);
381 // Adding a persistent watcher is not allowed if the file system doesn't
382 // support the notify tag. It's because the notify tag is essential to be
383 // able to recreate notification during shutdown.
384 Log log;
385 Observer observer;
387 // Create a provided file system interface, which does not support a notify
388 // tag, though.
389 const base::FilePath mount_path =
390 util::GetMountPath(profile_.get(), kExtensionId, kFileSystemId);
391 MountOptions mount_options;
392 mount_options.file_system_id = kFileSystemId;
393 mount_options.display_name = kDisplayName;
394 mount_options.supports_notify_tag = false;
395 ProvidedFileSystemInfo file_system_info(
396 kExtensionId, mount_options, mount_path);
397 ProvidedFileSystem simple_provided_file_system(profile_.get(),
398 file_system_info);
399 simple_provided_file_system.SetEventRouterForTesting(event_router_.get());
400 simple_provided_file_system.SetNotificationManagerForTesting(
401 make_scoped_ptr(new StubNotificationManager));
403 simple_provided_file_system.AddObserver(&observer);
405 simple_provided_file_system.AddWatcher(
406 GURL(kOrigin),
407 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
408 false /* recursive */,
409 true /* persistent */,
410 base::Bind(&LogStatus, base::Unretained(&log)),
411 storage::WatcherManager::NotificationCallback());
412 base::RunLoop().RunUntilIdle();
414 ASSERT_EQ(1u, log.size());
415 EXPECT_EQ(base::File::FILE_ERROR_INVALID_OPERATION, log[0]);
416 EXPECT_EQ(0, observer.list_changed_counter());
417 EXPECT_EQ(0, observer.tag_updated_counter());
419 simple_provided_file_system.RemoveObserver(&observer);
423 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher_Exists) {
424 Observer observer;
425 provided_file_system_->AddObserver(&observer);
428 // First watch a directory not recursively.
429 Log log;
430 provided_file_system_->AddWatcher(
431 GURL(kOrigin),
432 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
433 false /* recursive */,
434 true /* persistent */,
435 base::Bind(&LogStatus, base::Unretained(&log)),
436 storage::WatcherManager::NotificationCallback());
437 base::RunLoop().RunUntilIdle();
439 ASSERT_EQ(1u, log.size());
440 EXPECT_EQ(base::File::FILE_OK, log[0]);
441 EXPECT_EQ(1, observer.list_changed_counter());
442 EXPECT_EQ(0, observer.tag_updated_counter());
444 Watchers* const watchers = provided_file_system_->GetWatchers();
445 ASSERT_TRUE(watchers);
446 ASSERT_EQ(1u, watchers->size());
447 const auto& watcher_it = watchers->find(
448 WatcherKey(base::FilePath(FILE_PATH_LITERAL(kDirectoryPath)),
449 false /* recursive */));
450 ASSERT_NE(watchers->end(), watcher_it);
452 EXPECT_EQ(1u, watcher_it->second.subscribers.size());
453 const auto& subscriber_it =
454 watcher_it->second.subscribers.find(GURL(kOrigin));
455 ASSERT_NE(watcher_it->second.subscribers.end(), subscriber_it);
456 EXPECT_EQ(kOrigin, subscriber_it->second.origin.spec());
457 EXPECT_TRUE(subscriber_it->second.persistent);
461 // Create another non-recursive observer. That should fail.
462 Log log;
463 provided_file_system_->AddWatcher(
464 GURL(kOrigin),
465 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
466 false /* recursive */,
467 true /* persistent */,
468 base::Bind(&LogStatus, base::Unretained(&log)),
469 storage::WatcherManager::NotificationCallback());
470 base::RunLoop().RunUntilIdle();
472 ASSERT_EQ(1u, log.size());
473 EXPECT_EQ(base::File::FILE_ERROR_EXISTS, log[0]);
474 EXPECT_EQ(1, observer.list_changed_counter()); // No changes on the list.
475 EXPECT_EQ(0, observer.tag_updated_counter());
479 // Lastly, create another recursive observer. That should succeed.
480 Log log;
481 provided_file_system_->AddWatcher(
482 GURL(kOrigin),
483 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
484 true /* recursive */,
485 true /* persistent */,
486 base::Bind(&LogStatus, base::Unretained(&log)),
487 storage::WatcherManager::NotificationCallback());
488 base::RunLoop().RunUntilIdle();
490 ASSERT_EQ(1u, log.size());
491 EXPECT_EQ(base::File::FILE_OK, log[0]);
492 EXPECT_EQ(2, observer.list_changed_counter());
493 EXPECT_EQ(0, observer.tag_updated_counter());
496 provided_file_system_->RemoveObserver(&observer);
499 TEST_F(FileSystemProviderProvidedFileSystemTest, AddWatcher_MultipleOrigins) {
500 Observer observer;
501 provided_file_system_->AddObserver(&observer);
504 // First watch a directory not recursively.
505 Log log;
506 NotificationLog notification_log;
508 provided_file_system_->AddWatcher(
509 GURL(kOrigin),
510 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
511 false /* recursive */,
512 false /* persistent */,
513 base::Bind(&LogStatus, base::Unretained(&log)),
514 base::Bind(&LogNotification, base::Unretained(&notification_log)));
515 base::RunLoop().RunUntilIdle();
517 ASSERT_EQ(1u, log.size());
518 EXPECT_EQ(base::File::FILE_OK, log[0]);
519 EXPECT_EQ(1, observer.list_changed_counter());
520 EXPECT_EQ(0, observer.tag_updated_counter());
521 EXPECT_EQ(0u, notification_log.size());
523 Watchers* const watchers = provided_file_system_->GetWatchers();
524 ASSERT_TRUE(watchers);
525 ASSERT_EQ(1u, watchers->size());
526 const auto& watcher_it = watchers->find(
527 WatcherKey(base::FilePath(FILE_PATH_LITERAL(kDirectoryPath)),
528 false /* recursive */));
529 ASSERT_NE(watchers->end(), watcher_it);
531 EXPECT_EQ(1u, watcher_it->second.subscribers.size());
532 const auto& subscriber_it =
533 watcher_it->second.subscribers.find(GURL(kOrigin));
534 ASSERT_NE(watcher_it->second.subscribers.end(), subscriber_it);
535 EXPECT_EQ(kOrigin, subscriber_it->first.spec());
536 EXPECT_EQ(kOrigin, subscriber_it->second.origin.spec());
537 EXPECT_FALSE(subscriber_it->second.persistent);
541 // Create another watcher, but recursive and with a different origin.
542 Log log;
543 NotificationLog notification_log;
545 provided_file_system_->AddWatcher(
546 GURL(kAnotherOrigin),
547 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
548 true /* recursive */,
549 false /* persistent */,
550 base::Bind(&LogStatus, base::Unretained(&log)),
551 base::Bind(&LogNotification, base::Unretained(&notification_log)));
552 base::RunLoop().RunUntilIdle();
554 ASSERT_EQ(1u, log.size());
555 EXPECT_EQ(base::File::FILE_OK, log[0]);
556 EXPECT_EQ(2, observer.list_changed_counter());
557 EXPECT_EQ(0, observer.tag_updated_counter());
558 EXPECT_EQ(0u, notification_log.size());
560 Watchers* const watchers = provided_file_system_->GetWatchers();
561 ASSERT_TRUE(watchers);
562 ASSERT_EQ(2u, watchers->size());
563 const auto& watcher_it = watchers->find(
564 WatcherKey(base::FilePath(FILE_PATH_LITERAL(kDirectoryPath)),
565 false /* recursive */));
566 ASSERT_NE(watchers->end(), watcher_it);
568 EXPECT_EQ(1u, watcher_it->second.subscribers.size());
569 const auto& subscriber_it =
570 watcher_it->second.subscribers.find(GURL(kOrigin));
571 ASSERT_NE(watcher_it->second.subscribers.end(), subscriber_it);
572 EXPECT_EQ(kOrigin, subscriber_it->first.spec());
573 EXPECT_EQ(kOrigin, subscriber_it->second.origin.spec());
574 EXPECT_FALSE(subscriber_it->second.persistent);
578 // Remove the second watcher gracefully.
579 Log log;
580 provided_file_system_->RemoveWatcher(
581 GURL(kAnotherOrigin),
582 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
583 true /* recursive */,
584 base::Bind(&LogStatus, base::Unretained(&log)));
585 base::RunLoop().RunUntilIdle();
587 ASSERT_EQ(1u, log.size());
588 EXPECT_EQ(base::File::FILE_OK, log[0]);
589 EXPECT_EQ(3, observer.list_changed_counter());
590 EXPECT_EQ(0, observer.tag_updated_counter());
592 Watchers* const watchers = provided_file_system_->GetWatchers();
593 ASSERT_TRUE(watchers);
594 EXPECT_EQ(1u, watchers->size());
595 const auto& watcher_it = watchers->find(
596 WatcherKey(base::FilePath(FILE_PATH_LITERAL(kDirectoryPath)),
597 false /* recursive */));
598 ASSERT_NE(watchers->end(), watcher_it);
600 EXPECT_EQ(1u, watcher_it->second.subscribers.size());
601 const auto& subscriber_it =
602 watcher_it->second.subscribers.find(GURL(kOrigin));
603 ASSERT_NE(watcher_it->second.subscribers.end(), subscriber_it);
604 EXPECT_EQ(kOrigin, subscriber_it->first.spec());
605 EXPECT_EQ(kOrigin, subscriber_it->second.origin.spec());
606 EXPECT_FALSE(subscriber_it->second.persistent);
609 provided_file_system_->RemoveObserver(&observer);
612 TEST_F(FileSystemProviderProvidedFileSystemTest, RemoveWatcher) {
613 Observer observer;
614 provided_file_system_->AddObserver(&observer);
617 // First, confirm that removing a watcher which does not exist results in an
618 // error.
619 Log log;
620 provided_file_system_->RemoveWatcher(
621 GURL(kOrigin),
622 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
623 false /* recursive */,
624 base::Bind(&LogStatus, base::Unretained(&log)));
625 base::RunLoop().RunUntilIdle();
627 ASSERT_EQ(1u, log.size());
628 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, log[0]);
629 EXPECT_EQ(0, observer.list_changed_counter());
630 EXPECT_EQ(0, observer.tag_updated_counter());
634 // Watch a directory not recursively.
635 Log log;
636 NotificationLog notification_log;
638 provided_file_system_->AddWatcher(
639 GURL(kOrigin),
640 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
641 false /* recursive */,
642 false /* persistent */,
643 base::Bind(&LogStatus, base::Unretained(&log)),
644 base::Bind(&LogNotification, base::Unretained(&notification_log)));
645 base::RunLoop().RunUntilIdle();
647 ASSERT_EQ(1u, log.size());
648 EXPECT_EQ(base::File::FILE_OK, log[0]);
649 EXPECT_EQ(1, observer.list_changed_counter());
650 EXPECT_EQ(0, observer.tag_updated_counter());
651 EXPECT_EQ(0u, notification_log.size());
653 Watchers* const watchers = provided_file_system_->GetWatchers();
654 EXPECT_EQ(1u, watchers->size());
658 // Remove a watcher gracefully.
659 Log log;
660 provided_file_system_->RemoveWatcher(
661 GURL(kOrigin),
662 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
663 false /* recursive */,
664 base::Bind(&LogStatus, base::Unretained(&log)));
665 base::RunLoop().RunUntilIdle();
667 ASSERT_EQ(1u, log.size());
668 EXPECT_EQ(base::File::FILE_OK, log[0]);
669 EXPECT_EQ(2, observer.list_changed_counter());
670 EXPECT_EQ(0, observer.tag_updated_counter());
672 Watchers* const watchers = provided_file_system_->GetWatchers();
673 EXPECT_EQ(0u, watchers->size());
677 // Confirm that it's possible to watch it again.
678 Log log;
679 NotificationLog notification_log;
681 provided_file_system_->AddWatcher(
682 GURL(kOrigin),
683 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
684 false /* recursive */,
685 false /* persistent */,
686 base::Bind(&LogStatus, base::Unretained(&log)),
687 base::Bind(&LogNotification, base::Unretained(&notification_log)));
688 base::RunLoop().RunUntilIdle();
690 ASSERT_EQ(1u, log.size());
691 EXPECT_EQ(base::File::FILE_OK, log[0]);
692 EXPECT_EQ(3, observer.list_changed_counter());
693 EXPECT_EQ(0, observer.tag_updated_counter());
694 EXPECT_EQ(0u, notification_log.size());
696 Watchers* const watchers = provided_file_system_->GetWatchers();
697 EXPECT_EQ(1u, watchers->size());
701 // Finally, remove it, but with an error from extension. That should result
702 // in a removed watcher, anyway. The error code should not be passed.
703 event_router_->set_reply_result(base::File::FILE_ERROR_FAILED);
705 Log log;
706 provided_file_system_->RemoveWatcher(
707 GURL(kOrigin),
708 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
709 false /* recursive */,
710 base::Bind(&LogStatus, base::Unretained(&log)));
711 base::RunLoop().RunUntilIdle();
713 ASSERT_EQ(1u, log.size());
714 EXPECT_EQ(base::File::FILE_OK, log[0]);
715 EXPECT_EQ(4, observer.list_changed_counter());
716 EXPECT_EQ(0, observer.tag_updated_counter());
718 Watchers* const watchers = provided_file_system_->GetWatchers();
719 EXPECT_EQ(0u, watchers->size());
722 provided_file_system_->RemoveObserver(&observer);
725 TEST_F(FileSystemProviderProvidedFileSystemTest, Notify) {
726 Observer observer;
727 provided_file_system_->AddObserver(&observer);
728 NotificationLog notification_log;
731 // Watch a directory.
732 Log log;
734 provided_file_system_->AddWatcher(
735 GURL(kOrigin),
736 base::FilePath::FromUTF8Unsafe(kDirectoryPath),
737 false /* recursive */,
738 false /* persistent */,
739 base::Bind(&LogStatus, base::Unretained(&log)),
740 base::Bind(&LogNotification, base::Unretained(&notification_log)));
741 base::RunLoop().RunUntilIdle();
743 ASSERT_EQ(1u, log.size());
744 EXPECT_EQ(base::File::FILE_OK, log[0]);
745 EXPECT_EQ(1, observer.list_changed_counter());
746 EXPECT_EQ(0, observer.tag_updated_counter());
747 EXPECT_EQ(0u, notification_log.size());
749 Watchers* const watchers = provided_file_system_->GetWatchers();
750 EXPECT_EQ(1u, watchers->size());
751 provided_file_system_->GetWatchers();
752 EXPECT_EQ("", watchers->begin()->second.last_tag);
756 // Notify about a change.
757 const storage::WatcherManager::ChangeType change_type =
758 storage::WatcherManager::CHANGED;
759 const std::string tag = "hello-world";
761 Log log;
762 provided_file_system_->Notify(
763 base::FilePath::FromUTF8Unsafe(kDirectoryPath), false /* recursive */,
764 change_type, make_scoped_ptr(new ProvidedFileSystemObserver::Changes),
765 tag, base::Bind(&LogStatus, base::Unretained(&log)));
767 // Confirm that the notification callback was called.
768 ASSERT_EQ(1u, notification_log.size());
769 EXPECT_EQ(change_type, notification_log[0]);
771 // Verify the observer event.
772 ASSERT_EQ(1u, observer.change_events().size());
773 const Observer::ChangeEvent* const change_event =
774 observer.change_events()[0];
775 EXPECT_EQ(change_type, change_event->change_type());
776 EXPECT_EQ(0u, change_event->changes().size());
778 // The tag should not be updated in advance, before all observers handle
779 // the notification.
780 Watchers* const watchers = provided_file_system_->GetWatchers();
781 EXPECT_EQ(1u, watchers->size());
782 provided_file_system_->GetWatchers();
783 EXPECT_EQ("", watchers->begin()->second.last_tag);
785 // Wait until all observers finish handling the notification.
786 base::RunLoop().RunUntilIdle();
788 ASSERT_EQ(1u, log.size());
789 EXPECT_EQ(base::File::FILE_OK, log[0]);
791 // Confirm, that the watcher still exists, and that the tag is updated.
792 ASSERT_EQ(1u, watchers->size());
793 EXPECT_EQ(tag, watchers->begin()->second.last_tag);
794 EXPECT_EQ(1, observer.list_changed_counter());
795 EXPECT_EQ(1, observer.tag_updated_counter());
799 // Notify about deleting of the watched entry.
800 const storage::WatcherManager::ChangeType change_type =
801 storage::WatcherManager::DELETED;
802 const ProvidedFileSystemObserver::Changes changes;
803 const std::string tag = "chocolate-disco";
805 Log log;
806 provided_file_system_->Notify(
807 base::FilePath::FromUTF8Unsafe(kDirectoryPath), false /* recursive */,
808 change_type, make_scoped_ptr(new ProvidedFileSystemObserver::Changes),
809 tag, base::Bind(&LogStatus, base::Unretained(&log)));
810 base::RunLoop().RunUntilIdle();
811 ASSERT_EQ(1u, log.size());
812 EXPECT_EQ(base::File::FILE_OK, log[0]);
814 // Confirm that the notification callback was called.
815 ASSERT_EQ(2u, notification_log.size());
816 EXPECT_EQ(change_type, notification_log[1]);
818 // Verify the observer event.
819 ASSERT_EQ(2u, observer.change_events().size());
820 const Observer::ChangeEvent* const change_event =
821 observer.change_events()[1];
822 EXPECT_EQ(change_type, change_event->change_type());
823 EXPECT_EQ(0u, change_event->changes().size());
826 // Confirm, that the watcher is removed.
828 Watchers* const watchers = provided_file_system_->GetWatchers();
829 EXPECT_EQ(0u, watchers->size());
830 EXPECT_EQ(2, observer.list_changed_counter());
831 EXPECT_EQ(2, observer.tag_updated_counter());
834 provided_file_system_->RemoveObserver(&observer);
837 } // namespace file_system_provider
838 } // namespace chromeos