Commit ce5bb691 authored by Sergei Datsenko's avatar Sergei Datsenko Committed by Commit Bot

Cache tokens inside DriveFsHost for remounts

If drivefs needs to restart there is no need to redo all the job for
oauth token minting as the previous one should still be good.

BUG=chromium:897558

Change-Id: I4e1737a94a70476c6312ff11c04b8f3f233e4512
Reviewed-on: https://chromium-review.googlesource.com/c/1293058
Commit-Queue: Sergei Datsenko <dats@chromium.org>
Reviewed-by: default avatarSam McNally <sammc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#601877}
parent 1b13290f
...@@ -464,6 +464,8 @@ class DriveIntegrationService::DriveFsHolder ...@@ -464,6 +464,8 @@ class DriveIntegrationService::DriveFsHolder
drivefs_host_(profile_->GetPath(), drivefs_host_(profile_->GetPath(),
this, this,
this, this,
base::DefaultClock::GetInstance(),
chromeos::disks::DiskMountManager::GetInstance(),
std::make_unique<base::OneShotTimer>()) {} std::make_unique<base::OneShotTimer>()) {}
drivefs::DriveFsHost* drivefs_host() { return &drivefs_host_; } drivefs::DriveFsHost* drivefs_host() { return &drivefs_host_; }
......
...@@ -71,6 +71,122 @@ DriveFsHost::Delegate::CreateMojoConnectionDelegate() { ...@@ -71,6 +71,122 @@ DriveFsHost::Delegate::CreateMojoConnectionDelegate() {
return std::make_unique<MojoConnectionDelegateImpl>(); return std::make_unique<MojoConnectionDelegateImpl>();
} }
class DriveFsHost::AccountTokenDelegate : public OAuth2MintTokenFlow::Delegate {
public:
explicit AccountTokenDelegate(DriveFsHost* host) : host_(host) {}
~AccountTokenDelegate() override = default;
void GetAccessToken(bool use_cached,
const std::string& client_id,
const std::string& app_id,
const std::vector<std::string>& scopes,
mojom::DriveFsDelegate::GetAccessTokenCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
if (get_access_token_callback_) {
std::move(callback).Run(mojom::AccessTokenStatus::kTransientError, "");
return;
}
DCHECK(!mint_token_flow_);
const std::string& token =
MaybeGetCachedToken(use_cached, client_id, app_id, scopes);
if (!token.empty()) {
std::move(callback).Run(mojom::AccessTokenStatus::kSuccess, token);
return;
}
get_access_token_callback_ = std::move(callback);
mint_token_flow_ =
host_->delegate_->CreateMintTokenFlow(this, client_id, app_id, scopes);
DCHECK(mint_token_flow_);
GetIdentityManager().GetPrimaryAccountWhenAvailable(base::BindOnce(
&AccountTokenDelegate::AccountReady, base::Unretained(this)));
}
private:
void AccountReady(const AccountInfo& info,
const identity::AccountState& state) {
GetIdentityManager().GetAccessToken(
host_->delegate_->GetAccountId().GetUserEmail(), {},
kIdentityConsumerId,
base::BindOnce(&AccountTokenDelegate::GotChromeAccessToken,
base::Unretained(this)));
}
void GotChromeAccessToken(const base::Optional<std::string>& access_token,
base::Time expiration_time,
const GoogleServiceAuthError& error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
if (!access_token) {
OnMintTokenFailure(error);
return;
}
mint_token_flow_->Start(host_->delegate_->GetURLLoaderFactory(),
*access_token);
}
// OAuth2MintTokenFlow::Delegate:
void OnMintTokenSuccess(const std::string& access_token,
int time_to_live) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
UpdateCachedToken(access_token, base::TimeDelta::FromSeconds(time_to_live));
std::move(get_access_token_callback_)
.Run(mojom::AccessTokenStatus::kSuccess, access_token);
mint_token_flow_.reset();
}
void OnMintTokenFailure(const GoogleServiceAuthError& error) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
std::move(get_access_token_callback_)
.Run(error.IsPersistentError()
? mojom::AccessTokenStatus::kAuthError
: mojom::AccessTokenStatus::kTransientError,
"");
mint_token_flow_.reset();
}
const std::string& MaybeGetCachedToken(
bool use_cached,
const std::string& client_id,
const std::string& app_id,
const std::vector<std::string>& scopes) {
// Return value from cache at most once per mount.
if (!use_cached || host_->clock_->Now() >= last_token_expiry_) {
last_token_.clear();
}
return last_token_;
}
void UpdateCachedToken(const std::string& token, const base::TimeDelta& ttl) {
last_token_ = token;
last_token_expiry_ = host_->clock_->Now() + ttl;
}
identity::mojom::IdentityManager& GetIdentityManager() {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
if (!identity_manager_) {
host_->delegate_->GetConnector()->BindInterface(
identity::mojom::kServiceName, mojo::MakeRequest(&identity_manager_));
}
return *identity_manager_;
}
// Owns |this|.
DriveFsHost* const host_;
// The connection to the identity service. Access via |GetIdentityManager()|.
identity::mojom::IdentityManagerPtr identity_manager_;
// Pending callback for an in-flight GetAccessToken request.
mojom::DriveFsDelegate::GetAccessTokenCallback get_access_token_callback_;
// The mint token flow, if one is in flight.
std::unique_ptr<OAuth2MintTokenFlow> mint_token_flow_;
std::string last_token_;
base::Time last_token_expiry_;
DISALLOW_COPY_AND_ASSIGN(AccountTokenDelegate);
};
// A container of state tied to a particular mounting of DriveFS. None of this // A container of state tied to a particular mounting of DriveFS. None of this
// should be shared between mounts. // should be shared between mounts.
class DriveFsHost::MountState class DriveFsHost::MountState
...@@ -85,7 +201,7 @@ class DriveFsHost::MountState ...@@ -85,7 +201,7 @@ class DriveFsHost::MountState
host_->delegate_->CreateMojoConnectionDelegate()), host_->delegate_->CreateMojoConnectionDelegate()),
pending_token_(base::UnguessableToken::Create()), pending_token_(base::UnguessableToken::Create()),
binding_(this) { binding_(this) {
chromeos::disks::DiskMountManager::GetInstance()->AddObserver(this); host_->disk_mount_manager_->AddObserver(this);
source_path_ = base::StrCat({kMountScheme, pending_token_.ToString()}); source_path_ = base::StrCat({kMountScheme, pending_token_.ToString()});
std::string datadir_option = std::string datadir_option =
base::StrCat({"datadir=", host_->GetDataPath().value()}); base::StrCat({"datadir=", host_->GetDataPath().value()});
...@@ -107,7 +223,7 @@ class DriveFsHost::MountState ...@@ -107,7 +223,7 @@ class DriveFsHost::MountState
base::BindOnce(&DriveFsHost::MountState::AcceptMojoConnection, base::BindOnce(&DriveFsHost::MountState::AcceptMojoConnection,
base::Unretained(this))); base::Unretained(this)));
chromeos::disks::DiskMountManager::GetInstance()->MountPath( host_->disk_mount_manager_->MountPath(
source_path_, "", source_path_, "",
base::StrCat({"drivefs-", host_->delegate_->GetObfuscatedAccountId()}), base::StrCat({"drivefs-", host_->delegate_->GetObfuscatedAccountId()}),
{datadir_option}, chromeos::MOUNT_TYPE_NETWORK_STORAGE, {datadir_option}, chromeos::MOUNT_TYPE_NETWORK_STORAGE,
...@@ -120,7 +236,7 @@ class DriveFsHost::MountState ...@@ -120,7 +236,7 @@ class DriveFsHost::MountState
~MountState() override { ~MountState() override {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
chromeos::disks::DiskMountManager::GetInstance()->RemoveObserver(this); host_->disk_mount_manager_->RemoveObserver(this);
host_->delegate_->GetDriveNotificationManager().RemoveObserver(this); host_->delegate_->GetDriveNotificationManager().RemoveObserver(this);
host_->timer_->Stop(); host_->timer_->Stop();
if (pending_token_) { if (pending_token_) {
...@@ -128,7 +244,7 @@ class DriveFsHost::MountState ...@@ -128,7 +244,7 @@ class DriveFsHost::MountState
pending_token_); pending_token_);
} }
if (!mount_path_.empty()) { if (!mount_path_.empty()) {
chromeos::disks::DiskMountManager::GetInstance()->UnmountPath( host_->disk_mount_manager_->UnmountPath(
mount_path_.value(), chromeos::UNMOUNT_OPTIONS_NONE, {}); mount_path_.value(), chromeos::UNMOUNT_OPTIONS_NONE, {});
} }
if (mounted()) { if (mounted()) {
...@@ -159,17 +275,10 @@ class DriveFsHost::MountState ...@@ -159,17 +275,10 @@ class DriveFsHost::MountState
const std::vector<std::string>& scopes, const std::vector<std::string>& scopes,
GetAccessTokenCallback callback) override { GetAccessTokenCallback callback) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
if (get_access_token_callback_) { host_->account_token_delegate_->GetAccessToken(!token_fetch_attempted_,
std::move(callback).Run(mojom::AccessTokenStatus::kTransientError, ""); client_id, app_id, scopes,
return; std::move(callback));
} token_fetch_attempted_ = true;
DCHECK(!mint_token_flow_);
get_access_token_callback_ = std::move(callback);
mint_token_flow_ =
host_->delegate_->CreateMintTokenFlow(this, client_id, app_id, scopes);
DCHECK(mint_token_flow_);
GetIdentityManager().GetPrimaryAccountWhenAvailable(base::BindOnce(
&DriveFsHost::MountState::AccountReady, base::Unretained(this)));
} }
void OnMounted() override { void OnMounted() override {
...@@ -262,55 +371,6 @@ class DriveFsHost::MountState ...@@ -262,55 +371,6 @@ class DriveFsHost::MountState
} }
} }
void AccountReady(const AccountInfo& info,
const identity::AccountState& state) {
GetIdentityManager().GetAccessToken(
host_->delegate_->GetAccountId().GetUserEmail(), {},
kIdentityConsumerId,
base::BindOnce(&DriveFsHost::MountState::GotChromeAccessToken,
base::Unretained(this)));
}
void GotChromeAccessToken(const base::Optional<std::string>& access_token,
base::Time expiration_time,
const GoogleServiceAuthError& error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
if (!access_token) {
OnMintTokenFailure(error);
return;
}
mint_token_flow_->Start(host_->delegate_->GetURLLoaderFactory(),
*access_token);
}
// OAuth2MintTokenFlow::Delegate:
void OnMintTokenSuccess(const std::string& access_token,
int time_to_live) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
std::move(get_access_token_callback_)
.Run(mojom::AccessTokenStatus::kSuccess, access_token);
mint_token_flow_.reset();
}
void OnMintTokenFailure(const GoogleServiceAuthError& error) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
std::move(get_access_token_callback_)
.Run(error.IsPersistentError()
? mojom::AccessTokenStatus::kAuthError
: mojom::AccessTokenStatus::kTransientError,
"");
mint_token_flow_.reset();
}
identity::mojom::IdentityManager& GetIdentityManager() {
DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
if (!identity_manager_) {
host_->delegate_->GetConnector()->BindInterface(
identity::mojom::kServiceName, mojo::MakeRequest(&identity_manager_));
}
return *identity_manager_;
}
// DiskMountManager::Observer: // DiskMountManager::Observer:
void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event, void OnMountEvent(chromeos::disks::DiskMountManager::MountEvent event,
chromeos::MountError error_code, chromeos::MountError error_code,
...@@ -365,21 +425,13 @@ class DriveFsHost::MountState ...@@ -365,21 +425,13 @@ class DriveFsHost::MountState
// The path where DriveFS is mounted. // The path where DriveFS is mounted.
base::FilePath mount_path_; base::FilePath mount_path_;
// Pending callback for an in-flight GetAccessToken request.
GetAccessTokenCallback get_access_token_callback_;
// The mint token flow, if one is in flight.
std::unique_ptr<OAuth2MintTokenFlow> mint_token_flow_;
// Mojo connections to the DriveFS process. // Mojo connections to the DriveFS process.
mojom::DriveFsPtr drivefs_; mojom::DriveFsPtr drivefs_;
mojo::Binding<mojom::DriveFsDelegate> binding_; mojo::Binding<mojom::DriveFsDelegate> binding_;
bool drivefs_has_mounted_ = false; bool drivefs_has_mounted_ = false;
bool drivefs_has_terminated_ = false; bool drivefs_has_terminated_ = false;
bool token_fetch_attempted_ = false;
// The connection to the identity service. Access via |GetIdentityManager()|.
identity::mojom::IdentityManagerPtr identity_manager_;
DISALLOW_COPY_AND_ASSIGN(MountState); DISALLOW_COPY_AND_ASSIGN(MountState);
}; };
...@@ -387,13 +439,19 @@ class DriveFsHost::MountState ...@@ -387,13 +439,19 @@ class DriveFsHost::MountState
DriveFsHost::DriveFsHost(const base::FilePath& profile_path, DriveFsHost::DriveFsHost(const base::FilePath& profile_path,
DriveFsHost::Delegate* delegate, DriveFsHost::Delegate* delegate,
DriveFsHost::MountObserver* mount_observer, DriveFsHost::MountObserver* mount_observer,
const base::Clock* clock,
chromeos::disks::DiskMountManager* disk_mount_manager,
std::unique_ptr<base::OneShotTimer> timer) std::unique_ptr<base::OneShotTimer> timer)
: profile_path_(profile_path), : profile_path_(profile_path),
delegate_(delegate), delegate_(delegate),
mount_observer_(mount_observer), mount_observer_(mount_observer),
timer_(std::move(timer)) { clock_(clock),
disk_mount_manager_(disk_mount_manager),
timer_(std::move(timer)),
account_token_delegate_(std::make_unique<AccountTokenDelegate>(this)) {
DCHECK(delegate_); DCHECK(delegate_);
DCHECK(mount_observer_); DCHECK(mount_observer_);
DCHECK(clock_);
} }
DriveFsHost::~DriveFsHost() { DriveFsHost::~DriveFsHost() {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/scoped_file.h" #include "base/files/scoped_file.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/time/clock.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "chromeos/components/drivefs/mojom/drivefs.mojom.h" #include "chromeos/components/drivefs/mojom/drivefs.mojom.h"
#include "chromeos/disks/disk_mount_manager.h" #include "chromeos/disks/disk_mount_manager.h"
...@@ -32,6 +33,12 @@ namespace service_manager { ...@@ -32,6 +33,12 @@ namespace service_manager {
class Connector; class Connector;
} // namespace service_manager } // namespace service_manager
namespace chromeos {
namespace disks {
class DiskMountManager;
}
} // namespace chromeos
namespace drivefs { namespace drivefs {
class DriveFsHostObserver; class DriveFsHostObserver;
...@@ -94,6 +101,8 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsHost { ...@@ -94,6 +101,8 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsHost {
DriveFsHost(const base::FilePath& profile_path, DriveFsHost(const base::FilePath& profile_path,
Delegate* delegate, Delegate* delegate,
MountObserver* mount_observer, MountObserver* mount_observer,
const base::Clock* clock,
chromeos::disks::DiskMountManager* disk_mount_manager,
std::unique_ptr<base::OneShotTimer> timer); std::unique_ptr<base::OneShotTimer> timer);
~DriveFsHost(); ~DriveFsHost();
...@@ -118,6 +127,7 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsHost { ...@@ -118,6 +127,7 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsHost {
mojom::DriveFs* GetDriveFsInterface() const; mojom::DriveFs* GetDriveFsInterface() const;
private: private:
class AccountTokenDelegate;
class MountState; class MountState;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
...@@ -127,9 +137,12 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsHost { ...@@ -127,9 +137,12 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsHost {
Delegate* const delegate_; Delegate* const delegate_;
MountObserver* const mount_observer_; MountObserver* const mount_observer_;
const base::Clock* const clock_;
chromeos::disks::DiskMountManager* const disk_mount_manager_;
std::unique_ptr<base::OneShotTimer> timer_; std::unique_ptr<base::OneShotTimer> timer_;
std::unique_ptr<AccountTokenDelegate> account_token_delegate_;
// State specific to the current mount, or null if not mounted. // State specific to the current mount, or null if not mounted.
std::unique_ptr<MountState> mount_state_; std::unique_ptr<MountState> mount_state_;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "base/test/simple_test_clock.h"
#include "base/timer/mock_timer.h" #include "base/timer/mock_timer.h"
#include "chromeos/components/drivefs/drivefs_host_observer.h" #include "chromeos/components/drivefs/drivefs_host_observer.h"
#include "chromeos/components/drivefs/pending_connection_manager.h" #include "chromeos/components/drivefs/pending_connection_manager.h"
...@@ -57,8 +58,10 @@ class ForwardingOAuth2MintTokenFlow; ...@@ -57,8 +58,10 @@ class ForwardingOAuth2MintTokenFlow;
ACTION_P(SucceedMintToken, token) { ACTION_P(SucceedMintToken, token) {
base::SequencedTaskRunnerHandle::Get()->PostTask( base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, FROM_HERE, base::BindLambdaForTesting([=] {
base::BindLambdaForTesting([=] { arg0->OnMintTokenSuccess(token, 0); })); arg0->OnMintTokenSuccess(token,
base::TimeDelta::FromHours(1).InSeconds());
}));
} }
ACTION_P(FailMintToken, error) { ACTION_P(FailMintToken, error) {
...@@ -85,12 +88,13 @@ class MockOAuth2MintTokenFlow { ...@@ -85,12 +88,13 @@ class MockOAuth2MintTokenFlow {
void ExpectNoStartCalls() { EXPECT_CALL(*this, Start(_, _)).Times(0); } void ExpectNoStartCalls() { EXPECT_CALL(*this, Start(_, _)).Times(0); }
private:
friend class ForwardingOAuth2MintTokenFlow;
MOCK_METHOD2(Start, MOCK_METHOD2(Start,
void(OAuth2MintTokenFlow::Delegate* delegate, void(OAuth2MintTokenFlow::Delegate* delegate,
const std::string& access_token)); const std::string& access_token));
private:
friend class ForwardingOAuth2MintTokenFlow;
DISALLOW_COPY_AND_ASSIGN(MockOAuth2MintTokenFlow); DISALLOW_COPY_AND_ASSIGN(MockOAuth2MintTokenFlow);
}; };
...@@ -221,7 +225,9 @@ class FakeIdentityService ...@@ -221,7 +225,9 @@ class FakeIdentityService
: public identity::mojom::IdentityManagerInterceptorForTesting, : public identity::mojom::IdentityManagerInterceptorForTesting,
public service_manager::Service { public service_manager::Service {
public: public:
explicit FakeIdentityService(MockIdentityManager* mock) : mock_(mock) { explicit FakeIdentityService(MockIdentityManager* mock,
const base::Clock* clock)
: mock_(mock), clock_(clock) {
binder_registry_.AddInterface( binder_registry_.AddInterface(
base::BindRepeating(&FakeIdentityService::BindIdentityManagerRequest, base::BindRepeating(&FakeIdentityService::BindIdentityManagerRequest,
base::Unretained(this))); base::Unretained(this)));
...@@ -258,7 +264,7 @@ class FakeIdentityService ...@@ -258,7 +264,7 @@ class FakeIdentityService
const std::string& consumer_id, const std::string& consumer_id,
GetAccessTokenCallback callback) override { GetAccessTokenCallback callback) override {
auto result = mock_->GetAccessToken(account_id, scopes, consumer_id); auto result = mock_->GetAccessToken(account_id, scopes, consumer_id);
std::move(callback).Run(std::move(result.first), base::Time::Now(), std::move(callback).Run(std::move(result.first), clock_->Now(),
GoogleServiceAuthError(result.second)); GoogleServiceAuthError(result.second));
} }
...@@ -268,6 +274,7 @@ class FakeIdentityService ...@@ -268,6 +274,7 @@ class FakeIdentityService
} }
MockIdentityManager* const mock_; MockIdentityManager* const mock_;
const base::Clock* const clock_;
service_manager::BinderRegistry binder_registry_; service_manager::BinderRegistry binder_registry_;
mojo::BindingSet<identity::mojom::IdentityManager> bindings_; mojo::BindingSet<identity::mojom::IdentityManager> bindings_;
...@@ -297,25 +304,23 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap { ...@@ -297,25 +304,23 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
profile_path_ = base::FilePath(FILE_PATH_LITERAL("/path/to/profile")); profile_path_ = base::FilePath(FILE_PATH_LITERAL("/path/to/profile"));
account_id_ = AccountId::FromUserEmailGaiaId("test@example.com", "ID"); account_id_ = AccountId::FromUserEmailGaiaId("test@example.com", "ID");
disk_manager_ = new chromeos::disks::MockDiskMountManager; disk_manager_ = std::make_unique<chromeos::disks::MockDiskMountManager>();
// Takes ownership of |disk_manager_|.
chromeos::disks::DiskMountManager::InitializeForTesting(disk_manager_);
connector_factory_ = connector_factory_ =
service_manager::TestConnectorFactory::CreateForUniqueService( service_manager::TestConnectorFactory::CreateForUniqueService(
std::make_unique<FakeIdentityService>(&mock_identity_manager_)); std::make_unique<FakeIdentityService>(&mock_identity_manager_,
&clock_));
host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>( host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>(
connector_factory_->CreateConnector(), account_id_); connector_factory_->CreateConnector(), account_id_);
auto timer = std::make_unique<base::MockOneShotTimer>(); auto timer = std::make_unique<base::MockOneShotTimer>();
timer_ = timer.get(); timer_ = timer.get();
host_ = host_ = std::make_unique<DriveFsHost>(
std::make_unique<DriveFsHost>(profile_path_, host_delegate_.get(), profile_path_, host_delegate_.get(), host_delegate_.get(), &clock_,
host_delegate_.get(), std::move(timer)); disk_manager_.get(), std::move(timer));
} }
void TearDown() override { void TearDown() override {
host_.reset(); host_.reset();
disk_manager_ = nullptr; disk_manager_.reset();
chromeos::disks::DiskMountManager::Shutdown();
} }
void DispatchMountEvent( void DispatchMountEvent(
...@@ -384,11 +389,38 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap { ...@@ -384,11 +389,38 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
EXPECT_CALL(*host_delegate_, EXPECT_CALL(*host_delegate_,
OnMounted(base::FilePath("/media/drivefsroot/salt-g-ID"))) OnMounted(base::FilePath("/media/drivefsroot/salt-g-ID")))
.WillOnce(RunQuitClosure(&quit_closure)); .WillOnce(RunQuitClosure(&quit_closure));
// Eventually we must attempt unmount.
EXPECT_CALL(*disk_manager_, UnmountPath("/media/drivefsroot/salt-g-ID",
chromeos::UNMOUNT_OPTIONS_NONE, _));
SendOnMounted(); SendOnMounted();
run_loop.Run(); run_loop.Run();
ASSERT_TRUE(host_->IsMounted()); ASSERT_TRUE(host_->IsMounted());
} }
void DoUnmount() {
host_->Unmount();
binding_.Unbind();
bootstrap_binding_.Unbind();
delegate_ptr_.reset();
base::RunLoop().RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(disk_manager_.get());
}
void ExpectAccessToken(mojom::AccessTokenStatus expected_status,
const std::string& expected_token) {
base::RunLoop run_loop;
auto quit_closure = run_loop.QuitClosure();
delegate_ptr_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"},
base::BindLambdaForTesting(
[&](mojom::AccessTokenStatus status, const std::string& token) {
EXPECT_EQ(expected_status, status);
EXPECT_EQ(expected_token, token);
std::move(quit_closure).Run();
}));
run_loop.Run();
}
void Init(mojom::DriveFsConfigurationPtr config, void Init(mojom::DriveFsConfigurationPtr config,
mojom::DriveFsRequest drive_fs_request, mojom::DriveFsRequest drive_fs_request,
mojom::DriveFsDelegatePtr delegate) override { mojom::DriveFsDelegatePtr delegate) override {
...@@ -401,7 +433,8 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap { ...@@ -401,7 +433,8 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
base::FilePath profile_path_; base::FilePath profile_path_;
base::test::ScopedTaskEnvironment task_environment_; base::test::ScopedTaskEnvironment task_environment_;
AccountId account_id_; AccountId account_id_;
chromeos::disks::MockDiskMountManager* disk_manager_; std::unique_ptr<chromeos::disks::MockDiskMountManager> disk_manager_;
base::SimpleTestClock clock_;
MockIdentityManager mock_identity_manager_; MockIdentityManager mock_identity_manager_;
std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_; std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
std::unique_ptr<TestingDriveFsHostDelegate> host_delegate_; std::unique_ptr<TestingDriveFsHostDelegate> host_delegate_;
...@@ -428,6 +461,8 @@ TEST_F(DriveFsHostTest, Basic) { ...@@ -428,6 +461,8 @@ TEST_F(DriveFsHostTest, Basic) {
EXPECT_EQ(base::FilePath("/media/drivefsroot/salt-g-ID"), EXPECT_EQ(base::FilePath("/media/drivefsroot/salt-g-ID"),
host_->GetMountPath()); host_->GetMountPath());
DoUnmount();
} }
TEST_F(DriveFsHostTest, GetMountPathWhileUnmounted) { TEST_F(DriveFsHostTest, GetMountPathWhileUnmounted) {
...@@ -448,12 +483,16 @@ TEST_F(DriveFsHostTest, OnMountedBeforeMountEvent) { ...@@ -448,12 +483,16 @@ TEST_F(DriveFsHostTest, OnMountedBeforeMountEvent) {
EXPECT_CALL(*host_delegate_, EXPECT_CALL(*host_delegate_,
OnMounted(base::FilePath("/media/drivefsroot/salt-g-ID"))); OnMounted(base::FilePath("/media/drivefsroot/salt-g-ID")));
EXPECT_CALL(*disk_manager_, UnmountPath("/media/drivefsroot/salt-g-ID",
chromeos::UNMOUNT_OPTIONS_NONE, _));
DispatchMountSuccessEvent(token); DispatchMountSuccessEvent(token);
ASSERT_TRUE(host_->IsMounted()); ASSERT_TRUE(host_->IsMounted());
EXPECT_EQ(base::FilePath("/media/drivefsroot/salt-g-ID"), EXPECT_EQ(base::FilePath("/media/drivefsroot/salt-g-ID"),
host_->GetMountPath()); host_->GetMountPath());
DoUnmount();
} }
TEST_F(DriveFsHostTest, OnMountFailedFromMojo) { TEST_F(DriveFsHostTest, OnMountFailedFromMojo) {
...@@ -519,8 +558,6 @@ TEST_F(DriveFsHostTest, UnmountAfterMountComplete) { ...@@ -519,8 +558,6 @@ TEST_F(DriveFsHostTest, UnmountAfterMountComplete) {
ASSERT_NO_FATAL_FAILURE(DoMount()); ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_CALL(*disk_manager_, UnmountPath("/media/drivefsroot/salt-g-ID",
chromeos::UNMOUNT_OPTIONS_NONE, _));
EXPECT_CALL(observer, OnUnmounted()); EXPECT_CALL(observer, OnUnmounted());
base::RunLoop run_loop; base::RunLoop run_loop;
delegate_ptr_.set_connection_error_handler(run_loop.QuitClosure()); delegate_ptr_.set_connection_error_handler(run_loop.QuitClosure());
...@@ -598,6 +635,7 @@ TEST_F(DriveFsHostTest, ObserveOtherMount) { ...@@ -598,6 +635,7 @@ TEST_F(DriveFsHostTest, ObserveOtherMount) {
TEST_F(DriveFsHostTest, MountError) { TEST_F(DriveFsHostTest, MountError) {
auto token = StartMount(); auto token = StartMount();
EXPECT_CALL(*disk_manager_, UnmountPath(_, _, _)).Times(0); EXPECT_CALL(*disk_manager_, UnmountPath(_, _, _)).Times(0);
EXPECT_CALL(*host_delegate_, OnMountFailed(_));
DispatchMountEvent(chromeos::disks::DiskMountManager::MOUNTING, DispatchMountEvent(chromeos::disks::DiskMountManager::MOUNTING,
chromeos::MOUNT_ERROR_DIRECTORY_CREATION_FAILED, chromeos::MOUNT_ERROR_DIRECTORY_CREATION_FAILED,
...@@ -662,8 +700,8 @@ TEST_F(DriveFsHostTest, UnsupportedAccountTypes) { ...@@ -662,8 +700,8 @@ TEST_F(DriveFsHostTest, UnsupportedAccountTypes) {
host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>( host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>(
connector_factory_->CreateConnector(), account); connector_factory_->CreateConnector(), account);
host_ = std::make_unique<DriveFsHost>( host_ = std::make_unique<DriveFsHost>(
profile_path_, host_delegate_.get(), host_delegate_.get(), profile_path_, host_delegate_.get(), host_delegate_.get(), &clock_,
std::make_unique<base::MockOneShotTimer>()); disk_manager_.get(), std::make_unique<base::MockOneShotTimer>());
EXPECT_FALSE(host_->Mount()); EXPECT_FALSE(host_->Mount());
EXPECT_FALSE(host_->IsMounted()); EXPECT_FALSE(host_->IsMounted());
} }
...@@ -679,17 +717,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_Success) { ...@@ -679,17 +717,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_Success) {
host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token", host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token",
"auth token"); "auth token");
base::RunLoop run_loop; ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token");
auto quit_closure = run_loop.QuitClosure();
delegate_ptr_->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);
std::move(quit_closure).Run();
}));
run_loop.Run();
} }
TEST_F(DriveFsHostTest, GetAccessToken_ParallelRequests) { TEST_F(DriveFsHostTest, GetAccessToken_ParallelRequests) {
...@@ -724,18 +752,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_SequentialRequests) { ...@@ -724,18 +752,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_SequentialRequests) {
std::make_pair("chrome token", GoogleServiceAuthError::NONE))); std::make_pair("chrome token", GoogleServiceAuthError::NONE)));
host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token", host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token",
"auth token"); "auth token");
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token");
base::RunLoop run_loop;
auto quit_closure = run_loop.QuitClosure();
delegate_ptr_->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);
std::move(quit_closure).Run();
}));
run_loop.Run();
} }
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
EXPECT_CALL(mock_identity_manager_, EXPECT_CALL(mock_identity_manager_,
...@@ -743,18 +760,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_SequentialRequests) { ...@@ -743,18 +760,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_SequentialRequests) {
.WillOnce(testing::Return(std::make_pair( .WillOnce(testing::Return(std::make_pair(
base::nullopt, GoogleServiceAuthError::ACCOUNT_DISABLED))); base::nullopt, GoogleServiceAuthError::ACCOUNT_DISABLED)));
host_delegate_->mock_flow().ExpectNoStartCalls(); host_delegate_->mock_flow().ExpectNoStartCalls();
ExpectAccessToken(mojom::AccessTokenStatus::kAuthError, "");
base::RunLoop run_loop;
auto quit_closure = run_loop.QuitClosure();
delegate_ptr_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"},
base::BindLambdaForTesting(
[&](mojom::AccessTokenStatus status, const std::string& token) {
EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status);
EXPECT_TRUE(token.empty());
std::move(quit_closure).Run();
}));
run_loop.Run();
} }
} }
...@@ -766,18 +772,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_GetAccessTokenFailure_Permanent) { ...@@ -766,18 +772,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_GetAccessTokenFailure_Permanent) {
.WillOnce(testing::Return(std::make_pair( .WillOnce(testing::Return(std::make_pair(
base::nullopt, GoogleServiceAuthError::ACCOUNT_DISABLED))); base::nullopt, GoogleServiceAuthError::ACCOUNT_DISABLED)));
host_delegate_->mock_flow().ExpectNoStartCalls(); host_delegate_->mock_flow().ExpectNoStartCalls();
ExpectAccessToken(mojom::AccessTokenStatus::kAuthError, "");
base::RunLoop run_loop;
auto quit_closure = run_loop.QuitClosure();
delegate_ptr_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"},
base::BindLambdaForTesting(
[&](mojom::AccessTokenStatus status, const std::string& token) {
EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status);
EXPECT_TRUE(token.empty());
std::move(quit_closure).Run();
}));
run_loop.Run();
} }
TEST_F(DriveFsHostTest, GetAccessToken_GetAccessTokenFailure_Transient) { TEST_F(DriveFsHostTest, GetAccessToken_GetAccessTokenFailure_Transient) {
...@@ -788,18 +783,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_GetAccessTokenFailure_Transient) { ...@@ -788,18 +783,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_GetAccessTokenFailure_Transient) {
.WillOnce(testing::Return(std::make_pair( .WillOnce(testing::Return(std::make_pair(
base::nullopt, GoogleServiceAuthError::SERVICE_UNAVAILABLE))); base::nullopt, GoogleServiceAuthError::SERVICE_UNAVAILABLE)));
host_delegate_->mock_flow().ExpectNoStartCalls(); host_delegate_->mock_flow().ExpectNoStartCalls();
ExpectAccessToken(mojom::AccessTokenStatus::kTransientError, "");
base::RunLoop run_loop;
auto quit_closure = run_loop.QuitClosure();
delegate_ptr_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"},
base::BindLambdaForTesting(
[&](mojom::AccessTokenStatus status, const std::string& token) {
EXPECT_EQ(mojom::AccessTokenStatus::kTransientError, status);
EXPECT_TRUE(token.empty());
std::move(quit_closure).Run();
}));
run_loop.Run();
} }
TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Permanent) { TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Permanent) {
...@@ -811,18 +795,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Permanent) { ...@@ -811,18 +795,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Permanent) {
std::make_pair("chrome token", GoogleServiceAuthError::NONE))); std::make_pair("chrome token", GoogleServiceAuthError::NONE)));
host_delegate_->mock_flow().ExpectStartAndFail( host_delegate_->mock_flow().ExpectStartAndFail(
"chrome token", GoogleServiceAuthError::ACCOUNT_DISABLED); "chrome token", GoogleServiceAuthError::ACCOUNT_DISABLED);
ExpectAccessToken(mojom::AccessTokenStatus::kAuthError, "");
base::RunLoop run_loop;
auto quit_closure = run_loop.QuitClosure();
delegate_ptr_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"},
base::BindLambdaForTesting(
[&](mojom::AccessTokenStatus status, const std::string& token) {
EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status);
EXPECT_TRUE(token.empty());
std::move(quit_closure).Run();
}));
run_loop.Run();
} }
TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Transient) { TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Transient) {
...@@ -834,18 +807,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Transient) { ...@@ -834,18 +807,7 @@ TEST_F(DriveFsHostTest, GetAccessToken_MintTokenFailure_Transient) {
std::make_pair("chrome token", GoogleServiceAuthError::NONE))); std::make_pair("chrome token", GoogleServiceAuthError::NONE)));
host_delegate_->mock_flow().ExpectStartAndFail( host_delegate_->mock_flow().ExpectStartAndFail(
"chrome token", GoogleServiceAuthError::SERVICE_UNAVAILABLE); "chrome token", GoogleServiceAuthError::SERVICE_UNAVAILABLE);
ExpectAccessToken(mojom::AccessTokenStatus::kTransientError, "");
base::RunLoop run_loop;
auto quit_closure = run_loop.QuitClosure();
delegate_ptr_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"},
base::BindLambdaForTesting(
[&](mojom::AccessTokenStatus status, const std::string& token) {
EXPECT_EQ(mojom::AccessTokenStatus::kTransientError, status);
EXPECT_TRUE(token.empty());
std::move(quit_closure).Run();
}));
run_loop.Run();
} }
TEST_F(DriveFsHostTest, GetAccessToken_UnmountDuringMojoRequest) { TEST_F(DriveFsHostTest, GetAccessToken_UnmountDuringMojoRequest) {
...@@ -1026,5 +988,124 @@ TEST_F(DriveFsHostTest, RemoveDriveNotificationObserver) { ...@@ -1026,5 +988,124 @@ TEST_F(DriveFsHostTest, RemoveDriveNotificationObserver) {
.might_have_observers()); .might_have_observers());
} }
TEST_F(DriveFsHostTest, Remount_Cached) {
ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_CALL(mock_identity_manager_,
GetAccessToken("test@example.com", _, "drivefs"))
.WillOnce(testing::Return(
std::make_pair("chrome token", GoogleServiceAuthError::NONE)));
host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token",
"auth token");
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token");
base::Optional<base::TimeDelta> delay = base::TimeDelta::FromSeconds(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());
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token");
}
TEST_F(DriveFsHostTest, Remount_CachedOnceOnly) {
ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_CALL(mock_identity_manager_,
GetAccessToken("test@example.com", _, "drivefs"))
.WillOnce(testing::Return(
std::make_pair("chrome token", GoogleServiceAuthError::NONE)))
.WillOnce(testing::Return(
std::make_pair("chrome token 2", GoogleServiceAuthError::NONE)));
host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token",
"auth token");
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token");
base::Optional<base::TimeDelta> delay = base::TimeDelta::FromSeconds(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());
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token");
// But if it asks for token more than once it goes straight to identity.
host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token 2",
"auth token 2");
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token 2");
}
TEST_F(DriveFsHostTest, Remount_CacheExpired) {
ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_CALL(mock_identity_manager_,
GetAccessToken("test@example.com", _, "drivefs"))
.WillOnce(testing::Return(
std::make_pair("chrome token", GoogleServiceAuthError::NONE)))
.WillOnce(testing::Return(
std::make_pair("chrome token 2", GoogleServiceAuthError::NONE)));
host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token",
"auth token");
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token");
base::Optional<base::TimeDelta> delay = base::TimeDelta::FromSeconds(5);
EXPECT_CALL(*host_delegate_, OnUnmounted(delay));
SendOnUnmounted(delay);
base::RunLoop().RunUntilIdle();
ASSERT_NO_FATAL_FAILURE(DoUnmount());
clock_.Advance(base::TimeDelta::FromHours(2));
// As the token expired second mount should go to identity.
ASSERT_NO_FATAL_FAILURE(DoMount());
host_delegate_->mock_flow().ExpectStartAndSucceed("chrome token 2",
"auth token 2");
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token 2");
}
TEST_F(DriveFsHostTest, Remount_RequestInflight) {
ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_CALL(mock_identity_manager_,
GetAccessToken("test@example.com", _, "drivefs"))
.WillOnce(testing::Return(
std::make_pair("chrome token", GoogleServiceAuthError::NONE)));
OAuth2MintTokenFlow::Delegate* delegate = nullptr;
EXPECT_CALL(host_delegate_->mock_flow(), Start(_, "chrome token"))
.WillOnce(testing::SaveArg<0>(&delegate));
delegate_ptr_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"},
base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
const std::string& token) { FAIL(); }));
base::Optional<base::TimeDelta> delay = base::TimeDelta::FromSeconds(5);
EXPECT_CALL(*host_delegate_, OnUnmounted(delay));
SendOnUnmounted(delay);
base::RunLoop().RunUntilIdle();
ASSERT_NO_FATAL_FAILURE(DoUnmount());
// Now the response is ready.
delegate->OnMintTokenSuccess("auth token",
base::TimeDelta::FromHours(1).InSeconds());
// Second mount will reuse previous token.
ASSERT_NO_FATAL_FAILURE(DoMount());
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token");
}
} // namespace } // namespace
} // namespace drivefs } // namespace drivefs
...@@ -56,22 +56,16 @@ std::unique_ptr<Disk::Builder> MakeDiskBuilder() { ...@@ -56,22 +56,16 @@ std::unique_ptr<Disk::Builder> MakeDiskBuilder() {
} // namespace } // namespace
void MockDiskMountManager::AddObserverInternal( void MockDiskMountManager::AddObserver(DiskMountManager::Observer* observer) {
DiskMountManager::Observer* observer) {
observers_.AddObserver(observer); observers_.AddObserver(observer);
} }
void MockDiskMountManager::RemoveObserverInternal( void MockDiskMountManager::RemoveObserver(
DiskMountManager::Observer* observer) { DiskMountManager::Observer* observer) {
observers_.RemoveObserver(observer); observers_.RemoveObserver(observer);
} }
MockDiskMountManager::MockDiskMountManager() { MockDiskMountManager::MockDiskMountManager() {
ON_CALL(*this, AddObserver(_))
.WillByDefault(Invoke(this, &MockDiskMountManager::AddObserverInternal));
ON_CALL(*this, RemoveObserver(_))
.WillByDefault(Invoke(this,
&MockDiskMountManager::RemoveObserverInternal));
ON_CALL(*this, disks()) ON_CALL(*this, disks())
.WillByDefault(Invoke(this, &MockDiskMountManager::disksInternal)); .WillByDefault(Invoke(this, &MockDiskMountManager::disksInternal));
ON_CALL(*this, mount_points()) ON_CALL(*this, mount_points())
...@@ -137,10 +131,6 @@ void MockDiskMountManager::NotifyMountEvent(MountEvent event, ...@@ -137,10 +131,6 @@ void MockDiskMountManager::NotifyMountEvent(MountEvent event,
} }
void MockDiskMountManager::SetupDefaultReplies() { void MockDiskMountManager::SetupDefaultReplies() {
EXPECT_CALL(*this, AddObserver(_))
.Times(AnyNumber());
EXPECT_CALL(*this, RemoveObserver(_))
.Times(AnyNumber());
EXPECT_CALL(*this, disks()) EXPECT_CALL(*this, disks())
.WillRepeatedly(ReturnRef(disks_)); .WillRepeatedly(ReturnRef(disks_));
EXPECT_CALL(*this, mount_points()) EXPECT_CALL(*this, mount_points())
......
...@@ -28,8 +28,8 @@ class MockDiskMountManager : public DiskMountManager { ...@@ -28,8 +28,8 @@ class MockDiskMountManager : public DiskMountManager {
// DiskMountManager override. // DiskMountManager override.
MOCK_METHOD0(Init, void(void)); MOCK_METHOD0(Init, void(void));
MOCK_METHOD1(AddObserver, void(DiskMountManager::Observer*)); void AddObserver(DiskMountManager::Observer*) override;
MOCK_METHOD1(RemoveObserver, void(DiskMountManager::Observer*)); void RemoveObserver(DiskMountManager::Observer*) override;
MOCK_CONST_METHOD0(disks, const DiskMountManager::DiskMap&(void)); MOCK_CONST_METHOD0(disks, const DiskMountManager::DiskMap&(void));
MOCK_CONST_METHOD1(FindDiskBySourcePath, const Disk*(const std::string&)); MOCK_CONST_METHOD1(FindDiskBySourcePath, const Disk*(const std::string&));
MOCK_CONST_METHOD0(mount_points, MOCK_CONST_METHOD0(mount_points,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment