Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3045)

Unified Diff: chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc

Issue 625463002: [fsp] Add support for observing entries and notifying about changes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
diff --git a/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc b/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6de4a91238d44f529338b5f329f35a0455f3753e
--- /dev/null
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
@@ -0,0 +1,611 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/file_system_provider/provided_file_system.h"
+
+#include <string>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
+#include "chrome/browser/chromeos/file_system_provider/notification_manager.h"
+#include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
+#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
+#include "chrome/browser/chromeos/file_system_provider/provided_file_system_observer.h"
+#include "chrome/browser/chromeos/file_system_provider/request_manager.h"
+#include "chrome/common/extensions/api/file_system_provider.h"
+#include "chrome/common/extensions/api/file_system_provider_internal.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/browser/event_router.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace file_system_provider {
+namespace {
+
+const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
+const char kFileSystemId[] = "camera-pictures";
+const char kDisplayName[] = "Camera Pictures";
+const base::FilePath::CharType kDirectoryPath[] = "/hello/world";
+
+// Fake implementation of the event router, mocking out a real extension.
+// Handles requests and replies with fake answers back to the file system via
+// the request manager.
+class FakeEventRouter : public extensions::EventRouter {
+ public:
+ FakeEventRouter(Profile* profile, ProvidedFileSystemInterface* file_system)
+ : EventRouter(profile, NULL),
+ file_system_(file_system),
+ reply_result_(base::File::FILE_OK) {}
+ virtual ~FakeEventRouter() {}
+
+ // Handles an event which would normally be routed to an extension. Instead
+ // replies with a hard coded response.
+ virtual void DispatchEventToExtension(
+ const std::string& extension_id,
+ scoped_ptr<extensions::Event> event) override {
+ ASSERT_TRUE(file_system_);
+ std::string file_system_id;
+ const base::DictionaryValue* dictionary_value = NULL;
+ ASSERT_TRUE(event->event_args->GetDictionary(0, &dictionary_value));
+ EXPECT_TRUE(dictionary_value->GetString("fileSystemId", &file_system_id));
+ EXPECT_EQ(kFileSystemId, file_system_id);
+ int request_id = -1;
+ EXPECT_TRUE(dictionary_value->GetInteger("requestId", &request_id));
+ EXPECT_TRUE(event->event_name ==
+ extensions::api::file_system_provider::
+ OnObserveDirectoryRequested::kEventName ||
+ event->event_name == extensions::api::file_system_provider::
+ OnUnobserveEntryRequested::kEventName);
+
+ if (reply_result_ == base::File::FILE_OK) {
+ base::ListValue value_as_list;
+ value_as_list.Set(0, new base::StringValue(kFileSystemId));
+ value_as_list.Set(1, new base::FundamentalValue(request_id));
+ value_as_list.Set(2, new base::FundamentalValue(0) /* execution_time */);
+
+ using extensions::api::file_system_provider_internal::
+ OperationRequestedSuccess::Params;
+ scoped_ptr<Params> params(Params::Create(value_as_list));
+ ASSERT_TRUE(params.get());
+ file_system_->GetRequestManager()->FulfillRequest(
+ request_id,
+ RequestValue::CreateForOperationSuccess(params.Pass()),
+ false /* has_more */);
+ } else {
+ file_system_->GetRequestManager()->RejectRequest(
+ request_id, make_scoped_ptr(new RequestValue()), reply_result_);
+ }
+ }
+
+ void set_reply_result(base::File::Error result) { reply_result_ = result; }
+
+ private:
+ ProvidedFileSystemInterface* const file_system_; // Not owned.
+ base::File::Error reply_result_;
+ DISALLOW_COPY_AND_ASSIGN(FakeEventRouter);
+};
+
+// Observes the tested file system.
+class Observer : public ProvidedFileSystemObserver {
+ public:
+ class ChangeEvent {
+ public:
+ ChangeEvent(ProvidedFileSystemObserver::ChangeType change_type,
+ const ProvidedFileSystemObserver::ChildChanges& child_changes)
+ : change_type_(change_type), child_changes_(child_changes) {}
+ virtual ~ChangeEvent() {}
+
+ ProvidedFileSystemObserver::ChangeType change_type() const {
+ return change_type_;
+ }
+ const ProvidedFileSystemObserver::ChildChanges& child_changes() const {
+ return child_changes_;
+ }
+
+ private:
+ const ProvidedFileSystemObserver::ChangeType change_type_;
+ const ProvidedFileSystemObserver::ChildChanges child_changes_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChangeEvent);
+ };
+
+ Observer() : list_changed_counter_(0), tag_updated_counter_(0) {}
+
+ // ProvidedFileSystemInterfaceObserver overrides.
+ virtual void OnObservedEntryChanged(
+ const ProvidedFileSystemInfo& file_system_info,
+ const base::FilePath& observed_path,
+ ProvidedFileSystemObserver::ChangeType change_type,
+ const ProvidedFileSystemObserver::ChildChanges& child_changes,
+ const base::Closure& callback) override {
+ EXPECT_EQ(kFileSystemId, file_system_info.file_system_id());
+ change_events_.push_back(new ChangeEvent(change_type, child_changes));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+ }
+
+ virtual void OnObservedEntryTagUpdated(
+ const ProvidedFileSystemInfo& file_system_info,
+ const base::FilePath& observed_path) override {
+ EXPECT_EQ(kFileSystemId, file_system_info.file_system_id());
+ ++tag_updated_counter_;
+ }
+
+ virtual void OnObservedEntryListChanged(
+ const ProvidedFileSystemInfo& file_system_info) override {
+ EXPECT_EQ(kFileSystemId, file_system_info.file_system_id());
+ ++list_changed_counter_;
+ }
+
+ int list_changed_counter() const { return list_changed_counter_; }
+ const ScopedVector<ChangeEvent>& change_events() const {
+ return change_events_;
+ }
+ int tag_updated_counter() const { return tag_updated_counter_; }
+
+ private:
+ ScopedVector<ChangeEvent> change_events_;
+ int list_changed_counter_;
+ int tag_updated_counter_;
+
+ DISALLOW_COPY_AND_ASSIGN(Observer);
+};
+
+// Stub notification manager, which works in unit tests.
+class StubNotificationManager : public NotificationManagerInterface {
+ public:
+ StubNotificationManager() {}
+ virtual ~StubNotificationManager() {}
+
+ // NotificationManagerInterface overrides.
+ virtual void ShowUnresponsiveNotification(
+ int id,
+ const NotificationCallback& callback) override {}
+ virtual void HideUnresponsiveNotification(int id) override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StubNotificationManager);
+};
+
+typedef std::vector<base::File::Error> Log;
+
+// Writes a |result| to the |log| vector.
+void LogStatus(Log* log, base::File::Error result) {
+ log->push_back(result);
+}
+
+} // namespace
+
+class FileSystemProviderProvidedFileSystemTest : public testing::Test {
+ protected:
+ FileSystemProviderProvidedFileSystemTest() {}
+ virtual ~FileSystemProviderProvidedFileSystemTest() {}
+
+ virtual void SetUp() override {
+ profile_.reset(new TestingProfile);
+ const base::FilePath mount_path =
+ util::GetMountPath(profile_.get(), kExtensionId, kFileSystemId);
+ file_system_info_.reset(
+ new ProvidedFileSystemInfo(kExtensionId,
+ kFileSystemId,
+ kDisplayName,
+ false /* writable */,
+ true /* supports_notify_tag */,
+ mount_path));
+ provided_file_system_.reset(
+ new ProvidedFileSystem(profile_.get(), *file_system_info_.get()));
+ event_router_.reset(
+ new FakeEventRouter(profile_.get(), provided_file_system_.get()));
+ event_router_->AddEventListener(extensions::api::file_system_provider::
+ OnObserveDirectoryRequested::kEventName,
+ NULL,
+ kExtensionId);
+ event_router_->AddEventListener(extensions::api::file_system_provider::
+ OnUnobserveEntryRequested::kEventName,
+ NULL,
+ kExtensionId);
+ provided_file_system_->SetEventRouterForTesting(event_router_.get());
+ provided_file_system_->SetNotificationManagerForTesting(
+ make_scoped_ptr(new StubNotificationManager));
+ }
+
+ content::TestBrowserThreadBundle thread_bundle_;
+ scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<FakeEventRouter> event_router_;
+ scoped_ptr<ProvidedFileSystemInfo> file_system_info_;
+ scoped_ptr<ProvidedFileSystem> provided_file_system_;
+};
+
+TEST_F(FileSystemProviderProvidedFileSystemTest, AutoUpdater) {
+ Log log;
+ base::Closure firstCallback;
+ base::Closure secondCallback;
+
+ {
+ // Auto updater is ref counted, and bound to all callbacks.
+ scoped_refptr<AutoUpdater> auto_updater(new AutoUpdater(
+ base::Bind(&LogStatus, base::Unretained(&log), base::File::FILE_OK)));
+
+ firstCallback = auto_updater->CreateCallback();
+ secondCallback = auto_updater->CreateCallback();
+ }
+
+ // Getting out of scope, should not invoke updating if there are pending
+ // callbacks.
+ EXPECT_EQ(0u, log.size());
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, firstCallback);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, log.size());
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, secondCallback);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, log.size());
+}
+
+TEST_F(FileSystemProviderProvidedFileSystemTest, AutoUpdater_NoCallbacks) {
+ Log log;
+ {
+ scoped_refptr<AutoUpdater> auto_updater(new AutoUpdater(
+ base::Bind(&LogStatus, base::Unretained(&log), base::File::FILE_OK)));
+ }
+ EXPECT_EQ(1u, log.size());
+}
+
+TEST_F(FileSystemProviderProvidedFileSystemTest, AutoUpdater_CallbackIgnored) {
+ Log log;
+ {
+ scoped_refptr<AutoUpdater> auto_updater(new AutoUpdater(
+ base::Bind(&LogStatus, base::Unretained(&log), base::File::FILE_OK)));
+ base::Closure callback = auto_updater->CreateCallback();
+ // The callback gets out of scope, so the ref counted auto updater instance
+ // gets deleted. Still, updating shouldn't be invoked, since the callback
+ // wasn't executed.
+ }
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, log.size());
+}
+
+TEST_F(FileSystemProviderProvidedFileSystemTest, ObserveDirectory_NotFound) {
+ Log log;
+ Observer observer;
+
+ provided_file_system_->AddObserver(&observer);
+
+ // First, set the extension response to an error.
+ event_router_->set_reply_result(base::File::FILE_ERROR_NOT_FOUND);
+
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ false /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ // The directory should not become observed because of an error.
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, log[0]);
+
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ(0u, observed_entries->size());
+
+ // The observer should not be called.
+ EXPECT_EQ(0, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+
+ provided_file_system_->RemoveObserver(&observer);
+}
+
+TEST_F(FileSystemProviderProvidedFileSystemTest, ObserveDirectory) {
+ Log log;
+ Observer observer;
+
+ provided_file_system_->AddObserver(&observer);
+
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ false /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_OK, log[0]);
+ EXPECT_EQ(1, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ ASSERT_EQ(1u, observed_entries->size());
+ const ProvidedFileSystemInterface::ObservedEntry& observed_entry =
+ observed_entries->begin()->second;
+ EXPECT_EQ(kDirectoryPath, observed_entry.entry_path.value());
+ EXPECT_FALSE(observed_entry.recursive);
+ EXPECT_EQ("", observed_entry.last_tag);
+
+ provided_file_system_->RemoveObserver(&observer);
+}
+
+TEST_F(FileSystemProviderProvidedFileSystemTest, ObserveDirectory_Exists) {
+ Observer observer;
+ provided_file_system_->AddObserver(&observer);
+
+ {
+ // First observe a directory not recursively.
+ Log log;
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ false /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_OK, log[0]);
+ EXPECT_EQ(1, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+ }
+
+ {
+ // Create another non-recursive observer. That should fail.
+ Log log;
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ false /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_ERROR_EXISTS, log[0]);
+ EXPECT_EQ(1, observer.list_changed_counter()); // No changes on the list.
+ EXPECT_EQ(0, observer.tag_updated_counter());
+ }
+
+ {
+ // Create another observer on the same path, but a recursive one. That
+ // should
+ // succeed.
+ Log log;
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ true /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_OK, log[0]);
+ EXPECT_EQ(2, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ ASSERT_EQ(1u, observed_entries->size());
+ const ProvidedFileSystemInterface::ObservedEntry& observed_entry =
+ observed_entries->begin()->second;
+ EXPECT_EQ(kDirectoryPath, observed_entry.entry_path.value());
+ EXPECT_TRUE(observed_entry.recursive);
+ EXPECT_EQ("", observed_entry.last_tag);
+ }
+
+ {
+ // Lastly, create another recursive observer. That should fail, too.
+ Log log;
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ true /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_ERROR_EXISTS, log[0]);
+ EXPECT_EQ(2, observer.list_changed_counter()); // No changes on the list.
+ EXPECT_EQ(0, observer.tag_updated_counter());
+ }
+
+ provided_file_system_->RemoveObserver(&observer);
+}
+
+TEST_F(FileSystemProviderProvidedFileSystemTest, UnobserveEntry) {
+ Observer observer;
+ provided_file_system_->AddObserver(&observer);
+
+ {
+ // First, confirm that unobserving an entry which is not observed, results
+ // in an error.
+ Log log;
+ provided_file_system_->UnobserveEntry(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, log[0]);
+ EXPECT_EQ(0, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+ }
+
+ {
+ // Observe a directory not recursively.
+ Log log;
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ false /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_OK, log[0]);
+ EXPECT_EQ(1, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ(1u, observed_entries->size());
+ }
+
+ {
+ // Unobserve it gracefully.
+ Log log;
+ provided_file_system_->UnobserveEntry(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_OK, log[0]);
+ EXPECT_EQ(2, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ(0u, observed_entries->size());
+ }
+
+ {
+ // Confirm that it's possible to observe it again.
+ Log log;
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ false /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_OK, log[0]);
+ EXPECT_EQ(3, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ(1u, observed_entries->size());
+ }
+
+ {
+ // Finally, unobserve it, but with an error from extension. That should
+ // result
+ // in a removed observer, anyway.
+ event_router_->set_reply_result(base::File::FILE_ERROR_FAILED);
+
+ Log log;
+ provided_file_system_->UnobserveEntry(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_ERROR_FAILED, log[0]);
+ EXPECT_EQ(4, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ(0u, observed_entries->size());
+ }
+
+ provided_file_system_->RemoveObserver(&observer);
+}
+
+TEST_F(FileSystemProviderProvidedFileSystemTest, Notify) {
+ Observer observer;
+ provided_file_system_->AddObserver(&observer);
+
+ {
+ // Observe a directory.
+ Log log;
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ false /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_EQ(1u, log.size());
+ EXPECT_EQ(base::File::FILE_OK, log[0]);
+ EXPECT_EQ(1, observer.list_changed_counter());
+ EXPECT_EQ(0, observer.tag_updated_counter());
+
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ(1u, observed_entries->size());
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ("", observed_entries->begin()->second.last_tag);
+ }
+
+ {
+ // Notify about a change.
+ const ProvidedFileSystemObserver::ChangeType change_type =
+ ProvidedFileSystemObserver::CHANGED;
+ const ProvidedFileSystemObserver::ChildChanges child_changes;
+ const std::string tag = "hello-world";
+ EXPECT_TRUE(provided_file_system_->Notify(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ change_type,
+ child_changes,
+ tag));
+
+ // Verify the observer event.
+ ASSERT_EQ(1u, observer.change_events().size());
+ const Observer::ChangeEvent* const change_event =
+ observer.change_events()[0];
+ EXPECT_EQ(change_type, change_event->change_type());
+ EXPECT_EQ(0u, change_event->child_changes().size());
+
+ // The tag should not be updated in advance, before all observers handle
+ // the notification.
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ(1u, observed_entries->size());
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ("", observed_entries->begin()->second.last_tag);
+
+ // Wait until all observers finish handling the notification.
+ base::RunLoop().RunUntilIdle();
+
+ // Confirm, that the entry is still being observed, and that the tag is
+ // updated.
+ ASSERT_EQ(1u, observed_entries->size());
+ EXPECT_EQ(tag, observed_entries->begin()->second.last_tag);
+ EXPECT_EQ(1, observer.list_changed_counter());
+ EXPECT_EQ(1, observer.tag_updated_counter());
+ }
+
+ {
+ // Notify about deleting of the observed entry.
+ const ProvidedFileSystemObserver::ChangeType change_type =
+ ProvidedFileSystemObserver::DELETED;
+ const ProvidedFileSystemObserver::ChildChanges child_changes;
+ const std::string tag = "chocolate-disco";
+ EXPECT_TRUE(provided_file_system_->Notify(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ change_type,
+ child_changes,
+ tag));
+ base::RunLoop().RunUntilIdle();
+
+ // Verify the observer event.
+ ASSERT_EQ(2u, observer.change_events().size());
+ const Observer::ChangeEvent* const change_event =
+ observer.change_events()[1];
+ EXPECT_EQ(change_type, change_event->change_type());
+ EXPECT_EQ(0u, change_event->child_changes().size());
+ }
+
+ // Confirm, that the entry is not observed anymore.
+ {
+ ProvidedFileSystemInterface::ObservedEntries* const observed_entries =
+ provided_file_system_->GetObservedEntries();
+ EXPECT_EQ(0u, observed_entries->size());
+ EXPECT_EQ(2, observer.list_changed_counter());
+ EXPECT_EQ(2, observer.tag_updated_counter());
+ }
+
+ provided_file_system_->RemoveObserver(&observer);
+}
+
+} // namespace file_system_provider
+} // namespace chromeos

Powered by Google App Engine
This is Rietveld 408576698