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

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: More implementation. 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
index 77ed95b51b41dd69f12aa378ea68b24b1c6b652d..ea946e94a9a974477dc3cbf7020eaac55c086155 100644
--- a/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/provided_file_system_unittest.cc
@@ -2,22 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// TODO(mtomasz): Move these test cases to operations/unmount_unittest.cc.
-
#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"
@@ -25,53 +29,159 @@
namespace chromeos {
namespace file_system_provider {
-
namespace {
const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
-const int kExpectedRequestId = 1;
const char kFileSystemId[] = "camera-pictures";
const char kDisplayName[] = "Camera Pictures";
+const char kDirectoryPath[] = "/hello/world";
hirono 2014/10/03 07:19:13 char -> base::FilePath::CharType ?
mtomasz 2014/10/03 08:35:34 Done.
mtomasz 2014/10/03 08:35:34 Done.
+// 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:
- explicit FakeEventRouter(Profile* profile) : EventRouter(profile, NULL) {}
+ 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 {
- extension_id_ = extension_id;
- event_ = event.Pass();
+ 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_);
+ }
}
- const std::string& extension_id() const { return extension_id_; }
-
- const extensions::Event* event() const { return event_.get(); }
+ void set_reply_result(base::File::Error result) { reply_result_ = result; }
private:
- std::string extension_id_;
- scoped_ptr<extensions::Event> event_;
-
+ ProvidedFileSystemInterface* file_system_; // Not owned.
hirono 2014/10/03 07:19:13 const?
mtomasz 2014/10/03 08:35:34 Done.
+ base::File::Error reply_result_;
DISALLOW_COPY_AND_ASSIGN(FakeEventRouter);
};
-class EventLogger {
+// Observes the tested file system.
+class Observer : public ProvidedFileSystemObserver {
public:
- EventLogger() {}
- virtual ~EventLogger() {}
+ 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:
+ ProvidedFileSystemObserver::ChangeType change_type_;
hirono 2014/10/03 07:19:13 const?
mtomasz 2014/10/03 08:35:34 Done.
+ ProvidedFileSystemObserver::ChildChanges child_changes_;
hirono 2014/10/03 07:19:13 const?
mtomasz 2014/10/03 08:35:33 Done.
+
+ 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);
+ }
- void OnStatusCallback(base::File::Error error) {
- error_.reset(new base::File::Error(error));
+ 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_;
}
- base::File::Error* error() { return error_.get(); }
+ 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:
- scoped_ptr<base::File::Error> error_;
- DISALLOW_COPY_AND_ASSIGN(EventLogger);
+ 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 {
@@ -81,99 +191,420 @@ class FileSystemProviderProvidedFileSystemTest : public testing::Test {
virtual void SetUp() OVERRIDE {
profile_.reset(new TestingProfile);
- event_router_.reset(new FakeEventRouter(profile_.get()));
- event_router_->AddEventListener(
- extensions::api::file_system_provider::OnUnmountRequested::kEventName,
- NULL,
- kExtensionId);
-
const base::FilePath mount_path =
util::GetMountPath(profile_.get(), kExtensionId, kFileSystemId);
- file_system_info_.reset(new ProvidedFileSystemInfo(
- kExtensionId, kFileSystemId, kDisplayName, mount_path));
+ file_system_info_.reset(
+ new ProvidedFileSystemInfo(kExtensionId,
+ kFileSystemId,
+ kDisplayName,
+ false /* writable */,
+ true /* supports_notify_tag */,
+ mount_path));
provided_file_system_.reset(
- new ProvidedFileSystem(event_router_.get(), *file_system_info_.get()));
+ 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<ProvidedFileSystemInterface> provided_file_system_;
+ scoped_ptr<ProvidedFileSystem> provided_file_system_;
};
-TEST_F(FileSystemProviderProvidedFileSystemTest, RequestUnmount_Success) {
- EventLogger logger;
+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);
- provided_file_system_->RequestUnmount(
- base::Bind(&EventLogger::OnStatusCallback, base::Unretained(logger)));
+ // 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();
- // Verify that the event has been sent to the providing extension.
- EXPECT_EQ(kExtensionId, event_router_->extension_id());
- const extensions::Event* event = event_router_->event();
- ASSERT_TRUE(event);
- ASSERT_TRUE(event->event_args);
- base::ListValue* event_args = event->event_args.get();
- EXPECT_EQ(2u, event_args->GetSize());
- std::string file_system_id;
- EXPECT_TRUE(event_args->GetString(0, &file_system_id));
- EXPECT_EQ(kFileSystemId, file_system_id);
-
- // Remember the request id, and verify it is valid.
- int request_id = 0;
- EXPECT_TRUE(event_args->GetInteger(1, &request_id));
- EXPECT_EQ(kExpectedRequestId, request_id);
-
- // Callback should not be called, yet.
- EXPECT_FALSE(logger.error());
-
- // Simulate sending a success response from the providing extension.
- RequestManager* request_manager = provided_file_system_->GetRequestManager();
- ASSERT_TRUE(request_manager);
- scoped_ptr<RequestValue> response;
- bool reply_result = request_manager->FulfillRequest(
- request_id, response.Pass(), false /* has_more */);
- EXPECT_TRUE(reply_result);
-
- // Callback should be called. Verify the error code.
- ASSERT_TRUE(logger.error());
- EXPECT_EQ(base::File::FILE_OK, *logger.error());
+ // 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, RequestUnmount_Error) {
- EventLogger logger;
+TEST_F(FileSystemProviderProvidedFileSystemTest, ObserveDirectory) {
+ Log log;
+ Observer observer;
+
+ provided_file_system_->AddObserver(&observer);
- provided_file_system_->RequestUnmount(
- base::Bind(&EventLogger::OnStatusCallback, base::Unretained(logger)));
+ provided_file_system_->ObserveDirectory(
+ base::FilePath::FromUTF8Unsafe(kDirectoryPath),
+ false /* recursive */,
+ base::Bind(&LogStatus, base::Unretained(&log)));
base::RunLoop().RunUntilIdle();
- // Verify that the event has been sent to the providing extension.
- EXPECT_EQ(kExtensionId, event_router_->extension_id());
- const extensions::Event* event = event_router_->event();
- ASSERT_TRUE(event);
- ASSERT_TRUE(event->event_args);
- base::ListValue* event_args = event->event_args.get();
- EXPECT_EQ(2u, event_args->GetSize());
- std::string file_system_id;
- EXPECT_TRUE(event_args->GetString(0, &file_system_id));
- EXPECT_EQ(kFileSystemId, file_system_id);
-
- // Remember the request id, and verify it is valid.
- int request_id = 0;
- EXPECT_TRUE(event_args->GetInteger(1, &request_id));
- EXPECT_EQ(kExpectedRequestId, request_id);
-
- // Simulate sending an error response from the providing extension.
- RequestManager* request_manager = provided_file_system_->GetRequestManager();
- ASSERT_TRUE(request_manager);
- bool reply_result = request_manager->RejectRequest(
- request_id, base::File::FILE_ERROR_NOT_FOUND);
- EXPECT_TRUE(reply_result);
-
- // Callback should be called. Verify the error code.
- ASSERT_TRUE(logger.error());
- EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, *logger.error());
+ 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

Powered by Google App Engine
This is Rietveld 408576698