123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888 |
- // Copyright 2018 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 "ash/components/drivefs/drivefs_host.h"
- #include <set>
- #include <type_traits>
- #include <utility>
- #include "ash/components/disks/disk_mount_manager.h"
- #include "ash/components/disks/mock_disk_mount_manager.h"
- #include "ash/components/drivefs/drivefs_host_observer.h"
- #include "ash/components/drivefs/fake_drivefs.h"
- #include "ash/components/drivefs/mojom/drivefs.mojom-test-utils.h"
- #include "ash/components/drivefs/mojom/drivefs.mojom.h"
- #include "base/bind.h"
- #include "base/check.h"
- #include "base/notreached.h"
- #include "base/run_loop.h"
- #include "base/scoped_observation.h"
- #include "base/strings/strcat.h"
- #include "base/strings/string_split.h"
- #include "base/test/bind.h"
- #include "base/test/gmock_callback_support.h"
- #include "base/test/gmock_move_support.h"
- #include "base/test/simple_test_clock.h"
- #include "base/test/task_environment.h"
- #include "base/timer/mock_timer.h"
- #include "chromeos/components/mojo_bootstrap/pending_connection_manager.h"
- #include "components/drive/drive_notification_manager.h"
- #include "components/drive/drive_notification_observer.h"
- #include "components/invalidation/impl/fake_invalidation_service.h"
- #include "components/signin/public/identity_manager/identity_manager.h"
- #include "components/signin/public/identity_manager/identity_test_environment.h"
- #include "mojo/public/cpp/bindings/clone_traits.h"
- #include "mojo/public/cpp/bindings/pending_receiver.h"
- #include "mojo/public/cpp/bindings/pending_remote.h"
- #include "mojo/public/cpp/bindings/receiver.h"
- #include "mojo/public/cpp/bindings/receiver_set.h"
- #include "mojo/public/cpp/bindings/remote.h"
- #include "services/network/public/cpp/shared_url_loader_factory.h"
- #include "services/network/test/test_network_connection_tracker.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/utility/utility.h"
- namespace drivefs {
- namespace {
- using base::test::RunOnceClosure;
- using testing::_;
- using MountFailure = DriveFsHost::MountObserver::MountFailure;
- using ChangeLogOptionPair = std::pair<int64_t, std::string>;
- constexpr base::TimeDelta kTokenLifetime = base::Hours(1);
- class MockDriveFs : public mojom::DriveFsInterceptorForTesting,
- public mojom::SearchQuery {
- public:
- MockDriveFs() = default;
- DriveFs* GetForwardingInterface() override {
- NOTREACHED();
- return nullptr;
- }
- void FetchChangeLog(
- std::vector<mojom::FetchChangeLogOptionsPtr> options) override {
- std::vector<ChangeLogOptionPair> unwrapped_options;
- for (auto& entry : options) {
- unwrapped_options.push_back(
- std::make_pair(entry->change_id, entry->team_drive_id));
- }
- FetchChangeLogImpl(unwrapped_options);
- }
- MOCK_METHOD(void,
- FetchChangeLogImpl,
- (const std::vector<ChangeLogOptionPair>&));
- MOCK_METHOD(void, FetchAllChangeLogs, ());
- MOCK_METHOD(void,
- OnStartSearchQuery,
- (const mojom::QueryParameters&),
- (const));
- void StartSearchQuery(mojo::PendingReceiver<mojom::SearchQuery> receiver,
- mojom::QueryParametersPtr query_params) override {
- search_receiver_.reset();
- OnStartSearchQuery(*query_params);
- search_receiver_.Bind(std::move(receiver));
- }
- MOCK_METHOD(drive::FileError,
- OnGetNextPage,
- (absl::optional<std::vector<mojom::QueryItemPtr>> * items));
- void GetNextPage(GetNextPageCallback callback) override {
- absl::optional<std::vector<mojom::QueryItemPtr>> items;
- auto error = OnGetNextPage(&items);
- std::move(callback).Run(error, std::move(items));
- }
- private:
- mojo::Receiver<mojom::SearchQuery> search_receiver_{this};
- };
- class TestingDriveFsHostDelegate : public DriveFsHost::Delegate,
- public DriveFsHost::MountObserver {
- public:
- TestingDriveFsHostDelegate(signin::IdentityManager* identity_manager,
- const AccountId& account_id)
- : identity_manager_(identity_manager),
- account_id_(account_id),
- drive_notification_manager_(&invalidation_service_) {}
- TestingDriveFsHostDelegate(const TestingDriveFsHostDelegate&) = delete;
- TestingDriveFsHostDelegate& operator=(const TestingDriveFsHostDelegate&) =
- delete;
- ~TestingDriveFsHostDelegate() override {
- drive_notification_manager_.Shutdown();
- }
- void set_pending_bootstrap(
- mojo::PendingRemote<mojom::DriveFsBootstrap> pending_bootstrap) {
- pending_bootstrap_ = std::move(pending_bootstrap);
- }
- void set_verbose_logging_enabled(bool enabled) {
- verbose_logging_enabled_ = enabled;
- }
- drivefs::mojom::ExtensionConnectionParams& get_last_extension_params() {
- return *extension_params_;
- }
- // DriveFsHost::MountObserver:
- MOCK_METHOD(void, OnMounted, (const base::FilePath&));
- MOCK_METHOD(void,
- OnMountFailed,
- (MountFailure, absl::optional<base::TimeDelta>));
- MOCK_METHOD(void, OnUnmounted, (absl::optional<base::TimeDelta>));
- drive::DriveNotificationManager& GetDriveNotificationManager() override {
- return drive_notification_manager_;
- }
- private:
- // DriveFsHost::Delegate:
- scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
- override {
- return nullptr;
- }
- signin::IdentityManager* GetIdentityManager() override {
- return identity_manager_;
- }
- const AccountId& GetAccountId() override { return account_id_; }
- std::string GetObfuscatedAccountId() override {
- return "salt-" + account_id_.GetAccountIdKey();
- }
- bool IsMetricsCollectionEnabled() override { return false; }
- std::unique_ptr<DriveFsBootstrapListener> CreateMojoListener() override {
- DCHECK(pending_bootstrap_);
- return std::make_unique<FakeDriveFsBootstrapListener>(
- std::move(pending_bootstrap_));
- }
- std::string GetLostAndFoundDirectoryName() override {
- return "recovered files";
- }
- base::FilePath GetMyFilesPath() override {
- return base::FilePath("/MyFiles");
- }
- bool IsVerboseLoggingEnabled() override { return verbose_logging_enabled_; }
- drivefs::mojom::DriveFsDelegate::ExtensionConnectionStatus ConnectToExtension(
- drivefs::mojom::ExtensionConnectionParamsPtr params,
- mojo::PendingReceiver<drivefs::mojom::NativeMessagingPort> port,
- mojo::PendingRemote<drivefs::mojom::NativeMessagingHost> host) override {
- extension_params_ = std::move(params);
- return drivefs::mojom::DriveFsDelegate::ExtensionConnectionStatus::
- kExtensionNotFound;
- }
- const std::string GetMachineRootID() override { return ""; }
- void PersistMachineRootID(const std::string& id) override {}
- signin::IdentityManager* const identity_manager_;
- const AccountId account_id_;
- mojo::PendingRemote<mojom::DriveFsBootstrap> pending_bootstrap_;
- bool verbose_logging_enabled_ = false;
- invalidation::FakeInvalidationService invalidation_service_;
- drive::DriveNotificationManager drive_notification_manager_;
- drivefs::mojom::ExtensionConnectionParamsPtr extension_params_;
- };
- class MockDriveFsHostObserver : public DriveFsHostObserver {
- public:
- MOCK_METHOD(void, OnUnmounted, ());
- MOCK_METHOD(void,
- OnSyncingStatusUpdate,
- (const mojom::SyncingStatus& status));
- MOCK_METHOD(void,
- OnMirrorSyncingStatusUpdate,
- (const mojom::SyncingStatus& status));
- MOCK_METHOD(void,
- OnFilesChanged,
- (const std::vector<mojom::FileChange>& changes));
- MOCK_METHOD(void, OnError, (const mojom::DriveError& error));
- };
- class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
- public:
- DriveFsHostTest()
- : network_connection_tracker_(
- network::TestNetworkConnectionTracker::CreateInstance()) {
- clock_.SetNow(base::Time::Now());
- }
- DriveFsHostTest(const DriveFsHostTest&) = delete;
- DriveFsHostTest& operator=(const DriveFsHostTest&) = delete;
- protected:
- void SetUp() override {
- testing::Test::SetUp();
- profile_path_ = base::FilePath(FILE_PATH_LITERAL("/path/to/profile"));
- account_id_ = AccountId::FromUserEmailGaiaId("test@example.com", "ID");
- disk_manager_ = std::make_unique<ash::disks::MockDiskMountManager>();
- identity_test_env_.MakePrimaryAccountAvailable(
- "test@example.com", signin::ConsentLevel::kSignin);
- host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>(
- identity_test_env_.identity_manager(), account_id_);
- auto timer = std::make_unique<base::MockOneShotTimer>();
- timer_ = timer.get();
- host_ = std::make_unique<DriveFsHost>(
- profile_path_, host_delegate_.get(), host_delegate_.get(),
- network_connection_tracker_.get(), &clock_, disk_manager_.get(),
- std::move(timer));
- }
- void TearDown() override {
- host_.reset();
- disk_manager_.reset();
- }
- std::string StartMount() {
- std::string source;
- EXPECT_CALL(
- *disk_manager_,
- MountPath(
- testing::StartsWith("drivefs://"), "", "drivefs-salt-g-ID",
- testing::AllOf(testing::Contains(
- "datadir=/path/to/profile/GCache/v2/salt-g-ID"),
- testing::Contains("myfiles=/MyFiles")),
- _, ash::MountAccessMode::kReadWrite, _))
- .WillOnce(testing::DoAll(testing::SaveArg<0>(&source),
- MoveArg<6>(&mount_callback_)));
- host_delegate_->set_pending_bootstrap(
- bootstrap_receiver_.BindNewPipeAndPassRemote());
- pending_delegate_receiver_ = delegate_.BindNewPipeAndPassReceiver();
- EXPECT_TRUE(host_->Mount());
- testing::Mock::VerifyAndClear(&disk_manager_);
- return source.substr(strlen("drivefs://"));
- }
- void CallMountCallbackSuccess(const std::string& token) {
- std::move(mount_callback_)
- .Run(ash::MountError::kNone, {base::StrCat({"drivefs://", token}),
- "/media/drivefsroot/salt-g-ID",
- ash::MountType::kNetworkStorage,
- {}});
- }
- void SendOnMounted() { delegate_->OnMounted(); }
- void SendOnUnmounted(absl::optional<base::TimeDelta> delay) {
- delegate_->OnUnmounted(std::move(delay));
- }
- void SendMountFailed(absl::optional<base::TimeDelta> delay) {
- delegate_->OnMountFailed(std::move(delay));
- }
- void EstablishConnection() {
- token_ = StartMount();
- CallMountCallbackSuccess(token_);
- ASSERT_TRUE(mojo_bootstrap::PendingConnectionManager::Get().OpenIpcChannel(
- token_, {}));
- {
- base::RunLoop run_loop;
- bootstrap_receiver_.set_disconnect_handler(run_loop.QuitClosure());
- run_loop.Run();
- }
- }
- void DoMount() {
- EstablishConnection();
- base::RunLoop run_loop;
- base::OnceClosure quit_closure = run_loop.QuitClosure();
- EXPECT_CALL(*host_delegate_,
- OnMounted(base::FilePath("/media/drivefsroot/salt-g-ID")))
- .WillOnce(RunOnceClosure(std::move(quit_closure)));
- // Eventually we must attempt unmount.
- EXPECT_CALL(*disk_manager_, UnmountPath("/media/drivefsroot/salt-g-ID", _));
- SendOnMounted();
- run_loop.Run();
- ASSERT_TRUE(host_->IsMounted());
- }
- void DoUnmount() {
- EXPECT_CALL(*host_delegate_, OnUnmounted(_)).Times(0);
- host_->Unmount();
- receiver_.reset();
- bootstrap_receiver_.reset();
- delegate_.reset();
- base::RunLoop().RunUntilIdle();
- testing::Mock::VerifyAndClearExpectations(disk_manager_.get());
- testing::Mock::VerifyAndClearExpectations(host_delegate_.get());
- }
- void Init(mojom::DriveFsConfigurationPtr config,
- mojo::PendingReceiver<mojom::DriveFs> drive_fs_receiver,
- mojo::PendingRemote<mojom::DriveFsDelegate> delegate) override {
- EXPECT_EQ("test@example.com", config->user_email);
- EXPECT_EQ("recovered files",
- config->lost_and_found_directory_name.value_or("<None>"));
- verbose_logging_enabled_ = config->enable_verbose_logging;
- init_access_token_ = std::move(config->access_token);
- receiver_.Bind(std::move(drive_fs_receiver));
- mojo::FusePipes(std::move(pending_delegate_receiver_), std::move(delegate));
- }
- base::FilePath profile_path_;
- base::test::TaskEnvironment task_environment_;
- AccountId account_id_;
- std::unique_ptr<ash::disks::MockDiskMountManager> disk_manager_;
- ash::disks::DiskMountManager::MountPathCallback mount_callback_;
- std::unique_ptr<network::TestNetworkConnectionTracker>
- network_connection_tracker_;
- base::SimpleTestClock clock_;
- signin::IdentityTestEnvironment identity_test_env_;
- std::unique_ptr<TestingDriveFsHostDelegate> host_delegate_;
- std::unique_ptr<DriveFsHost> host_;
- base::MockOneShotTimer* timer_;
- absl::optional<bool> verbose_logging_enabled_;
- mojo::Receiver<mojom::DriveFsBootstrap> bootstrap_receiver_{this};
- MockDriveFs mock_drivefs_;
- mojo::Receiver<mojom::DriveFs> receiver_{&mock_drivefs_};
- mojo::Remote<mojom::DriveFsDelegate> delegate_;
- mojo::PendingReceiver<mojom::DriveFsDelegate> pending_delegate_receiver_;
- std::string token_;
- absl::optional<std::string> init_access_token_;
- };
- TEST_F(DriveFsHostTest, Basic) {
- MockDriveFsHostObserver observer;
- base::ScopedObservation<DriveFsHost, DriveFsHostObserver> observation_scoper(
- &observer);
- observation_scoper.Observe(host_.get());
- EXPECT_FALSE(host_->IsMounted());
- EXPECT_EQ(base::FilePath("/path/to/profile/GCache/v2/salt-g-ID"),
- host_->GetDataPath());
- ASSERT_NO_FATAL_FAILURE(DoMount());
- EXPECT_FALSE(init_access_token_);
- ASSERT_TRUE(verbose_logging_enabled_);
- EXPECT_FALSE(verbose_logging_enabled_.value());
- EXPECT_EQ(base::FilePath("/media/drivefsroot/salt-g-ID"),
- host_->GetMountPath());
- EXPECT_CALL(observer, OnUnmounted());
- EXPECT_CALL(*host_delegate_, OnUnmounted(_)).Times(0);
- base::RunLoop run_loop;
- delegate_.set_disconnect_handler(run_loop.QuitClosure());
- host_->Unmount();
- run_loop.Run();
- }
- TEST_F(DriveFsHostTest, EnableVerboseLogging) {
- ASSERT_FALSE(host_->IsMounted());
- host_delegate_->set_verbose_logging_enabled(true);
- ASSERT_NO_FATAL_FAILURE(DoMount());
- ASSERT_TRUE(verbose_logging_enabled_);
- EXPECT_TRUE(verbose_logging_enabled_.value());
- }
- TEST_F(DriveFsHostTest, GetMountPathWhileUnmounted) {
- EXPECT_EQ(base::FilePath("/media/fuse/drivefs-salt-g-ID"),
- host_->GetMountPath());
- }
- TEST_F(DriveFsHostTest, OnMountFailedFromMojo) {
- ASSERT_FALSE(host_->IsMounted());
- ASSERT_NO_FATAL_FAILURE(EstablishConnection());
- base::RunLoop run_loop;
- base::OnceClosure quit_closure = run_loop.QuitClosure();
- EXPECT_CALL(*host_delegate_, OnMountFailed(MountFailure::kUnknown, _))
- .WillOnce(RunOnceClosure(std::move(quit_closure)));
- SendMountFailed({});
- run_loop.Run();
- ASSERT_FALSE(host_->IsMounted());
- }
- TEST_F(DriveFsHostTest, OnMountFailedFromDbus) {
- ASSERT_FALSE(host_->IsMounted());
- EXPECT_CALL(*disk_manager_, UnmountPath(_, _)).Times(0);
- auto token = StartMount();
- base::RunLoop run_loop;
- base::OnceClosure quit_closure = run_loop.QuitClosure();
- EXPECT_CALL(*host_delegate_, OnMountFailed(MountFailure::kInvocation, _))
- .WillOnce(RunOnceClosure(std::move(quit_closure)));
- std::move(mount_callback_)
- .Run(ash::MountError::kInvalidMountOptions,
- {base::StrCat({"drivefs://", token}),
- "/media/drivefsroot/salt-g-ID",
- ash::MountType::kNetworkStorage,
- {}});
- run_loop.Run();
- ASSERT_FALSE(host_->IsMounted());
- EXPECT_FALSE(mojo_bootstrap::PendingConnectionManager::Get().OpenIpcChannel(
- token, {}));
- }
- TEST_F(DriveFsHostTest, DestroyBeforeMojoConnection) {
- auto token = StartMount();
- CallMountCallbackSuccess(token);
- base::RunLoop run_loop;
- EXPECT_CALL(*disk_manager_, UnmountPath("/media/drivefsroot/salt-g-ID", _))
- .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
- host_.reset();
- EXPECT_FALSE(mojo_bootstrap::PendingConnectionManager::Get().OpenIpcChannel(
- token, {}));
- run_loop.Run();
- }
- TEST_F(DriveFsHostTest, MountWhileAlreadyMounted) {
- DoMount();
- EXPECT_FALSE(host_->Mount());
- }
- TEST_F(DriveFsHostTest, UnsupportedAccountTypes) {
- EXPECT_CALL(*disk_manager_, MountPath(_, _, _, _, _, _, _)).Times(0);
- const AccountId unsupported_accounts[] = {
- AccountId::FromGaiaId("ID"),
- AccountId::FromUserEmail("test2@example.com"),
- };
- for (auto& account : unsupported_accounts) {
- host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>(
- identity_test_env_.identity_manager(), account);
- host_ = std::make_unique<DriveFsHost>(
- profile_path_, host_delegate_.get(), host_delegate_.get(),
- network_connection_tracker_.get(), &clock_, disk_manager_.get(),
- std::make_unique<base::MockOneShotTimer>());
- EXPECT_FALSE(host_->Mount());
- EXPECT_FALSE(host_->IsMounted());
- }
- }
- TEST_F(DriveFsHostTest, GetAccessToken_UnmountDuringMojoRequest) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- base::RunLoop run_loop;
- delegate_.set_disconnect_handler(run_loop.QuitClosure());
- delegate_->GetAccessToken(
- "client ID", "app ID", {"scope1", "scope2"},
- base::BindLambdaForTesting([](mojom::AccessTokenStatus status,
- const std::string& token) { FAIL(); }));
- host_->Unmount();
- run_loop.Run();
- EXPECT_FALSE(host_->IsMounted());
- EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
- }
- ACTION_P(CloneStruct, output) {
- *output = arg0.Clone();
- }
- TEST_F(DriveFsHostTest, OnSyncingStatusUpdate_ForwardToObservers) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- MockDriveFsHostObserver observer;
- base::ScopedObservation<DriveFsHost, DriveFsHostObserver> observation_scoper(
- &observer);
- observation_scoper.Observe(host_.get());
- auto status = mojom::SyncingStatus::New();
- status->item_events.emplace_back(absl::in_place, 12, 34, "filename.txt",
- mojom::ItemEvent::State::kInProgress, 123,
- 456, mojom::ItemEventReason::kPin);
- mojom::SyncingStatusPtr observed_status;
- EXPECT_CALL(observer, OnSyncingStatusUpdate(_))
- .WillOnce(CloneStruct(&observed_status));
- delegate_->OnSyncingStatusUpdate(status.Clone());
- delegate_.FlushForTesting();
- testing::Mock::VerifyAndClear(&observer);
- EXPECT_EQ(status, observed_status);
- }
- ACTION_P(CloneVectorOfStructs, output) {
- for (auto& s : arg0) {
- output->emplace_back(s.Clone());
- }
- }
- TEST_F(DriveFsHostTest, OnFilesChanged_ForwardToObservers) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- MockDriveFsHostObserver observer;
- base::ScopedObservation<DriveFsHost, DriveFsHostObserver> observation_scoper(
- &observer);
- observation_scoper.Observe(host_.get());
- std::vector<mojom::FileChangePtr> changes;
- changes.emplace_back(absl::in_place, base::FilePath("/create"),
- mojom::FileChange::Type::kCreate);
- changes.emplace_back(absl::in_place, base::FilePath("/delete"),
- mojom::FileChange::Type::kDelete);
- changes.emplace_back(absl::in_place, base::FilePath("/modify"),
- mojom::FileChange::Type::kModify);
- std::vector<mojom::FileChangePtr> observed_changes;
- EXPECT_CALL(observer, OnFilesChanged(_))
- .WillOnce(CloneVectorOfStructs(&observed_changes));
- delegate_->OnFilesChanged(mojo::Clone(changes));
- delegate_.FlushForTesting();
- testing::Mock::VerifyAndClear(&observer);
- EXPECT_EQ(changes, observed_changes);
- }
- TEST_F(DriveFsHostTest, OnError_ForwardToObservers) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- MockDriveFsHostObserver observer;
- base::ScopedObservation<DriveFsHost, DriveFsHostObserver> observation_scoper(
- &observer);
- observation_scoper.Observe(host_.get());
- auto error = mojom::DriveError::New(
- mojom::DriveError::Type::kCantUploadStorageFull, base::FilePath("/foo"));
- mojom::DriveErrorPtr observed_error;
- EXPECT_CALL(observer, OnError(_)).WillOnce(CloneStruct(&observed_error));
- delegate_->OnError(error.Clone());
- delegate_.FlushForTesting();
- testing::Mock::VerifyAndClear(&observer);
- EXPECT_EQ(error, observed_error);
- }
- TEST_F(DriveFsHostTest, OnError_IgnoreUnknownErrorTypes) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- MockDriveFsHostObserver observer;
- base::ScopedObservation<DriveFsHost, DriveFsHostObserver> observation_scoper(
- &observer);
- observation_scoper.Observe(host_.get());
- EXPECT_CALL(observer, OnError(_)).Times(0);
- delegate_->OnError(mojom::DriveError::New(
- static_cast<mojom::DriveError::Type>(
- static_cast<std::underlying_type_t<mojom::DriveError::Type>>(
- mojom::DriveError::Type::kMaxValue) +
- 1),
- base::FilePath("/foo")));
- delegate_.FlushForTesting();
- }
- TEST_F(DriveFsHostTest, DisplayConfirmDialog_ForwardToHandler) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- auto reason = mojom::DialogReason::New(
- mojom::DialogReason::Type::kEnableDocsOffline, base::FilePath());
- mojom::DialogReasonPtr observed_reason;
- host_->set_dialog_handler(base::BindLambdaForTesting(
- [&](const mojom::DialogReason& reason,
- base::OnceCallback<void(mojom::DialogResult)> callback) {
- observed_reason = reason.Clone();
- std::move(callback).Run(mojom::DialogResult::kAccept);
- }));
- bool called = false;
- delegate_->DisplayConfirmDialog(
- reason.Clone(),
- base::BindLambdaForTesting([&](mojom::DialogResult result) {
- EXPECT_EQ(mojom::DialogResult::kAccept, result);
- called = true;
- }));
- delegate_.FlushForTesting();
- EXPECT_EQ(reason, observed_reason);
- EXPECT_TRUE(called);
- }
- TEST_F(DriveFsHostTest, DisplayConfirmDialogImpl_IgnoreIfNoHandler) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- bool called = false;
- delegate_->DisplayConfirmDialog(
- mojom::DialogReason::New(mojom::DialogReason::Type::kEnableDocsOffline,
- base::FilePath()),
- base::BindLambdaForTesting([&](mojom::DialogResult result) {
- EXPECT_EQ(mojom::DialogResult::kNotDisplayed, result);
- called = true;
- }));
- delegate_.FlushForTesting();
- EXPECT_TRUE(called);
- }
- TEST_F(DriveFsHostTest, DisplayConfirmDialogImpl_IgnoreUnknownReasonTypes) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- host_->set_dialog_handler(base::BindRepeating(
- [](const mojom::DialogReason&,
- base::OnceCallback<void(mojom::DialogResult)>) { NOTREACHED(); }));
- bool called = false;
- delegate_->DisplayConfirmDialog(
- mojom::DialogReason::New(
- static_cast<mojom::DialogReason::Type>(
- static_cast<std::underlying_type_t<mojom::DialogReason::Type>>(
- mojom::DialogReason::Type::kMaxValue) +
- 1),
- base::FilePath()),
- base::BindLambdaForTesting([&](mojom::DialogResult result) {
- EXPECT_EQ(mojom::DialogResult::kNotDisplayed, result);
- called = true;
- }));
- delegate_.FlushForTesting();
- EXPECT_TRUE(called);
- }
- TEST_F(DriveFsHostTest, TeamDriveTracking) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- delegate_->OnTeamDrivesListReady({"a", "b"});
- delegate_.FlushForTesting();
- EXPECT_EQ(
- (std::set<std::string>{"a", "b"}),
- host_delegate_->GetDriveNotificationManager().team_drive_ids_for_test());
- delegate_->OnTeamDriveChanged(
- "c", mojom::DriveFsDelegate::CreateOrDelete::kCreated);
- delegate_.FlushForTesting();
- EXPECT_EQ(
- (std::set<std::string>{"a", "b", "c"}),
- host_delegate_->GetDriveNotificationManager().team_drive_ids_for_test());
- delegate_->OnTeamDriveChanged(
- "b", mojom::DriveFsDelegate::CreateOrDelete::kDeleted);
- delegate_.FlushForTesting();
- EXPECT_EQ(
- (std::set<std::string>{"a", "c"}),
- host_delegate_->GetDriveNotificationManager().team_drive_ids_for_test());
- }
- TEST_F(DriveFsHostTest, TeamDriveTrackingIgnoreChanges) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- EXPECT_EQ(
- std::set<std::string>(),
- host_delegate_->GetDriveNotificationManager().team_drive_ids_for_test());
- delegate_->OnTeamDriveChanged(
- "a", mojom::DriveFsDelegate::CreateOrDelete::kCreated);
- delegate_.FlushForTesting();
- EXPECT_EQ(
- std::set<std::string>(),
- host_delegate_->GetDriveNotificationManager().team_drive_ids_for_test());
- delegate_->OnTeamDriveChanged(
- "b", mojom::DriveFsDelegate::CreateOrDelete::kDeleted);
- delegate_.FlushForTesting();
- EXPECT_EQ(
- std::set<std::string>(),
- host_delegate_->GetDriveNotificationManager().team_drive_ids_for_test());
- }
- TEST_F(DriveFsHostTest, Invalidation) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- delegate_->OnTeamDrivesListReady({"a", "b"});
- delegate_.FlushForTesting();
- EXPECT_CALL(mock_drivefs_,
- FetchChangeLogImpl(
- std::vector<ChangeLogOptionPair>{{123, ""}, {456, "a"}}));
- for (auto& observer :
- host_delegate_->GetDriveNotificationManager().observers_for_test()) {
- observer.OnNotificationReceived({{"", 123}, {"a", 456}});
- }
- receiver_.FlushForTesting();
- }
- TEST_F(DriveFsHostTest, InvalidateAll) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- delegate_->OnTeamDrivesListReady({"a", "b"});
- delegate_.FlushForTesting();
- EXPECT_CALL(mock_drivefs_, FetchAllChangeLogs());
- for (auto& observer :
- host_delegate_->GetDriveNotificationManager().observers_for_test()) {
- observer.OnNotificationTimerFired();
- }
- receiver_.FlushForTesting();
- }
- TEST_F(DriveFsHostTest, RemoveDriveNotificationObserver) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- delegate_->OnTeamDrivesListReady({"a", "b"});
- delegate_.FlushForTesting();
- EXPECT_TRUE(!host_delegate_->GetDriveNotificationManager()
- .observers_for_test()
- .empty());
- host_.reset();
- EXPECT_FALSE(!host_delegate_->GetDriveNotificationManager()
- .observers_for_test()
- .empty());
- }
- TEST_F(DriveFsHostTest, Remount_CachedOnceOnly) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- // Request an access token.
- delegate_->GetAccessToken(
- "client ID", "app ID", {"scope1", "scope2"},
- base::BindLambdaForTesting(
- [&](mojom::AccessTokenStatus status, const std::string& token) {
- EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
- EXPECT_EQ("auth token", token);
- }));
- delegate_.FlushForTesting();
- EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
- // Fulfill the request.
- identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
- "auth token", clock_.Now() + kTokenLifetime);
- EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
- absl::optional<base::TimeDelta> delay = base::Seconds(5);
- EXPECT_CALL(*host_delegate_, OnUnmounted(delay));
- SendOnUnmounted(delay);
- base::RunLoop().RunUntilIdle();
- ASSERT_NO_FATAL_FAILURE(DoUnmount());
- // Second mount attempt should reuse already available token.
- ASSERT_NO_FATAL_FAILURE(DoMount());
- EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
- EXPECT_EQ("auth token", init_access_token_.value_or(""));
- // But if it asks for token again it goes to identity manager.
- delegate_->GetAccessToken(
- "client ID", "app ID", {"scope1", "scope2"},
- base::BindLambdaForTesting(
- [&](mojom::AccessTokenStatus status, const std::string& token) {
- EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
- EXPECT_EQ("auth token 2", token);
- }));
- delegate_.FlushForTesting();
- EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
- // Fulfill the request with a different token.
- identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
- "auth token 2", clock_.Now() + kTokenLifetime);
- EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
- }
- TEST_F(DriveFsHostTest, Remount_RequestInflight) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- delegate_->GetAccessToken(
- "client ID", "app ID", {"scope1", "scope2"},
- base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
- const std::string& token) { FAIL(); }));
- absl::optional<base::TimeDelta> delay = base::Seconds(5);
- EXPECT_CALL(*host_delegate_, OnUnmounted(delay));
- SendOnUnmounted(delay);
- base::RunLoop().RunUntilIdle();
- ASSERT_NO_FATAL_FAILURE(DoUnmount());
- EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
- // Now the response is ready.
- identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
- "auth token", clock_.Now() + kTokenLifetime);
- // Second mount will reuse previous token.
- ASSERT_NO_FATAL_FAILURE(DoMount());
- EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
- EXPECT_EQ("auth token", init_access_token_.value_or(""));
- }
- TEST_F(DriveFsHostTest, Remount_RequestInflightCompleteAfterMount) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- delegate_->GetAccessToken(
- "client ID", "app ID", {"scope1", "scope2"},
- base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
- const std::string& token) { FAIL(); }));
- absl::optional<base::TimeDelta> delay = base::Seconds(5);
- EXPECT_CALL(*host_delegate_, OnUnmounted(delay));
- SendOnUnmounted(delay);
- base::RunLoop().RunUntilIdle();
- ASSERT_NO_FATAL_FAILURE(DoUnmount());
- EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
- // Second mount will reuse previous token.
- ASSERT_NO_FATAL_FAILURE(DoMount());
- EXPECT_FALSE(init_access_token_);
- EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
- // Now the response is ready.
- identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
- "auth token", clock_.Now() + kTokenLifetime);
- EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
- // A new request will reuse the cached token.
- delegate_->GetAccessToken(
- "client ID", "app ID", {"scope1", "scope2"},
- base::BindLambdaForTesting(
- [&](mojom::AccessTokenStatus status, const std::string& token) {
- EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
- EXPECT_EQ("auth token", token);
- }));
- delegate_.FlushForTesting();
- EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
- }
- TEST_F(DriveFsHostTest, ConnectToExtension) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- mojo::Remote<drivefs::mojom::NativeMessagingPort> remote;
- mojo::PendingRemote<drivefs::mojom::NativeMessagingHost> host_remote;
- auto receiver = host_remote.InitWithNewPipeAndPassReceiver();
- base::RunLoop run_loop;
- delegate_->ConnectToExtension(
- drivefs::mojom::ExtensionConnectionParams::New("foo"),
- remote.BindNewPipeAndPassReceiver(), std::move(host_remote),
- base::BindLambdaForTesting(
- [&](drivefs::mojom::DriveFsDelegate::ExtensionConnectionStatus
- status) {
- EXPECT_EQ(drivefs::mojom::DriveFsDelegate::
- ExtensionConnectionStatus::kExtensionNotFound,
- status);
- run_loop.Quit();
- }));
- run_loop.Run();
- EXPECT_EQ("foo", host_delegate_->get_last_extension_params().extension_id);
- }
- TEST_F(DriveFsHostTest, OnMirrorSyncingStatusUpdate_ForwardToObservers) {
- ASSERT_NO_FATAL_FAILURE(DoMount());
- MockDriveFsHostObserver observer;
- base::ScopedObservation<DriveFsHost, DriveFsHostObserver> observation_scoper(
- &observer);
- observation_scoper.Observe(host_.get());
- auto status = mojom::SyncingStatus::New();
- status->item_events.emplace_back(absl::in_place, 12, 34, "filename.txt",
- mojom::ItemEvent::State::kInProgress, 123,
- 456, mojom::ItemEventReason::kPin);
- mojom::SyncingStatusPtr observed_status;
- EXPECT_CALL(observer, OnMirrorSyncingStatusUpdate(_))
- .WillOnce(CloneStruct(&observed_status));
- delegate_->OnMirrorSyncingStatusUpdate(status.Clone());
- delegate_.FlushForTesting();
- testing::Mock::VerifyAndClear(&observer);
- EXPECT_EQ(status, observed_status);
- }
- } // namespace
- } // namespace drivefs
|