| 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
|
|
|