Commit c2afb9b8 authored by James Cook's avatar James Cook Committed by Commit Bot

chromeos: Migrate DriveFS off the mojo Identity Service

The code in //chromeos/components/drivefs runs in the browser process
on the UI thread. There aren't any plans to move it out of process.
It can directly use the C++ IdentityManager instead of using the mojo
Identity Service. This will eliminate the last client of the Identity
Service, making it easier to refactor or delete it.

Convert DriveFsAuth to use PrimaryAccountAccessTokenFetcher, which
automatically handles waiting for / getting information about the
primary account.

Migrate the tests to use IdentityTestEnvironment, specifically the
helpers for access token requests. This requires rewriting tests
that used GMock on the Identity Service mojo API, but ends up being
less code overall.

Test: rewrite the chromeos_components_unittests
Test: Google Drive still works in File Manager to read / write / copy
      files.
Bug: 1054673

Change-Id: If83be823ee2ab1936289e21b2c50451004557c17
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2063419
Commit-Queue: James Cook <jamescook@chromium.org>
Reviewed-by: default avatarAustin Tankiang <austinct@chromium.org>
Reviewed-by: default avatarColin Blundell <blundell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#744097}
parent 60e93eb9
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include "components/metrics/metrics_pref_names.h" #include "components/metrics/metrics_pref_names.h"
#include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/user_manager/user.h" #include "components/user_manager/user.h"
#include "components/version_info/version_info.h" #include "components/version_info/version_info.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
...@@ -60,7 +61,6 @@ ...@@ -60,7 +61,6 @@
#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/traffic_annotation/network_traffic_annotation.h" #include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h" #include "services/device/public/mojom/wake_lock_provider.mojom.h"
#include "services/identity/public/mojom/identity_service.mojom.h"
#include "services/network/public/cpp/network_connection_tracker.h" #include "services/network/public/cpp/network_connection_tracker.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/connector.h"
...@@ -456,12 +456,8 @@ class DriveIntegrationService::DriveFsHolder ...@@ -456,12 +456,8 @@ class DriveIntegrationService::DriveFsHolder
return profile_->GetURLLoaderFactory(); return profile_->GetURLLoaderFactory();
} }
void BindIdentityAccessor( signin::IdentityManager* GetIdentityManager() override {
mojo::PendingReceiver<identity::mojom::IdentityAccessor> receiver) return IdentityManagerFactory::GetForProfile(profile_);
override {
auto* service = profile_->GetIdentityService();
if (service)
service->BindIdentityAccessor(std::move(receiver));
} }
const AccountId& GetAccountId() override { const AccountId& GetAccountId() override {
......
...@@ -30,12 +30,12 @@ component("drivefs") { ...@@ -30,12 +30,12 @@ component("drivefs") {
"//chromeos/disks", "//chromeos/disks",
"//components/account_id", "//components/account_id",
"//components/drive", "//components/drive",
"//components/signin/public/identity_manager",
"//dbus", "//dbus",
"//google_apis", "//google_apis",
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
"//mojo/public/cpp/platform", "//mojo/public/cpp/platform",
"//net", "//net",
"//services/identity/public/mojom",
"//services/network/public/cpp:cpp", "//services/network/public/cpp:cpp",
] ]
defines = [ "IS_DRIVEFS_IMPL" ] defines = [ "IS_DRIVEFS_IMPL" ]
...@@ -77,10 +77,11 @@ source_set("unit_tests") { ...@@ -77,10 +77,11 @@ source_set("unit_tests") {
"//components/account_id", "//components/account_id",
"//components/drive", "//components/drive",
"//components/invalidation/impl:test_support", "//components/invalidation/impl:test_support",
"//components/signin/public/identity_manager",
"//components/signin/public/identity_manager:test_support",
"//mojo/public/cpp/bindings", "//mojo/public/cpp/bindings",
"//net", "//net",
"//net:test_support", "//net:test_support",
"//services/identity/public/mojom",
"//services/network:test_support", "//services/network:test_support",
"//services/network/public/cpp:cpp", "//services/network/public/cpp:cpp",
"//testing/gmock", "//testing/gmock",
......
include_rules = [ include_rules = [
"+components/drive", "+components/drive",
"+components/invalidation/impl/fake_invalidation_service.h", "+components/invalidation/impl/fake_invalidation_service.h",
"+components/signin",
"+mojo/public", "+mojo/public",
"+services/identity/public",
] ]
...@@ -6,6 +6,11 @@ ...@@ -6,6 +6,11 @@
#include "base/bind.h" #include "base/bind.h"
#include "components/account_id/account_id.h" #include "components/account_id/account_id.h"
#include "components/signin/public/identity_manager/access_token_info.h"
#include "components/signin/public/identity_manager/consent_level.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
namespace drivefs { namespace drivefs {
...@@ -23,7 +28,7 @@ DriveFsAuth::DriveFsAuth(const base::Clock* clock, ...@@ -23,7 +28,7 @@ DriveFsAuth::DriveFsAuth(const base::Clock* clock,
timer_(std::move(timer)), timer_(std::move(timer)),
delegate_(delegate) {} delegate_(delegate) {}
DriveFsAuth::~DriveFsAuth() {} DriveFsAuth::~DriveFsAuth() = default;
base::Optional<std::string> DriveFsAuth::GetCachedAccessToken() { base::Optional<std::string> DriveFsAuth::GetCachedAccessToken() {
const auto& token = GetOrResetCachedToken(true); const auto& token = GetOrResetCachedToken(true);
...@@ -48,35 +53,32 @@ void DriveFsAuth::GetAccessToken( ...@@ -48,35 +53,32 @@ void DriveFsAuth::GetAccessToken(
return; return;
} }
signin::IdentityManager* identity_manager = delegate_->GetIdentityManager();
if (!identity_manager) {
std::move(callback).Run(mojom::AccessTokenStatus::kAuthError, "");
return;
}
get_access_token_callback_ = std::move(callback); get_access_token_callback_ = std::move(callback);
timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(30), // Timer is cancelled when it is destroyed, so use base::Unretained().
base::BindOnce(&DriveFsAuth::AuthTimeout, timer_->Start(
weak_ptr_factory_.GetWeakPtr())); FROM_HERE, base::TimeDelta::FromSeconds(30),
GetIdentityAccessor()->GetUnconsentedPrimaryAccountWhenAvailable( base::BindOnce(&DriveFsAuth::AuthTimeout, base::Unretained(this)));
base::BindOnce(&DriveFsAuth::AccountReady, std::set<std::string> scopes({"https://www.googleapis.com/auth/drive"});
weak_ptr_factory_.GetWeakPtr())); access_token_fetcher_ =
} std::make_unique<signin::PrimaryAccountAccessTokenFetcher>(
kIdentityConsumerId, identity_manager, scopes,
void DriveFsAuth::AccountReady(const CoreAccountId& account_id,
const std::string& gaia,
const std::string& email,
const identity::AccountState& state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
weak_ptr_factory_.InvalidateWeakPtrs();
timer_->Stop();
GetIdentityAccessor()->GetAccessToken(
account_id, {"https://www.googleapis.com/auth/drive"},
kIdentityConsumerId,
base::BindOnce(&DriveFsAuth::GotChromeAccessToken, base::BindOnce(&DriveFsAuth::GotChromeAccessToken,
base::Unretained(this))); base::Unretained(this)),
signin::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable,
signin::ConsentLevel::kNotRequired);
} }
void DriveFsAuth::GotChromeAccessToken( void DriveFsAuth::GotChromeAccessToken(
const base::Optional<std::string>& access_token, GoogleServiceAuthError error,
base::Time expiration_time, signin::AccessTokenInfo access_token_info) {
const GoogleServiceAuthError& error) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!access_token) { timer_->Stop();
if (error.state() != GoogleServiceAuthError::NONE) {
std::move(get_access_token_callback_) std::move(get_access_token_callback_)
.Run(error.IsPersistentError() .Run(error.IsPersistentError()
? mojom::AccessTokenStatus::kAuthError ? mojom::AccessTokenStatus::kAuthError
...@@ -84,9 +86,9 @@ void DriveFsAuth::GotChromeAccessToken( ...@@ -84,9 +86,9 @@ void DriveFsAuth::GotChromeAccessToken(
""); "");
return; return;
} }
UpdateCachedToken(*access_token, expiration_time); UpdateCachedToken(access_token_info.token, access_token_info.expiration_time);
std::move(get_access_token_callback_) std::move(get_access_token_callback_)
.Run(mojom::AccessTokenStatus::kSuccess, *access_token); .Run(mojom::AccessTokenStatus::kSuccess, access_token_info.token);
} }
const std::string& DriveFsAuth::GetOrResetCachedToken(bool use_cached) { const std::string& DriveFsAuth::GetOrResetCachedToken(bool use_cached) {
...@@ -104,18 +106,8 @@ void DriveFsAuth::UpdateCachedToken(const std::string& token, ...@@ -104,18 +106,8 @@ void DriveFsAuth::UpdateCachedToken(const std::string& token,
void DriveFsAuth::AuthTimeout() { void DriveFsAuth::AuthTimeout() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
weak_ptr_factory_.InvalidateWeakPtrs();
std::move(get_access_token_callback_) std::move(get_access_token_callback_)
.Run(mojom::AccessTokenStatus::kAuthError, ""); .Run(mojom::AccessTokenStatus::kAuthError, "");
} }
identity::mojom::IdentityAccessor* DriveFsAuth::GetIdentityAccessor() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!identity_accessor_) {
delegate_->BindIdentityAccessor(
identity_accessor_.BindNewPipeAndPassReceiver());
}
return identity_accessor_.get();
}
} // namespace drivefs } // namespace drivefs
...@@ -11,20 +11,23 @@ ...@@ -11,20 +11,23 @@
#include "base/component_export.h" #include "base/component_export.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/clock.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 "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/identity/public/mojom/identity_accessor.mojom.h"
class AccountId; class AccountId;
class GoogleServiceAuthError;
namespace network { namespace network {
class SharedURLLoaderFactory; class SharedURLLoaderFactory;
} // namespace network } // namespace network
namespace signin {
struct AccessTokenInfo;
class IdentityManager;
class PrimaryAccountAccessTokenFetcher;
} // namespace signin
namespace drivefs { namespace drivefs {
class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth { class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth {
...@@ -36,8 +39,7 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth { ...@@ -36,8 +39,7 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth {
virtual scoped_refptr<network::SharedURLLoaderFactory> virtual scoped_refptr<network::SharedURLLoaderFactory>
GetURLLoaderFactory() = 0; GetURLLoaderFactory() = 0;
virtual void BindIdentityAccessor( virtual signin::IdentityManager* GetIdentityManager() = 0;
mojo::PendingReceiver<identity::mojom::IdentityAccessor> receiver) = 0;
virtual const AccountId& GetAccountId() = 0; virtual const AccountId& GetAccountId() = 0;
virtual std::string GetObfuscatedAccountId() = 0; virtual std::string GetObfuscatedAccountId() = 0;
virtual bool IsMetricsCollectionEnabled() = 0; virtual bool IsMetricsCollectionEnabled() = 0;
...@@ -71,14 +73,8 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth { ...@@ -71,14 +73,8 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth {
mojom::DriveFsDelegate::GetAccessTokenCallback callback); mojom::DriveFsDelegate::GetAccessTokenCallback callback);
private: private:
void AccountReady(const CoreAccountId& account_id, void GotChromeAccessToken(GoogleServiceAuthError error,
const std::string& gaia, signin::AccessTokenInfo access_token_info);
const std::string& email,
const identity::AccountState& state);
void GotChromeAccessToken(const base::Optional<std::string>& access_token,
base::Time expiration_time,
const GoogleServiceAuthError& error);
const std::string& GetOrResetCachedToken(bool use_cached); const std::string& GetOrResetCachedToken(bool use_cached);
...@@ -86,16 +82,14 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth { ...@@ -86,16 +82,14 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth {
void AuthTimeout(); void AuthTimeout();
identity::mojom::IdentityAccessor* GetIdentityAccessor();
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
const base::Clock* const clock_; const base::Clock* const clock_;
const base::FilePath profile_path_; const base::FilePath profile_path_;
const std::unique_ptr<base::OneShotTimer> timer_; const std::unique_ptr<base::OneShotTimer> timer_;
Delegate* const delegate_; Delegate* const delegate_;
// The connection to the identity service. Access via |GetIdentityAccessor()|. std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher>
mojo::Remote<identity::mojom::IdentityAccessor> identity_accessor_; access_token_fetcher_;
// Pending callback for an in-flight GetAccessToken request. // Pending callback for an in-flight GetAccessToken request.
mojom::DriveFsDelegate::GetAccessTokenCallback get_access_token_callback_; mojom::DriveFsDelegate::GetAccessTokenCallback get_access_token_callback_;
...@@ -103,7 +97,6 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth { ...@@ -103,7 +97,6 @@ class COMPONENT_EXPORT(DRIVEFS) DriveFsAuth {
std::string last_token_; std::string last_token_;
base::Time last_token_expiry_; base::Time last_token_expiry_;
base::WeakPtrFactory<DriveFsAuth> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(DriveFsAuth); DISALLOW_COPY_AND_ASSIGN(DriveFsAuth);
}; };
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chromeos/components/drivefs/drivefs_auth.h" #include "chromeos/components/drivefs/drivefs_auth.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/strcat.h" #include "base/strings/strcat.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
...@@ -13,9 +14,10 @@ ...@@ -13,9 +14,10 @@
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/timer/mock_timer.h" #include "base/timer/mock_timer.h"
#include "components/account_id/account_id.h" #include "components/account_id/account_id.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/receiver_set.h"
#include "services/identity/public/mojom/identity_accessor.mojom-test-utils.h"
#include "services/identity/public/mojom/identity_service.mojom.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -25,11 +27,14 @@ namespace { ...@@ -25,11 +27,14 @@ namespace {
using testing::_; using testing::_;
constexpr char kTestEmail[] = "test@example.com";
constexpr base::TimeDelta kTokenLifetime = base::TimeDelta::FromHours(1);
class AuthDelegateImpl : public DriveFsAuth::Delegate { class AuthDelegateImpl : public DriveFsAuth::Delegate {
public: public:
AuthDelegateImpl(identity::mojom::IdentityService* identity_service, AuthDelegateImpl(signin::IdentityManager* identity_manager,
const AccountId& account_id) const AccountId& account_id)
: identity_service_(identity_service), account_id_(account_id) {} : identity_manager_(identity_manager), account_id_(account_id) {}
~AuthDelegateImpl() override = default; ~AuthDelegateImpl() override = default;
...@@ -39,10 +44,8 @@ class AuthDelegateImpl : public DriveFsAuth::Delegate { ...@@ -39,10 +44,8 @@ class AuthDelegateImpl : public DriveFsAuth::Delegate {
override { override {
return nullptr; return nullptr;
} }
void BindIdentityAccessor( signin::IdentityManager* GetIdentityManager() override {
mojo::PendingReceiver<identity::mojom::IdentityAccessor> receiver) return identity_manager_;
override {
identity_service_->BindIdentityAccessor(std::move(receiver));
} }
const AccountId& GetAccountId() override { return account_id_; } const AccountId& GetAccountId() override { return account_id_; }
std::string GetObfuscatedAccountId() override { std::string GetObfuscatedAccountId() override {
...@@ -51,95 +54,25 @@ class AuthDelegateImpl : public DriveFsAuth::Delegate { ...@@ -51,95 +54,25 @@ class AuthDelegateImpl : public DriveFsAuth::Delegate {
bool IsMetricsCollectionEnabled() override { return false; } bool IsMetricsCollectionEnabled() override { return false; }
identity::mojom::IdentityService* const identity_service_; signin::IdentityManager* const identity_manager_;
const AccountId account_id_; const AccountId account_id_;
DISALLOW_COPY_AND_ASSIGN(AuthDelegateImpl); DISALLOW_COPY_AND_ASSIGN(AuthDelegateImpl);
}; };
class MockIdentityAccessor {
public:
MOCK_METHOD3(
GetAccessToken,
std::pair<base::Optional<std::string>, GoogleServiceAuthError::State>(
const CoreAccountId& account_id,
const ::identity::ScopeSet& scopes,
const std::string& consumer_id));
mojo::ReceiverSet<identity::mojom::IdentityAccessor>* receivers_ = nullptr;
};
class FakeIdentityService
: public identity::mojom::IdentityAccessorInterceptorForTesting,
public identity::mojom::IdentityService {
public:
explicit FakeIdentityService(MockIdentityAccessor* mock,
const base::Clock* clock)
: mock_(mock), clock_(clock) {
mock_->receivers_ = &receivers_;
}
~FakeIdentityService() override { mock_->receivers_ = nullptr; }
void set_auth_enabled(bool enabled) { auth_enabled_ = enabled; }
private:
// identity::mojom::IdentityService:
void BindIdentityAccessor(
mojo::PendingReceiver<identity::mojom::IdentityAccessor> receiver)
override {
receivers_.Add(this, std::move(receiver));
}
// identity::mojom::IdentityAccessorInterceptorForTesting overrides:
void GetUnconsentedPrimaryAccountWhenAvailable(
GetUnconsentedPrimaryAccountWhenAvailableCallback callback) override {
if (!auth_enabled_) {
return;
}
auto account_id = AccountId::FromUserEmailGaiaId("test@example.com", "ID");
std::move(callback).Run(CoreAccountId(account_id.GetUserEmail()),
account_id.GetGaiaId(), account_id.GetUserEmail(),
{});
}
void GetAccessToken(const CoreAccountId& account_id,
const ::identity::ScopeSet& scopes,
const std::string& consumer_id,
GetAccessTokenCallback callback) override {
auto result = mock_->GetAccessToken(account_id, scopes, consumer_id);
std::move(callback).Run(std::move(result.first),
clock_->Now() + base::TimeDelta::FromSeconds(1),
GoogleServiceAuthError(result.second));
}
IdentityAccessor* GetForwardingInterface() override {
NOTREACHED();
return nullptr;
}
MockIdentityAccessor* const mock_;
const base::Clock* const clock_;
mojo::ReceiverSet<identity::mojom::IdentityAccessor> receivers_;
bool auth_enabled_ = true;
DISALLOW_COPY_AND_ASSIGN(FakeIdentityService);
};
class DriveFsAuthTest : public ::testing::Test { class DriveFsAuthTest : public ::testing::Test {
public: public:
DriveFsAuthTest() : kTestAccountId("test@example.com") {} DriveFsAuthTest() = default;
protected: protected:
void SetUp() override { void SetUp() override {
clock_.SetNow(base::Time::Now()); clock_.SetNow(base::Time::Now());
identity_service_ = std::make_unique<FakeIdentityService>( identity_test_env_.MakeUnconsentedPrimaryAccountAvailable(kTestEmail);
&mock_identity_accessor_, &clock_);
auto timer = std::make_unique<base::MockOneShotTimer>(); auto timer = std::make_unique<base::MockOneShotTimer>();
timer_ = timer.get(); timer_ = timer.get();
delegate_ = std::make_unique<AuthDelegateImpl>( delegate_ = std::make_unique<AuthDelegateImpl>(
identity_service_.get(), identity_test_env_.identity_manager(),
AccountId::FromUserEmailGaiaId("test@example.com", "ID")); AccountId::FromUserEmailGaiaId(kTestEmail, "ID"));
auth_ = std::make_unique<DriveFsAuth>(&clock_, auth_ = std::make_unique<DriveFsAuth>(&clock_,
base::FilePath("/path/to/profile"), base::FilePath("/path/to/profile"),
std::move(timer), delegate_.get()); std::move(timer), delegate_.get());
...@@ -150,26 +83,21 @@ class DriveFsAuthTest : public ::testing::Test { ...@@ -150,26 +83,21 @@ class DriveFsAuthTest : public ::testing::Test {
auth_.reset(); auth_.reset();
} }
void ExpectAccessToken(bool use_cached, // Helper function for better line wrapping.
mojom::AccessTokenStatus expected_status, void RespondWithAccessToken(const std::string& token) {
const std::string& expected_token) { identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
base::RunLoop run_loop; token, clock_.Now() + kTokenLifetime);
auto quit_closure = run_loop.QuitClosure(); }
auth_->GetAccessToken(use_cached, base::BindLambdaForTesting(
[&](mojom::AccessTokenStatus status, // Helper function for better line wrapping.
const std::string& token) { void RespondWithAuthError(GoogleServiceAuthError::State error_state) {
EXPECT_EQ(expected_status, status); identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
EXPECT_EQ(expected_token, token); GoogleServiceAuthError(error_state));
std::move(quit_closure).Run();
}));
run_loop.Run();
} }
const CoreAccountId kTestAccountId;
base::test::TaskEnvironment task_environment_; base::test::TaskEnvironment task_environment_;
MockIdentityAccessor mock_identity_accessor_; signin::IdentityTestEnvironment identity_test_env_;
base::SimpleTestClock clock_; base::SimpleTestClock clock_;
std::unique_ptr<FakeIdentityService> identity_service_;
std::unique_ptr<AuthDelegateImpl> delegate_; std::unique_ptr<AuthDelegateImpl> delegate_;
std::unique_ptr<DriveFsAuth> auth_; std::unique_ptr<DriveFsAuth> auth_;
...@@ -180,31 +108,45 @@ class DriveFsAuthTest : public ::testing::Test { ...@@ -180,31 +108,45 @@ class DriveFsAuthTest : public ::testing::Test {
}; };
TEST_F(DriveFsAuthTest, GetAccessToken_Success) { TEST_F(DriveFsAuthTest, GetAccessToken_Success) {
EXPECT_CALL(mock_identity_accessor_, base::RunLoop run_loop;
GetAccessToken(kTestAccountId, _, "drivefs")) auth_->GetAccessToken(
.WillOnce(testing::Return( false, base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
std::make_pair("auth token", GoogleServiceAuthError::NONE))); const std::string& token) {
ExpectAccessToken(false, mojom::AccessTokenStatus::kSuccess, "auth token"); EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
EXPECT_EQ("auth token", token);
run_loop.Quit();
}));
RespondWithAccessToken("auth token");
run_loop.Run();
} }
TEST_F(DriveFsAuthTest, GetAccessToken_GetAccessTokenFailure_Permanent) { TEST_F(DriveFsAuthTest, GetAccessToken_GetAccessTokenFailure_Permanent) {
EXPECT_CALL(mock_identity_accessor_, base::RunLoop run_loop;
GetAccessToken(kTestAccountId, _, "drivefs")) auth_->GetAccessToken(
.WillOnce(testing::Return(std::make_pair( false, base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
base::nullopt, GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS))); const std::string& token) {
ExpectAccessToken(false, mojom::AccessTokenStatus::kAuthError, ""); EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status);
EXPECT_TRUE(token.empty());
run_loop.Quit();
}));
RespondWithAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
run_loop.Run();
} }
TEST_F(DriveFsAuthTest, GetAccessToken_GetAccessTokenFailure_Transient) { TEST_F(DriveFsAuthTest, GetAccessToken_GetAccessTokenFailure_Transient) {
EXPECT_CALL(mock_identity_accessor_, base::RunLoop run_loop;
GetAccessToken(kTestAccountId, _, "drivefs")) auth_->GetAccessToken(
.WillOnce(testing::Return(std::make_pair( false, base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
base::nullopt, GoogleServiceAuthError::SERVICE_UNAVAILABLE))); const std::string& token) {
ExpectAccessToken(false, mojom::AccessTokenStatus::kTransientError, ""); EXPECT_EQ(mojom::AccessTokenStatus::kTransientError, status);
EXPECT_TRUE(token.empty());
run_loop.Quit();
}));
RespondWithAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE);
run_loop.Run();
} }
TEST_F(DriveFsAuthTest, GetAccessToken_GetAccessTokenFailure_Timeout) { TEST_F(DriveFsAuthTest, GetAccessToken_GetAccessTokenFailure_Timeout) {
identity_service_->set_auth_enabled(false);
base::RunLoop run_loop; base::RunLoop run_loop;
auto quit_closure = run_loop.QuitClosure(); auto quit_closure = run_loop.QuitClosure();
auth_->GetAccessToken( auth_->GetAccessToken(
...@@ -213,16 +155,13 @@ TEST_F(DriveFsAuthTest, GetAccessToken_GetAccessTokenFailure_Timeout) { ...@@ -213,16 +155,13 @@ TEST_F(DriveFsAuthTest, GetAccessToken_GetAccessTokenFailure_Timeout) {
EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status); EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status);
std::move(quit_closure).Run(); std::move(quit_closure).Run();
})); }));
// Timer fires before access token becomes available.
timer_->Fire(); timer_->Fire();
run_loop.Run(); run_loop.Run();
} }
TEST_F(DriveFsAuthTest, GetAccessToken_ParallelRequests) { TEST_F(DriveFsAuthTest, GetAccessToken_ParallelRequests) {
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_CALL(mock_identity_accessor_,
GetAccessToken(kTestAccountId, _, "drivefs"))
.WillOnce(testing::Return(
std::make_pair("auth token", GoogleServiceAuthError::NONE)));
auto quit_closure = run_loop.QuitClosure(); auto quit_closure = run_loop.QuitClosure();
auth_->GetAccessToken( auth_->GetAccessToken(
false, base::BindLambdaForTesting([&](mojom::AccessTokenStatus status, false, base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
...@@ -237,69 +176,103 @@ TEST_F(DriveFsAuthTest, GetAccessToken_ParallelRequests) { ...@@ -237,69 +176,103 @@ TEST_F(DriveFsAuthTest, GetAccessToken_ParallelRequests) {
EXPECT_EQ(mojom::AccessTokenStatus::kTransientError, status); EXPECT_EQ(mojom::AccessTokenStatus::kTransientError, status);
EXPECT_TRUE(token.empty()); EXPECT_TRUE(token.empty());
})); }));
RespondWithAccessToken("auth token");
run_loop.Run(); run_loop.Run();
} }
TEST_F(DriveFsAuthTest, GetAccessToken_SequentialRequests) { TEST_F(DriveFsAuthTest, GetAccessToken_SequentialRequests) {
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
EXPECT_CALL(mock_identity_accessor_, base::RunLoop run_loop;
GetAccessToken(kTestAccountId, _, "drivefs")) auth_->GetAccessToken(
.WillOnce(testing::Return( false, base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
std::make_pair("auth token", GoogleServiceAuthError::NONE))); const std::string& token) {
ExpectAccessToken(false, mojom::AccessTokenStatus::kSuccess, "auth token"); EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
EXPECT_EQ("auth token", token);
run_loop.Quit();
}));
RespondWithAccessToken("auth token");
run_loop.Run();
} }
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
EXPECT_CALL(mock_identity_accessor_, base::RunLoop run_loop;
GetAccessToken(kTestAccountId, _, "drivefs")) auth_->GetAccessToken(
.WillOnce(testing::Return(std::make_pair( false, base::BindLambdaForTesting([&](mojom::AccessTokenStatus status,
base::nullopt, GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS))); const std::string& token) {
ExpectAccessToken(false, mojom::AccessTokenStatus::kAuthError, ""); EXPECT_EQ(mojom::AccessTokenStatus::kAuthError, status);
EXPECT_TRUE(token.empty());
run_loop.Quit();
}));
RespondWithAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
run_loop.Run();
} }
} }
TEST_F(DriveFsAuthTest, Caching) { TEST_F(DriveFsAuthTest, Caching) {
EXPECT_CALL(mock_identity_accessor_, auth_->GetAccessToken(true, base::BindOnce([](mojom::AccessTokenStatus status,
GetAccessToken(kTestAccountId, _, "drivefs")) const std::string& token) {
.WillOnce(testing::Return( EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
std::make_pair("auth token", GoogleServiceAuthError::NONE))); EXPECT_EQ("auth token", token);
}));
ExpectAccessToken(true, mojom::AccessTokenStatus::kSuccess, "auth token"); EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
RespondWithAccessToken("auth token");
// Second attempt should reuse already available token. // Second attempt should reuse already available token.
ExpectAccessToken(true, mojom::AccessTokenStatus::kSuccess, "auth token"); auth_->GetAccessToken(true, base::BindOnce([](mojom::AccessTokenStatus status,
const std::string& token) {
EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
EXPECT_EQ("auth token", token);
}));
EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
} }
TEST_F(DriveFsAuthTest, CachedAndNotCached) { TEST_F(DriveFsAuthTest, CachedAndNotCached) {
EXPECT_CALL(mock_identity_accessor_, auth_->GetAccessToken(true, base::BindOnce([](mojom::AccessTokenStatus status,
GetAccessToken(kTestAccountId, _, "drivefs")) const std::string& token) {
.WillOnce(testing::Return( EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
std::make_pair("auth token", GoogleServiceAuthError::NONE))) EXPECT_EQ("auth token", token);
.WillOnce(testing::Return( }));
std::make_pair("auth token 2", GoogleServiceAuthError::NONE))); EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
RespondWithAccessToken("auth token");
ExpectAccessToken(true, mojom::AccessTokenStatus::kSuccess, "auth token");
// Second attempt should reuse already available token. // Second attempt should reuse already available token.
ExpectAccessToken(true, mojom::AccessTokenStatus::kSuccess, "auth token"); auth_->GetAccessToken(true, base::BindOnce([](mojom::AccessTokenStatus status,
const std::string& token) {
EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
EXPECT_EQ("auth token", token);
}));
EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
// Now ask for token explicitly bypassing the cache. // Now ask for token explicitly bypassing the cache.
ExpectAccessToken(false, mojom::AccessTokenStatus::kSuccess, "auth token 2"); auth_->GetAccessToken(
false, base::BindOnce(
[](mojom::AccessTokenStatus status, const std::string& token) {
EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
EXPECT_EQ("auth token 2", token);
}));
EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
RespondWithAccessToken("auth token 2");
EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
} }
TEST_F(DriveFsAuthTest, CacheExpired) { TEST_F(DriveFsAuthTest, CacheExpired) {
EXPECT_CALL(mock_identity_accessor_, auth_->GetAccessToken(true, base::BindOnce([](mojom::AccessTokenStatus status,
GetAccessToken(kTestAccountId, _, "drivefs")) const std::string& token) {
.WillOnce(testing::Return( EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
std::make_pair("auth token", GoogleServiceAuthError::NONE))) EXPECT_EQ("auth token", token);
.WillOnce(testing::Return( }));
std::make_pair("auth token 2", GoogleServiceAuthError::NONE))); EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
RespondWithAccessToken("auth token");
ExpectAccessToken(true, mojom::AccessTokenStatus::kSuccess, "auth token");
clock_.Advance(base::TimeDelta::FromHours(2)); clock_.Advance(base::TimeDelta::FromHours(2));
// As the token expired second mount attempt go to identity. // The token expired so a new one is requested.
ExpectAccessToken(true, mojom::AccessTokenStatus::kSuccess, "auth token 2"); auth_->GetAccessToken(true, base::BindOnce([](mojom::AccessTokenStatus status,
const std::string& token) {
EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
EXPECT_EQ("auth token 2", token);
}));
RespondWithAccessToken("auth token 2");
EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
} }
} // namespace } // namespace
......
...@@ -28,14 +28,14 @@ ...@@ -28,14 +28,14 @@
#include "components/drive/drive_notification_manager.h" #include "components/drive/drive_notification_manager.h"
#include "components/drive/drive_notification_observer.h" #include "components/drive/drive_notification_observer.h"
#include "components/invalidation/impl/fake_invalidation_service.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/clone_traits.h"
#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/remote.h"
#include "services/identity/public/mojom/identity_accessor.mojom-test-utils.h"
#include "services/identity/public/mojom/identity_service.mojom.h"
#include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/test/test_network_connection_tracker.h" #include "services/network/test/test_network_connection_tracker.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -46,6 +46,8 @@ namespace { ...@@ -46,6 +46,8 @@ namespace {
using testing::_; using testing::_;
using MountFailure = DriveFsHost::MountObserver::MountFailure; using MountFailure = DriveFsHost::MountObserver::MountFailure;
constexpr base::TimeDelta kTokenLifetime = base::TimeDelta::FromHours(1);
class MockDriveFs : public mojom::DriveFsInterceptorForTesting, class MockDriveFs : public mojom::DriveFsInterceptorForTesting,
public mojom::SearchQuery { public mojom::SearchQuery {
public: public:
...@@ -95,9 +97,9 @@ class MockDriveFs : public mojom::DriveFsInterceptorForTesting, ...@@ -95,9 +97,9 @@ class MockDriveFs : public mojom::DriveFsInterceptorForTesting,
class TestingDriveFsHostDelegate : public DriveFsHost::Delegate, class TestingDriveFsHostDelegate : public DriveFsHost::Delegate,
public DriveFsHost::MountObserver { public DriveFsHost::MountObserver {
public: public:
TestingDriveFsHostDelegate(identity::mojom::IdentityService* identity_service, TestingDriveFsHostDelegate(signin::IdentityManager* identity_manager,
const AccountId& account_id) const AccountId& account_id)
: identity_service_(identity_service), : identity_manager_(identity_manager),
account_id_(account_id), account_id_(account_id),
drive_notification_manager_(&invalidation_service_) {} drive_notification_manager_(&invalidation_service_) {}
...@@ -126,10 +128,8 @@ class TestingDriveFsHostDelegate : public DriveFsHost::Delegate, ...@@ -126,10 +128,8 @@ class TestingDriveFsHostDelegate : public DriveFsHost::Delegate,
override { override {
return nullptr; return nullptr;
} }
void BindIdentityAccessor( signin::IdentityManager* GetIdentityManager() override {
mojo::PendingReceiver<identity::mojom::IdentityAccessor> receiver) return identity_manager_;
override {
identity_service_->BindIdentityAccessor(std::move(receiver));
} }
const AccountId& GetAccountId() override { return account_id_; } const AccountId& GetAccountId() override { return account_id_; }
std::string GetObfuscatedAccountId() override { std::string GetObfuscatedAccountId() override {
...@@ -151,7 +151,7 @@ class TestingDriveFsHostDelegate : public DriveFsHost::Delegate, ...@@ -151,7 +151,7 @@ class TestingDriveFsHostDelegate : public DriveFsHost::Delegate,
return base::FilePath("/MyFiles"); return base::FilePath("/MyFiles");
} }
identity::mojom::IdentityService* const identity_service_; signin::IdentityManager* const identity_manager_;
const AccountId account_id_; const AccountId account_id_;
mojo::PendingRemote<mojom::DriveFsBootstrap> pending_bootstrap_; mojo::PendingRemote<mojom::DriveFsBootstrap> pending_bootstrap_;
invalidation::FakeInvalidationService invalidation_service_; invalidation::FakeInvalidationService invalidation_service_;
...@@ -160,91 +160,6 @@ class TestingDriveFsHostDelegate : public DriveFsHost::Delegate, ...@@ -160,91 +160,6 @@ class TestingDriveFsHostDelegate : public DriveFsHost::Delegate,
DISALLOW_COPY_AND_ASSIGN(TestingDriveFsHostDelegate); DISALLOW_COPY_AND_ASSIGN(TestingDriveFsHostDelegate);
}; };
class MockIdentityAccessor {
public:
explicit MockIdentityAccessor(const base::Clock* clock) : clock_(clock) {}
MOCK_METHOD3(
GetAccessToken,
std::pair<base::Optional<std::string>, GoogleServiceAuthError::State>(
const CoreAccountId& account_id,
const ::identity::ScopeSet& scopes,
const std::string& consumer_id));
void OnGetAccessToken(
const CoreAccountId& account_id,
const ::identity::ScopeSet& scopes,
const std::string& consumer_id,
identity::mojom::IdentityAccessor::GetAccessTokenCallback callback) {
if (pause_requests_) {
callbacks_.push_back(std::move(callback));
return;
}
auto result = GetAccessToken(account_id, scopes, consumer_id);
std::move(callback).Run(std::move(result.first),
clock_->Now() + base::TimeDelta::FromHours(1),
GoogleServiceAuthError(result.second));
}
std::vector<identity::mojom::IdentityAccessor::GetAccessTokenCallback>&
callbacks() {
return callbacks_;
}
void set_pause_requests(bool pause) { pause_requests_ = pause; }
const base::Clock* const clock_;
bool pause_requests_ = false;
std::vector<identity::mojom::IdentityAccessor::GetAccessTokenCallback>
callbacks_;
mojo::ReceiverSet<identity::mojom::IdentityAccessor>* receivers_ = nullptr;
};
class FakeIdentityService
: public identity::mojom::IdentityAccessorInterceptorForTesting,
public identity::mojom::IdentityService {
public:
explicit FakeIdentityService(MockIdentityAccessor* mock) : mock_(mock) {
mock_->receivers_ = &receivers_;
}
~FakeIdentityService() override { mock_->receivers_ = nullptr; }
private:
// identity::mojom::IdentityService:
void BindIdentityAccessor(
mojo::PendingReceiver<identity::mojom::IdentityAccessor> receiver)
override {
receivers_.Add(this, std::move(receiver));
}
// identity::mojom::IdentityAccessorInterceptorForTesting overrides:
void GetUnconsentedPrimaryAccountWhenAvailable(
GetUnconsentedPrimaryAccountWhenAvailableCallback callback) override {
auto account_id = AccountId::FromUserEmailGaiaId("test@example.com", "ID");
std::move(callback).Run(CoreAccountId(account_id.GetUserEmail()),
account_id.GetGaiaId(), account_id.GetUserEmail(),
{});
}
void GetAccessToken(const CoreAccountId& account_id,
const ::identity::ScopeSet& scopes,
const std::string& consumer_id,
GetAccessTokenCallback callback) override {
mock_->OnGetAccessToken(account_id, scopes, consumer_id,
std::move(callback));
}
IdentityAccessor* GetForwardingInterface() override {
NOTREACHED();
return nullptr;
}
MockIdentityAccessor* const mock_;
mojo::ReceiverSet<identity::mojom::IdentityAccessor> receivers_;
DISALLOW_COPY_AND_ASSIGN(FakeIdentityService);
};
class MockDriveFsHostObserver : public DriveFsHostObserver { class MockDriveFsHostObserver : public DriveFsHostObserver {
public: public:
MOCK_METHOD0(OnUnmounted, void()); MOCK_METHOD0(OnUnmounted, void());
...@@ -262,8 +177,7 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap { ...@@ -262,8 +177,7 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
public: public:
DriveFsHostTest() DriveFsHostTest()
: network_connection_tracker_( : network_connection_tracker_(
network::TestNetworkConnectionTracker::CreateInstance()), network::TestNetworkConnectionTracker::CreateInstance()) {
mock_identity_accessor_(&clock_) {
clock_.SetNow(base::Time::Now()); clock_.SetNow(base::Time::Now());
} }
...@@ -274,10 +188,10 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap { ...@@ -274,10 +188,10 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
account_id_ = AccountId::FromUserEmailGaiaId("test@example.com", "ID"); account_id_ = AccountId::FromUserEmailGaiaId("test@example.com", "ID");
disk_manager_ = std::make_unique<chromeos::disks::MockDiskMountManager>(); disk_manager_ = std::make_unique<chromeos::disks::MockDiskMountManager>();
identity_service_ = identity_test_env_.MakeUnconsentedPrimaryAccountAvailable(
std::make_unique<FakeIdentityService>(&mock_identity_accessor_); "test@example.com");
host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>( host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>(
identity_service_.get(), account_id_); identity_test_env_.identity_manager(), account_id_);
auto timer = std::make_unique<base::MockOneShotTimer>(); auto timer = std::make_unique<base::MockOneShotTimer>();
timer_ = timer.get(); timer_ = timer.get();
host_ = std::make_unique<DriveFsHost>( host_ = std::make_unique<DriveFsHost>(
...@@ -377,21 +291,6 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap { ...@@ -377,21 +291,6 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
testing::Mock::VerifyAndClearExpectations(host_delegate_.get()); testing::Mock::VerifyAndClearExpectations(host_delegate_.get());
} }
void ExpectAccessToken(mojom::AccessTokenStatus expected_status,
const std::string& expected_token) {
base::RunLoop run_loop;
auto quit_closure = run_loop.QuitClosure();
delegate_->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,
mojo::PendingReceiver<mojom::DriveFs> drive_fs_receiver, mojo::PendingReceiver<mojom::DriveFs> drive_fs_receiver,
mojo::PendingRemote<mojom::DriveFsDelegate> delegate) override { mojo::PendingRemote<mojom::DriveFsDelegate> delegate) override {
...@@ -410,8 +309,7 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap { ...@@ -410,8 +309,7 @@ class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
std::unique_ptr<network::TestNetworkConnectionTracker> std::unique_ptr<network::TestNetworkConnectionTracker>
network_connection_tracker_; network_connection_tracker_;
base::SimpleTestClock clock_; base::SimpleTestClock clock_;
MockIdentityAccessor mock_identity_accessor_; signin::IdentityTestEnvironment identity_test_env_;
std::unique_ptr<FakeIdentityService> identity_service_;
std::unique_ptr<TestingDriveFsHostDelegate> host_delegate_; std::unique_ptr<TestingDriveFsHostDelegate> host_delegate_;
std::unique_ptr<DriveFsHost> host_; std::unique_ptr<DriveFsHost> host_;
base::MockOneShotTimer* timer_; base::MockOneShotTimer* timer_;
...@@ -522,7 +420,7 @@ TEST_F(DriveFsHostTest, UnsupportedAccountTypes) { ...@@ -522,7 +420,7 @@ TEST_F(DriveFsHostTest, UnsupportedAccountTypes) {
}; };
for (auto& account : unsupported_accounts) { for (auto& account : unsupported_accounts) {
host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>( host_delegate_ = std::make_unique<TestingDriveFsHostDelegate>(
identity_service_.get(), account); identity_test_env_.identity_manager(), 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(),
network_connection_tracker_.get(), &clock_, disk_manager_.get(), network_connection_tracker_.get(), &clock_, disk_manager_.get(),
...@@ -535,25 +433,17 @@ TEST_F(DriveFsHostTest, UnsupportedAccountTypes) { ...@@ -535,25 +433,17 @@ TEST_F(DriveFsHostTest, UnsupportedAccountTypes) {
TEST_F(DriveFsHostTest, GetAccessToken_UnmountDuringMojoRequest) { TEST_F(DriveFsHostTest, GetAccessToken_UnmountDuringMojoRequest) {
ASSERT_NO_FATAL_FAILURE(DoMount()); ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_CALL(mock_identity_accessor_,
GetAccessToken(CoreAccountId("test@example.com"), _, "drivefs"))
.WillOnce(testing::DoAll(
testing::InvokeWithoutArgs([&]() { host_->Unmount(); }),
testing::Return(std::make_pair(
base::nullopt,
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS))));
base::RunLoop run_loop; base::RunLoop run_loop;
delegate_.set_disconnect_handler(run_loop.QuitClosure()); delegate_.set_disconnect_handler(run_loop.QuitClosure());
delegate_->GetAccessToken( delegate_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"}, "client ID", "app ID", {"scope1", "scope2"},
base::BindLambdaForTesting([](mojom::AccessTokenStatus status, base::BindLambdaForTesting([](mojom::AccessTokenStatus status,
const std::string& token) { FAIL(); })); const std::string& token) { FAIL(); }));
host_->Unmount();
run_loop.Run(); run_loop.Run();
EXPECT_FALSE(host_->IsMounted()); EXPECT_FALSE(host_->IsMounted());
// Wait for the response to reach the remote if it's still open. EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
mock_identity_accessor_.receivers_->FlushForTesting();
} }
ACTION_P(CloneStruct, output) { ACTION_P(CloneStruct, output) {
...@@ -713,14 +603,21 @@ TEST_F(DriveFsHostTest, RemoveDriveNotificationObserver) { ...@@ -713,14 +603,21 @@ TEST_F(DriveFsHostTest, RemoveDriveNotificationObserver) {
TEST_F(DriveFsHostTest, Remount_CachedOnceOnly) { TEST_F(DriveFsHostTest, Remount_CachedOnceOnly) {
ASSERT_NO_FATAL_FAILURE(DoMount()); ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_CALL(mock_identity_accessor_, // Request an access token.
GetAccessToken(CoreAccountId("test@example.com"), _, "drivefs")) delegate_->GetAccessToken(
.WillOnce(testing::Return( "client ID", "app ID", {"scope1", "scope2"},
std::make_pair("auth token", GoogleServiceAuthError::NONE))) base::BindLambdaForTesting(
.WillOnce(testing::Return( [&](mojom::AccessTokenStatus status, const std::string& token) {
std::make_pair("auth token 2", GoogleServiceAuthError::NONE))); EXPECT_EQ(mojom::AccessTokenStatus::kSuccess, status);
EXPECT_EQ("auth token", token);
}));
delegate_.FlushForTesting();
EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token"); // Fulfill the request.
identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"auth token", clock_.Now() + kTokenLifetime);
EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
base::Optional<base::TimeDelta> delay = base::TimeDelta::FromSeconds(5); base::Optional<base::TimeDelta> delay = base::TimeDelta::FromSeconds(5);
EXPECT_CALL(*host_delegate_, OnUnmounted(delay)); EXPECT_CALL(*host_delegate_, OnUnmounted(delay));
...@@ -730,15 +627,28 @@ TEST_F(DriveFsHostTest, Remount_CachedOnceOnly) { ...@@ -730,15 +627,28 @@ TEST_F(DriveFsHostTest, Remount_CachedOnceOnly) {
// Second mount attempt should reuse already available token. // Second mount attempt should reuse already available token.
ASSERT_NO_FATAL_FAILURE(DoMount()); ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
EXPECT_EQ("auth token", init_access_token_.value_or("")); EXPECT_EQ("auth token", init_access_token_.value_or(""));
// But if it asks for token it goes straight to identity. // But if it asks for token again it goes to identity manager.
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth token 2"); 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) { TEST_F(DriveFsHostTest, Remount_RequestInflight) {
ASSERT_NO_FATAL_FAILURE(DoMount()); ASSERT_NO_FATAL_FAILURE(DoMount());
mock_identity_accessor_.set_pause_requests(true);
delegate_->GetAccessToken( delegate_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"}, "client ID", "app ID", {"scope1", "scope2"},
...@@ -750,22 +660,20 @@ TEST_F(DriveFsHostTest, Remount_RequestInflight) { ...@@ -750,22 +660,20 @@ TEST_F(DriveFsHostTest, Remount_RequestInflight) {
SendOnUnmounted(delay); SendOnUnmounted(delay);
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
ASSERT_NO_FATAL_FAILURE(DoUnmount()); ASSERT_NO_FATAL_FAILURE(DoUnmount());
EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
// Now the response is ready. // Now the response is ready.
ASSERT_EQ(1u, mock_identity_accessor_.callbacks().size()); identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
std::move(mock_identity_accessor_.callbacks().front()) "auth token", clock_.Now() + kTokenLifetime);
.Run("auth token", clock_.Now() + base::TimeDelta::FromHours(1),
GoogleServiceAuthError(GoogleServiceAuthError::NONE));
mock_identity_accessor_.receivers_->FlushForTesting();
// Second mount will reuse previous token. // Second mount will reuse previous token.
ASSERT_NO_FATAL_FAILURE(DoMount()); ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
EXPECT_EQ("auth token", init_access_token_.value_or("")); EXPECT_EQ("auth token", init_access_token_.value_or(""));
} }
TEST_F(DriveFsHostTest, Remount_RequestInflightCompleteAfterMount) { TEST_F(DriveFsHostTest, Remount_RequestInflightCompleteAfterMount) {
ASSERT_NO_FATAL_FAILURE(DoMount()); ASSERT_NO_FATAL_FAILURE(DoMount());
mock_identity_accessor_.set_pause_requests(true);
delegate_->GetAccessToken( delegate_->GetAccessToken(
"client ID", "app ID", {"scope1", "scope2"}, "client ID", "app ID", {"scope1", "scope2"},
...@@ -777,20 +685,28 @@ TEST_F(DriveFsHostTest, Remount_RequestInflightCompleteAfterMount) { ...@@ -777,20 +685,28 @@ TEST_F(DriveFsHostTest, Remount_RequestInflightCompleteAfterMount) {
SendOnUnmounted(delay); SendOnUnmounted(delay);
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
ASSERT_NO_FATAL_FAILURE(DoUnmount()); ASSERT_NO_FATAL_FAILURE(DoUnmount());
EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
// Second mount will reuse previous token. // Second mount will reuse previous token.
ASSERT_NO_FATAL_FAILURE(DoMount()); ASSERT_NO_FATAL_FAILURE(DoMount());
EXPECT_FALSE(init_access_token_); EXPECT_FALSE(init_access_token_);
EXPECT_TRUE(identity_test_env_.IsAccessTokenRequestPending());
// Now the response is ready. // Now the response is ready.
ASSERT_EQ(1u, mock_identity_accessor_.callbacks().size()); identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
std::move(mock_identity_accessor_.callbacks().front()) "auth token", clock_.Now() + kTokenLifetime);
.Run("auth token", clock_.Now() + base::TimeDelta::FromHours(1), EXPECT_FALSE(identity_test_env_.IsAccessTokenRequestPending());
GoogleServiceAuthError(GoogleServiceAuthError::NONE));
mock_identity_accessor_.receivers_->FlushForTesting();
// A new request will reuse the cached token. // A new request will reuse the cached token.
ExpectAccessToken(mojom::AccessTokenStatus::kSuccess, "auth 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());
} }
} // namespace } // namespace
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "net/base/mime_util.h" #include "net/base/mime_util.h"
#include "url/gurl.h"
namespace drivefs { namespace drivefs {
namespace { namespace {
......
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