blob: 8cea7258ec18d5655efdf9fba464431eaa430819 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/account_manager_core/chromeos/account_manager_mojo_service.h"
#include <cstddef>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "chromeos/crosapi/mojom/account_manager.mojom-test-utils.h"
#include "chromeos/crosapi/mojom/account_manager.mojom.h"
#include "components/account_manager_core/account.h"
#include "components/account_manager_core/account_manager_util.h"
#include "components/account_manager_core/chromeos/access_token_fetcher.h"
#include "components/account_manager_core/chromeos/account_manager.h"
#include "components/account_manager_core/chromeos/account_manager_ui.h"
#include "components/prefs/testing_pref_service.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_fetcher.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace crosapi {
namespace {
const char kFakeGaiaId[] = "fake-gaia-id";
const char kFakeEmail[] = "fake_email@example.com";
const char kFakeToken[] = "fake-token";
const char kFakeOAuthConsumerName[] = "fake-oauth-consumer-name";
constexpr char kFakeAccessToken[] = "fake-access-token";
// Same access token value as above in `kFakeAccessToken`.
constexpr char kAccessTokenResponse[] = R"(
{
"access_token": "fake-access-token",
"expires_in": 3600,
"token_type": "Bearer",
"id_token": "id_token"
})";
const account_manager::Account kFakeAccount = account_manager::Account{
account_manager::AccountKey{kFakeGaiaId,
account_manager::AccountType::kGaia},
kFakeEmail};
} // namespace
class TestAccountManagerObserver
: public mojom::AccountManagerObserverInterceptorForTesting {
public:
TestAccountManagerObserver() : receiver_(this) {}
TestAccountManagerObserver(const TestAccountManagerObserver&) = delete;
TestAccountManagerObserver& operator=(const TestAccountManagerObserver&) =
delete;
~TestAccountManagerObserver() override = default;
void Observe(
mojom::AccountManagerAsyncWaiter* const account_manager_async_waiter) {
mojo::PendingReceiver<mojom::AccountManagerObserver> receiver;
account_manager_async_waiter->AddObserver(&receiver);
receiver_.Bind(std::move(receiver));
}
int GetNumOnTokenUpsertedCalls() const { return num_token_upserted_calls_; }
account_manager::Account GetLastUpsertedAccount() const {
return last_upserted_account_;
}
int GetNumOnAccountRemovedCalls() const { return num_account_removed_calls_; }
account_manager::Account GetLastRemovedAccount() const {
return last_removed_account_;
}
private:
// mojom::AccountManagerObserverInterceptorForTesting override:
AccountManagerObserver* GetForwardingInterface() override { return this; }
// mojom::AccountManagerObserverInterceptorForTesting override:
void OnTokenUpserted(mojom::AccountPtr account) override {
++num_token_upserted_calls_;
last_upserted_account_ = account_manager::FromMojoAccount(account).value();
}
// mojom::AccountManagerObserverInterceptorForTesting override:
void OnAccountRemoved(mojom::AccountPtr account) override {
++num_account_removed_calls_;
last_removed_account_ = account_manager::FromMojoAccount(account).value();
}
int num_token_upserted_calls_ = 0;
int num_account_removed_calls_ = 0;
account_manager::Account last_upserted_account_;
account_manager::Account last_removed_account_;
mojo::Receiver<mojom::AccountManagerObserver> receiver_;
};
class FakeAccountManagerUI : public account_manager::AccountManagerUI {
public:
FakeAccountManagerUI() = default;
FakeAccountManagerUI(const FakeAccountManagerUI&) = delete;
FakeAccountManagerUI& operator=(const FakeAccountManagerUI&) = delete;
~FakeAccountManagerUI() override = default;
void SetIsDialogShown(bool is_dialog_shown) {
is_dialog_shown_ = is_dialog_shown;
}
void CloseDialog() {
if (!close_dialog_closure_.is_null()) {
std::move(close_dialog_closure_).Run();
}
is_dialog_shown_ = false;
}
int show_account_addition_dialog_calls() const {
return show_account_addition_dialog_calls_;
}
int show_account_reauthentication_dialog_calls() const {
return show_account_reauthentication_dialog_calls_;
}
int show_manage_accounts_settings_calls() const {
return show_manage_accounts_settings_calls_;
}
private:
// AccountManagerUI overrides:
void ShowAddAccountDialog(base::OnceClosure close_dialog_closure) override {
close_dialog_closure_ = std::move(close_dialog_closure);
show_account_addition_dialog_calls_++;
is_dialog_shown_ = true;
}
void ShowReauthAccountDialog(
const std::string& email,
base::OnceClosure close_dialog_closure) override {
close_dialog_closure_ = std::move(close_dialog_closure);
show_account_reauthentication_dialog_calls_++;
is_dialog_shown_ = true;
}
bool IsDialogShown() override { return is_dialog_shown_; }
void ShowManageAccountsSettings() override {
show_manage_accounts_settings_calls_++;
}
base::OnceClosure close_dialog_closure_;
bool is_dialog_shown_ = false;
int show_account_addition_dialog_calls_ = 0;
int show_account_reauthentication_dialog_calls_ = 0;
int show_manage_accounts_settings_calls_ = 0;
};
// A test spy for intercepting AccountManager calls.
class AccountManagerSpy : public account_manager::AccountManager {
public:
AccountManagerSpy() = default;
AccountManagerSpy(const AccountManagerSpy&) = delete;
AccountManagerSpy& operator=(const AccountManagerSpy&) = delete;
~AccountManagerSpy() override = default;
// account_manager::AccountManager override:
std::unique_ptr<OAuth2AccessTokenFetcher> CreateAccessTokenFetcher(
const ::account_manager::AccountKey& account_key,
OAuth2AccessTokenConsumer* consumer) override {
num_access_token_fetches_++;
last_access_token_account_key_ = account_key;
return account_manager::AccountManager::CreateAccessTokenFetcher(
account_key, consumer);
}
int num_access_token_fetches() const { return num_access_token_fetches_; }
account_manager::AccountKey last_access_token_account_key() const {
return last_access_token_account_key_;
}
private:
// Mutated by const CreateAccessTokenFetcher.
mutable int num_access_token_fetches_ = 0;
mutable account_manager::AccountKey last_access_token_account_key_;
};
class AccountManagerMojoServiceTest : public ::testing::Test {
public:
AccountManagerMojoServiceTest() = default;
AccountManagerMojoServiceTest(const AccountManagerMojoServiceTest&) = delete;
AccountManagerMojoServiceTest& operator=(
const AccountManagerMojoServiceTest&) = delete;
~AccountManagerMojoServiceTest() override = default;
protected:
void SetUp() override {
account_manager_mojo_service_ =
std::make_unique<AccountManagerMojoService>(&account_manager_);
account_manager_mojo_service_->SetAccountManagerUI(
std::make_unique<FakeAccountManagerUI>());
account_manager_mojo_service_->BindReceiver(
remote_.BindNewPipeAndPassReceiver());
account_manager_async_waiter_ =
std::make_unique<mojom::AccountManagerAsyncWaiter>(
account_manager_mojo_service_.get());
}
void RunAllPendingTasks() { task_environment_.RunUntilIdle(); }
void FlushMojoForTesting() {
account_manager_mojo_service_->FlushMojoForTesting();
}
// Returns |true| if initialization was successful.
bool InitializeAccountManager() {
base::RunLoop run_loop;
account_manager_.InitializeInEphemeralMode(
test_url_loader_factory_.GetSafeWeakWrapper(), run_loop.QuitClosure());
account_manager_.SetPrefService(&pref_service_);
account_manager_.RegisterPrefs(pref_service_.registry());
run_loop.Run();
return account_manager_.IsInitialized();
}
FakeAccountManagerUI* GetFakeAccountManagerUI() {
return static_cast<FakeAccountManagerUI*>(
account_manager_mojo_service_->account_manager_ui_.get());
}
mojom::AccountAdditionResultPtr ShowAddAccountDialog(
base::OnceClosure quit_closure) {
auto add_account_result = mojom::AccountAdditionResult::New();
account_manager_mojo_service_->ShowAddAccountDialog(base::BindOnce(
[](base::OnceClosure quit_closure,
mojom::AccountAdditionResultPtr* add_account_result,
mojom::AccountAdditionResultPtr result) {
(*add_account_result)->status = result->status;
(*add_account_result)->account = std::move(result->account);
std::move(quit_closure).Run();
},
std::move(quit_closure), &add_account_result));
return add_account_result;
}
void ShowReauthAccountDialog(const std::string& email,
base::OnceClosure close_dialog_closure) {
account_manager_mojo_service_->ShowReauthAccountDialog(
email, std::move(close_dialog_closure));
}
void CallAccountAdditionFinished(
const account_manager::AccountAdditionResult& result) {
account_manager_mojo_service_->OnAccountAdditionFinished(result);
GetFakeAccountManagerUI()->CloseDialog();
}
void ShowManageAccountsSettings() {
account_manager_mojo_service_->ShowManageAccountsSettings();
}
mojom::AccessTokenResultPtr FetchAccessToken(
const account_manager::AccountKey& account_key) {
return FetchAccessToken(account_key, /*scopes=*/{});
}
mojom::AccessTokenResultPtr FetchAccessToken(
const account_manager::AccountKey& account_key,
const std::vector<std::string>& scopes) {
mojo::PendingRemote<mojom::AccessTokenFetcher> pending_remote;
account_manager_async_waiter()->CreateAccessTokenFetcher(
account_manager::ToMojoAccountKey(account_key), kFakeOAuthConsumerName,
&pending_remote);
mojo::Remote<mojom::AccessTokenFetcher> remote(std::move(pending_remote));
base::RunLoop run_loop;
mojom::AccessTokenResultPtr result;
remote->Start(
scopes,
base::BindLambdaForTesting(
[&run_loop, &result](mojom::AccessTokenResultPtr returned_result) {
result = std::move(returned_result);
run_loop.Quit();
}));
run_loop.Run();
return result;
}
void AddFakeAccessTokenResponse() {
GURL url(GaiaUrls::GetInstance()->oauth2_token_url());
test_url_loader_factory_.AddResponse(url.spec(), kAccessTokenResponse,
net::HTTP_OK);
}
int GetNumObservers() const {
return account_manager_mojo_service_->observers_.size();
}
int GetNumPendingAccessTokenRequests() const {
return account_manager_mojo_service_->GetNumPendingAccessTokenRequests();
}
mojom::AccountManagerAsyncWaiter* account_manager_async_waiter() {
return account_manager_async_waiter_.get();
}
AccountManagerSpy* account_manager() { return &account_manager_; }
private:
base::test::SingleThreadTaskEnvironment task_environment_;
network::TestURLLoaderFactory test_url_loader_factory_;
TestingPrefServiceSimple pref_service_;
AccountManagerSpy account_manager_;
mojo::Remote<mojom::AccountManager> remote_;
std::unique_ptr<AccountManagerMojoService> account_manager_mojo_service_;
std::unique_ptr<mojom::AccountManagerAsyncWaiter>
account_manager_async_waiter_;
};
TEST_F(AccountManagerMojoServiceTest,
IsInitializedReturnsFalseForUninitializedAccountManager) {
bool is_initialized = true;
account_manager_async_waiter()->IsInitialized(&is_initialized);
EXPECT_FALSE(is_initialized);
}
TEST_F(AccountManagerMojoServiceTest,
IsInitializedReturnsTrueForInitializedAccountManager) {
bool is_initialized = true;
account_manager_async_waiter()->IsInitialized(&is_initialized);
EXPECT_FALSE(is_initialized);
ASSERT_TRUE(InitializeAccountManager());
account_manager_async_waiter()->IsInitialized(&is_initialized);
EXPECT_TRUE(is_initialized);
}
// Test that lacros remotes do not leak.
TEST_F(AccountManagerMojoServiceTest,
LacrosRemotesAreAutomaticallyRemovedOnConnectionClose) {
EXPECT_EQ(0, GetNumObservers());
{
mojo::PendingReceiver<mojom::AccountManagerObserver> receiver;
account_manager_async_waiter()->AddObserver(&receiver);
EXPECT_EQ(1, GetNumObservers());
}
// Wait for the disconnect handler to be called.
RunAllPendingTasks();
EXPECT_EQ(0, GetNumObservers());
}
TEST_F(AccountManagerMojoServiceTest,
LacrosObserversAreNotifiedOnAccountUpdates) {
const account_manager::AccountKey kTestAccountKey{
kFakeGaiaId, account_manager::AccountType::kGaia};
ASSERT_TRUE(InitializeAccountManager());
TestAccountManagerObserver observer;
observer.Observe(account_manager_async_waiter());
ASSERT_EQ(1, GetNumObservers());
EXPECT_EQ(0, observer.GetNumOnTokenUpsertedCalls());
account_manager()->UpsertAccount(kTestAccountKey, kFakeEmail, kFakeToken);
FlushMojoForTesting();
EXPECT_EQ(1, observer.GetNumOnTokenUpsertedCalls());
EXPECT_EQ(kTestAccountKey, observer.GetLastUpsertedAccount().key);
EXPECT_EQ(kFakeEmail, observer.GetLastUpsertedAccount().raw_email);
}
TEST_F(AccountManagerMojoServiceTest,
LacrosObserversAreNotifiedOnAccountRemovals) {
const account_manager::AccountKey kTestAccountKey{
kFakeGaiaId, account_manager::AccountType::kGaia};
ASSERT_TRUE(InitializeAccountManager());
TestAccountManagerObserver observer;
observer.Observe(account_manager_async_waiter());
ASSERT_EQ(1, GetNumObservers());
account_manager()->UpsertAccount(kTestAccountKey, kFakeEmail, kFakeToken);
FlushMojoForTesting();
EXPECT_EQ(0, observer.GetNumOnAccountRemovedCalls());
account_manager()->RemoveAccount(kTestAccountKey);
FlushMojoForTesting();
EXPECT_EQ(1, observer.GetNumOnAccountRemovedCalls());
EXPECT_EQ(kTestAccountKey, observer.GetLastRemovedAccount().key);
EXPECT_EQ(kFakeEmail, observer.GetLastRemovedAccount().raw_email);
}
TEST_F(AccountManagerMojoServiceTest, GetAccounts) {
ASSERT_TRUE(InitializeAccountManager());
{
std::vector<mojom::AccountPtr> accounts;
account_manager_async_waiter()->GetAccounts(&accounts);
EXPECT_TRUE(accounts.empty());
}
const account_manager::AccountKey kTestAccountKey{
kFakeGaiaId, account_manager::AccountType::kGaia};
account_manager()->UpsertAccount(kTestAccountKey, kFakeEmail, kFakeToken);
std::vector<mojom::AccountPtr> accounts;
account_manager_async_waiter()->GetAccounts(&accounts);
EXPECT_EQ(1UL, accounts.size());
EXPECT_EQ(kFakeEmail, accounts[0]->raw_email);
EXPECT_EQ(kFakeGaiaId, accounts[0]->key->id);
EXPECT_EQ(mojom::AccountType::kGaia, accounts[0]->key->account_type);
}
TEST_F(AccountManagerMojoServiceTest,
ShowAddAccountDialogReturnsInProgressIfDialogIsOpen) {
EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
GetFakeAccountManagerUI()->SetIsDialogShown(true);
mojom::AccountAdditionResultPtr account_addition_result;
account_manager_async_waiter()->ShowAddAccountDialog(
&account_addition_result);
// Check status.
EXPECT_EQ(mojom::AccountAdditionResult::Status::kAlreadyInProgress,
account_addition_result->status);
// Check that dialog was not called.
EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
}
TEST_F(AccountManagerMojoServiceTest,
ShowAddAccountDialogReturnsCancelledAfterDialogIsClosed) {
EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
GetFakeAccountManagerUI()->SetIsDialogShown(false);
base::RunLoop run_loop;
mojom::AccountAdditionResultPtr account_addition_result =
ShowAddAccountDialog(run_loop.QuitClosure());
// Simulate closing the dialog.
GetFakeAccountManagerUI()->CloseDialog();
run_loop.Run();
// Check status.
EXPECT_EQ(mojom::AccountAdditionResult::Status::kCancelledByUser,
account_addition_result->status);
// Check that dialog was called once.
EXPECT_EQ(1, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
}
TEST_F(AccountManagerMojoServiceTest,
ShowAddAccountDialogReturnsSuccessAfterAccountIsAdded) {
EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
GetFakeAccountManagerUI()->SetIsDialogShown(false);
base::RunLoop run_loop;
mojom::AccountAdditionResultPtr account_addition_result =
ShowAddAccountDialog(run_loop.QuitClosure());
// Simulate account addition.
CallAccountAdditionFinished(
account_manager::AccountAdditionResult::FromAccount(kFakeAccount));
// Simulate closing the dialog.
GetFakeAccountManagerUI()->CloseDialog();
run_loop.Run();
// Check status.
EXPECT_EQ(mojom::AccountAdditionResult::Status::kSuccess,
account_addition_result->status);
// Check account.
absl::optional<account_manager::Account> account =
account_manager::FromMojoAccount(account_addition_result->account);
EXPECT_TRUE(account.has_value());
EXPECT_EQ(kFakeAccount.key, account.value().key);
EXPECT_EQ(kFakeAccount.raw_email, account.value().raw_email);
// Check that dialog was called once.
EXPECT_EQ(1, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
}
TEST_F(AccountManagerMojoServiceTest,
ShowAddAccountDialogCanHandleMultipleCalls) {
EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
GetFakeAccountManagerUI()->SetIsDialogShown(false);
base::RunLoop run_loop;
mojom::AccountAdditionResultPtr account_addition_result =
ShowAddAccountDialog(run_loop.QuitClosure());
base::RunLoop run_loop_2;
mojom::AccountAdditionResultPtr account_addition_result_2 =
ShowAddAccountDialog(run_loop_2.QuitClosure());
run_loop_2.Run();
// The second call gets 'kAlreadyInProgress' reply.
EXPECT_EQ(mojom::AccountAdditionResult::Status::kAlreadyInProgress,
account_addition_result_2->status);
// Simulate account addition.
CallAccountAdditionFinished(
account_manager::AccountAdditionResult::FromAccount(kFakeAccount));
// Simulate closing the dialog.
GetFakeAccountManagerUI()->CloseDialog();
run_loop.Run();
EXPECT_EQ(mojom::AccountAdditionResult::Status::kSuccess,
account_addition_result->status);
// Check account.
absl::optional<account_manager::Account> account =
account_manager::FromMojoAccount(account_addition_result->account);
EXPECT_TRUE(account.has_value());
EXPECT_EQ(kFakeAccount.key, account.value().key);
EXPECT_EQ(kFakeAccount.raw_email, account.value().raw_email);
// Check that dialog was called once.
EXPECT_EQ(1, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
}
TEST_F(AccountManagerMojoServiceTest,
ShowAddAccountDialogCanHandleMultipleSequentialCalls) {
EXPECT_EQ(0, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
GetFakeAccountManagerUI()->SetIsDialogShown(false);
base::RunLoop run_loop;
mojom::AccountAdditionResultPtr account_addition_result =
ShowAddAccountDialog(run_loop.QuitClosure());
// Simulate account addition.
CallAccountAdditionFinished(
account_manager::AccountAdditionResult::FromAccount(kFakeAccount));
// Simulate closing the dialog.
GetFakeAccountManagerUI()->CloseDialog();
run_loop.Run();
EXPECT_EQ(mojom::AccountAdditionResult::Status::kSuccess,
account_addition_result->status);
// Check account.
absl::optional<account_manager::Account> account =
account_manager::FromMojoAccount(account_addition_result->account);
EXPECT_TRUE(account.has_value());
EXPECT_EQ(kFakeAccount.key, account.value().key);
EXPECT_EQ(kFakeAccount.raw_email, account.value().raw_email);
base::RunLoop run_loop_2;
mojom::AccountAdditionResultPtr account_addition_result_2 =
ShowAddAccountDialog(run_loop_2.QuitClosure());
// Simulate account addition.
CallAccountAdditionFinished(
account_manager::AccountAdditionResult::FromAccount(kFakeAccount));
// Simulate closing the dialog.
GetFakeAccountManagerUI()->CloseDialog();
run_loop_2.Run();
EXPECT_EQ(mojom::AccountAdditionResult::Status::kSuccess,
account_addition_result_2->status);
// Check account.
absl::optional<account_manager::Account> account_2 =
account_manager::FromMojoAccount(account_addition_result_2->account);
EXPECT_TRUE(account_2.has_value());
EXPECT_EQ(kFakeAccount.key, account_2.value().key);
EXPECT_EQ(kFakeAccount.raw_email, account_2.value().raw_email);
// Check that dialog was called 2 times.
EXPECT_EQ(2, GetFakeAccountManagerUI()->show_account_addition_dialog_calls());
}
TEST_F(AccountManagerMojoServiceTest,
ShowReauthAccountDialogDoesntCallTheDialogIfItsAlreadyShown) {
EXPECT_EQ(
0,
GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
GetFakeAccountManagerUI()->SetIsDialogShown(true);
base::RunLoop run_loop;
// Simulate account reauthentication.
ShowReauthAccountDialog(kFakeEmail, run_loop.QuitClosure());
// Simulate closing the dialog.
GetFakeAccountManagerUI()->CloseDialog();
// Check that dialog was not called.
EXPECT_EQ(
0,
GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
}
TEST_F(AccountManagerMojoServiceTest, ShowReauthAccountDialogOpensTheDialog) {
EXPECT_EQ(
0,
GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
GetFakeAccountManagerUI()->SetIsDialogShown(false);
base::RunLoop run_loop;
// Simulate account reauthentication.
ShowReauthAccountDialog(kFakeEmail, run_loop.QuitClosure());
// Simulate closing the dialog.
GetFakeAccountManagerUI()->CloseDialog();
// Check that dialog was called once.
EXPECT_EQ(
1,
GetFakeAccountManagerUI()->show_account_reauthentication_dialog_calls());
}
TEST_F(AccountManagerMojoServiceTest, ShowManageAccountSettingsTest) {
EXPECT_EQ(0,
GetFakeAccountManagerUI()->show_manage_accounts_settings_calls());
ShowManageAccountsSettings();
EXPECT_EQ(1,
GetFakeAccountManagerUI()->show_manage_accounts_settings_calls());
}
TEST_F(AccountManagerMojoServiceTest,
FetchingAccessTokenResultsInErrorForInvalidAccountKey) {
ASSERT_TRUE(InitializeAccountManager());
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
account_manager::AccountKey account_key{std::string(),
account_manager::AccountType::kGaia};
mojom::AccessTokenResultPtr result = FetchAccessToken(account_key);
ASSERT_TRUE(result->is_error());
EXPECT_EQ(mojom::GoogleServiceAuthError::State::kUserNotSignedUp,
result->get_error()->state);
// Check that requests are not leaking.
RunAllPendingTasks();
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
}
TEST_F(AccountManagerMojoServiceTest,
FetchingAccessTokenResultsInErrorForActiveDirectoryAccounts) {
ASSERT_TRUE(InitializeAccountManager());
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
account_manager::AccountKey account_key{
kFakeGaiaId, account_manager::AccountType::kActiveDirectory};
mojom::AccessTokenResultPtr result = FetchAccessToken(account_key);
ASSERT_TRUE(result->is_error());
EXPECT_EQ(mojom::GoogleServiceAuthError::State::kUserNotSignedUp,
result->get_error()->state);
// Check that requests are not leaking.
RunAllPendingTasks();
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
}
TEST_F(AccountManagerMojoServiceTest,
FetchingAccessTokenResultsInErrorForUnknownAccountKey) {
ASSERT_TRUE(InitializeAccountManager());
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
account_manager::AccountKey account_key{kFakeGaiaId,
account_manager::AccountType::kGaia};
mojom::AccessTokenResultPtr result = FetchAccessToken(account_key);
ASSERT_TRUE(result->is_error());
EXPECT_EQ(mojom::GoogleServiceAuthError::State::kUserNotSignedUp,
result->get_error()->state);
// Check that requests are not leaking.
RunAllPendingTasks();
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
}
TEST_F(AccountManagerMojoServiceTest, FetchAccessTokenRequestsCanBeCancelled) {
// Setup.
ASSERT_TRUE(InitializeAccountManager());
account_manager::AccountKey account_key{kFakeGaiaId,
account_manager::AccountType::kGaia};
account_manager()->UpsertAccount(account_key, kFakeEmail, kFakeToken);
mojo::PendingRemote<mojom::AccessTokenFetcher> pending_remote;
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
account_manager_async_waiter()->CreateAccessTokenFetcher(
account_manager::ToMojoAccountKey(account_key), kFakeOAuthConsumerName,
&pending_remote);
mojo::Remote<mojom::AccessTokenFetcher> remote(std::move(pending_remote));
mojom::AccessTokenResultPtr result;
EXPECT_TRUE(result.is_null());
// Make a request to fetch access token. Since we haven't setup our test URL
// loader factory via `AddFakeAccessTokenResponse`, this request will never be
// completed.
remote->Start(/*scopes=*/{},
base::BindLambdaForTesting(
[&result](mojom::AccessTokenResultPtr returned_result) {
result = std::move(returned_result);
}));
EXPECT_EQ(1, GetNumPendingAccessTokenRequests());
// Test.
// This should cancel the pending request.
remote.reset();
RunAllPendingTasks();
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
// Verify that result is still unset - i.e. the pending request was cancelled,
// and didn't complete normally.
EXPECT_TRUE(result.is_null());
}
TEST_F(AccountManagerMojoServiceTest, FetchAccessToken) {
constexpr char kFakeScope[] = "fake-scope";
ASSERT_TRUE(InitializeAccountManager());
account_manager::AccountKey account_key{kFakeGaiaId,
account_manager::AccountType::kGaia};
account_manager()->UpsertAccount(account_key, kFakeEmail, kFakeToken);
AddFakeAccessTokenResponse();
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
mojom::AccessTokenResultPtr result =
FetchAccessToken(account_key, {kFakeScope});
ASSERT_TRUE(result->is_access_token_info());
EXPECT_EQ(kFakeAccessToken, result->get_access_token_info()->access_token);
EXPECT_EQ(1, account_manager()->num_access_token_fetches());
EXPECT_EQ(account_key, account_manager()->last_access_token_account_key());
// Check that requests are not leaking.
RunAllPendingTasks();
EXPECT_EQ(0, GetNumPendingAccessTokenRequests());
}
} // namespace crosapi