Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Lacros] Define available accounts for profiles
This CL defines helper functions that (based on AccountProfileMapper) return the list of accounts - available as primary accounts for a new profile, or - available as secondary accounts for a given profile. To this end, AccountProfileMapper is extended to return the complete mapping. Bug: 1226076 Change-Id: Idf0e3723b0be49d3aaba7911fe87a75c617daf83 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3269214 Commit-Queue: Jan Krcal <jkrcal@chromium.org> Reviewed-by: David Roger <droger@chromium.org> Cr-Commit-Position: refs/heads/main@{#940299}
- Loading branch information
Jan Krcal
authored and
Chromium LUCI CQ
committed
Nov 10, 2021
1 parent
fb26faf
commit 8ac0c8e
Showing
7 changed files
with
460 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
253 changes: 253 additions & 0 deletions
253
chrome/browser/lacros/account_manager/account_manager_util_unittest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,253 @@ | ||
// Copyright 2021 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 "chrome/browser/lacros/account_manager/account_manager_util.h" | ||
|
||
#include <algorithm> | ||
#include <vector> | ||
|
||
#include "base/callback.h" | ||
#include "base/callback_forward.h" | ||
#include "base/containers/flat_map.h" | ||
#include "base/files/file_path.h" | ||
#include "base/test/mock_callback.h" | ||
#include "base/test/scoped_feature_list.h" | ||
#include "chrome/browser/profiles/profile.h" | ||
#include "chrome/browser/profiles/profile_attributes_entry.h" | ||
#include "chrome/browser/profiles/profile_attributes_storage.h" | ||
#include "chrome/browser/profiles/profile_manager.h" | ||
#include "chrome/browser/signin/signin_features.h" | ||
#include "chrome/test/base/testing_browser_process.h" | ||
#include "chrome/test/base/testing_profile_manager.h" | ||
#include "components/account_manager_core/account.h" | ||
#include "components/account_manager_core/account_manager_facade.h" | ||
#include "components/account_manager_core/mock_account_manager_facade.h" | ||
#include "content/public/test/browser_task_environment.h" | ||
#include "google_apis/gaia/google_service_auth_error.h" | ||
#include "testing/gmock/include/gmock/gmock.h" | ||
#include "testing/gtest/include/gtest/gtest.h" | ||
|
||
using account_manager::Account; | ||
using account_manager::AccountKey; | ||
using account_manager::AccountManagerFacade; | ||
using testing::Field; | ||
using testing::UnorderedElementsAre; | ||
|
||
namespace { | ||
|
||
constexpr account_manager::AccountType kGaiaType = | ||
account_manager::AccountType::kGaia; | ||
|
||
// Map from profile path to a vector of GaiaIds. | ||
using AccountMapping = | ||
base::flat_map<base::FilePath, base::flat_set<std::string>>; | ||
|
||
// Synthetizes a `Account` from a Gaia ID, with a dummy email. | ||
Account AccountFromGaiaID(const std::string& gaia_id) { | ||
AccountKey key(gaia_id, kGaiaType); | ||
return {key, gaia_id + std::string("@gmail.com")}; | ||
} | ||
|
||
} // namespace | ||
|
||
class AccountManagerUtilTest : public testing::Test { | ||
public: | ||
AccountManagerUtilTest() | ||
: scoped_feature_list_(kMultiProfileAccountConsistency), | ||
testing_profile_manager_(TestingBrowserProcess::GetGlobal()) { | ||
CHECK(testing_profile_manager_.SetUp()); | ||
main_path_ = GetProfilePath("Default"); | ||
ON_CALL(mock_facade_, GetPersistentErrorForAccount) | ||
.WillByDefault( | ||
[](const AccountKey&, | ||
base::OnceCallback<void(const GoogleServiceAuthError&)> | ||
callback) { | ||
std::move(callback).Run(GoogleServiceAuthError::AuthErrorNone()); | ||
}); | ||
} | ||
|
||
~AccountManagerUtilTest() override = default; | ||
|
||
ProfileAttributesStorage* attributes_storage() { | ||
return &testing_profile_manager_.profile_manager() | ||
->GetProfileAttributesStorage(); | ||
} | ||
|
||
account_manager::MockAccountManagerFacade* mock_facade() { | ||
return &mock_facade_; | ||
} | ||
|
||
const base::FilePath& main_path() { return main_path_; } | ||
|
||
base::FilePath GetProfilePath(const std::string& name) { | ||
return testing_profile_manager_.profiles_dir().AppendASCII(name); | ||
} | ||
|
||
std::unique_ptr<AccountProfileMapper> CreateMapper( | ||
const AccountMapping& accounts) { | ||
// Mapper asks the facade for accounts upon construction. | ||
std::vector<Account> accounts_in_facade; | ||
for (const auto& path_accounts_pair : accounts) { | ||
for (const std::string& id : path_accounts_pair.second) { | ||
accounts_in_facade.push_back(AccountFromGaiaID(id)); | ||
} | ||
} | ||
ON_CALL(mock_facade_, GetAccounts(testing::_)) | ||
.WillByDefault( | ||
[&accounts_in_facade]( | ||
base::OnceCallback<void(const std::vector<Account>&)> | ||
callback) { std::move(callback).Run(accounts_in_facade); }); | ||
auto mapper = std::make_unique<AccountProfileMapper>(mock_facade(), | ||
attributes_storage()); | ||
SetAccountsInStorage(accounts); | ||
return mapper; | ||
} | ||
|
||
// Sets the accounts in `ProfileAttributesStorage`. `accounts_map` is a map | ||
// from profile path to a vector of GaiaIds. One of the profiles must be the | ||
// main profile. | ||
void SetAccountsInStorage(const AccountMapping& accounts_map) { | ||
// Clear all profiles. | ||
testing_profile_manager_.DeleteAllTestingProfiles(); | ||
// Create new profiles. | ||
for (const auto& path_accounts_pair : accounts_map) { | ||
const base::FilePath path = path_accounts_pair.first; | ||
if (path.empty()) | ||
continue; // Account is unassigned. | ||
testing_profile_manager_.CreateTestingProfile( | ||
path.BaseName().MaybeAsASCII()); | ||
} | ||
// Import accounts from the map. | ||
ProfileAttributesStorage* storage = attributes_storage(); | ||
for (const auto& path_accounts_pair : accounts_map) { | ||
const base::FilePath path = path_accounts_pair.first; | ||
if (path.empty()) | ||
continue; // Account is unassigned. | ||
storage->GetProfileAttributesWithPath(path)->SetGaiaIds( | ||
path_accounts_pair.second); | ||
} | ||
} | ||
|
||
void SetPrimaryAccountForProfile(const base::FilePath& profile_path, | ||
const std::string& primary_gaia_id) { | ||
ProfileAttributesStorage* storage = attributes_storage(); | ||
ProfileAttributesEntry* entry = | ||
storage->GetProfileAttributesWithPath(profile_path); | ||
ASSERT_TRUE(entry); | ||
entry->SetAuthInfo(primary_gaia_id, u"Test", | ||
/*is_consented_primary_account=*/true); | ||
} | ||
|
||
private: | ||
base::test::ScopedFeatureList scoped_feature_list_; | ||
content::BrowserTaskEnvironment task_environment_; | ||
testing::NiceMock<account_manager::MockAccountManagerFacade> mock_facade_; | ||
TestingProfileManager testing_profile_manager_; | ||
base::FilePath main_path_; | ||
}; | ||
|
||
TEST_F(AccountManagerUtilTest, GetAccountsAvailableAsPrimary) { | ||
base::FilePath other_path = GetProfilePath("Other"); | ||
std::unique_ptr<AccountProfileMapper> mapper = | ||
CreateMapper({{main_path(), {"A"}}, {other_path, {"B", "C"}}}); | ||
|
||
base::MockRepeatingCallback<void(const std::vector<Account>&)> mock_callback; | ||
|
||
// All the non-syncing accounts are returned. | ||
EXPECT_CALL(mock_callback, | ||
Run(testing::UnorderedElementsAre( | ||
Field(&Account::key, AccountKey{"A", kGaiaType}), | ||
Field(&Account::key, AccountKey{"B", kGaiaType}), | ||
Field(&Account::key, AccountKey{"C", kGaiaType})))); | ||
GetAccountsAvailableAsPrimary(mapper.get(), attributes_storage(), | ||
mock_callback.Get()); | ||
testing::Mock::VerifyAndClearExpectations(&mock_callback); | ||
|
||
// Check that only the non-syncing accounts are returned. | ||
SetPrimaryAccountForProfile(other_path, "B"); | ||
EXPECT_CALL(mock_callback, | ||
Run(testing::UnorderedElementsAre( | ||
Field(&Account::key, AccountKey{"A", kGaiaType}), | ||
Field(&Account::key, AccountKey{"C", kGaiaType})))); | ||
GetAccountsAvailableAsPrimary(mapper.get(), attributes_storage(), | ||
mock_callback.Get()); | ||
testing::Mock::VerifyAndClearExpectations(&mock_callback); | ||
|
||
SetPrimaryAccountForProfile(main_path(), "A"); | ||
EXPECT_CALL(mock_callback, Run(testing::UnorderedElementsAre(Field( | ||
&Account::key, AccountKey{"C", kGaiaType})))); | ||
GetAccountsAvailableAsPrimary(mapper.get(), attributes_storage(), | ||
mock_callback.Get()); | ||
} | ||
|
||
TEST_F(AccountManagerUtilTest, GetAccountsAvailableAsSecondary) { | ||
base::FilePath second_path = GetProfilePath("Second"); | ||
base::FilePath third_path = GetProfilePath("Third"); | ||
base::FilePath unassigned = base::FilePath(); | ||
std::unique_ptr<AccountProfileMapper> mapper = | ||
CreateMapper({{main_path(), {"A"}}, | ||
{second_path, {"B", "C"}}, | ||
{third_path, {"D"}}, | ||
{unassigned, {"E"}}}); | ||
|
||
base::MockRepeatingCallback<void(const std::vector<Account>&)> mock_callback; | ||
|
||
// Accounts from all other profiles are returned, incl. unassigned. | ||
EXPECT_CALL(mock_callback, | ||
Run(testing::UnorderedElementsAre( | ||
Field(&Account::key, AccountKey{"B", kGaiaType}), | ||
Field(&Account::key, AccountKey{"C", kGaiaType}), | ||
Field(&Account::key, AccountKey{"D", kGaiaType}), | ||
Field(&Account::key, AccountKey{"E", kGaiaType})))); | ||
GetAccountsAvailableAsSecondary(mapper.get(), main_path(), | ||
mock_callback.Get()); | ||
testing::Mock::VerifyAndClearExpectations(&mock_callback); | ||
|
||
EXPECT_CALL(mock_callback, | ||
Run(testing::UnorderedElementsAre( | ||
Field(&Account::key, AccountKey{"A", kGaiaType}), | ||
Field(&Account::key, AccountKey{"D", kGaiaType}), | ||
Field(&Account::key, AccountKey{"E", kGaiaType})))); | ||
GetAccountsAvailableAsSecondary(mapper.get(), second_path, | ||
mock_callback.Get()); | ||
testing::Mock::VerifyAndClearExpectations(&mock_callback); | ||
|
||
// Syncing status does not change anything here. | ||
SetPrimaryAccountForProfile(main_path(), "A"); | ||
SetPrimaryAccountForProfile(second_path, "B"); | ||
EXPECT_CALL(mock_callback, | ||
Run(testing::UnorderedElementsAre( | ||
Field(&Account::key, AccountKey{"B", kGaiaType}), | ||
Field(&Account::key, AccountKey{"C", kGaiaType}), | ||
Field(&Account::key, AccountKey{"D", kGaiaType}), | ||
Field(&Account::key, AccountKey{"E", kGaiaType})))); | ||
GetAccountsAvailableAsSecondary(mapper.get(), main_path(), | ||
mock_callback.Get()); | ||
testing::Mock::VerifyAndClearExpectations(&mock_callback); | ||
|
||
EXPECT_CALL(mock_callback, | ||
Run(testing::UnorderedElementsAre( | ||
Field(&Account::key, AccountKey{"A", kGaiaType}), | ||
Field(&Account::key, AccountKey{"D", kGaiaType}), | ||
Field(&Account::key, AccountKey{"E", kGaiaType})))); | ||
GetAccountsAvailableAsSecondary(mapper.get(), second_path, | ||
mock_callback.Get()); | ||
testing::Mock::VerifyAndClearExpectations(&mock_callback); | ||
|
||
// Non existing profile path or empty profile path returns all accounts. | ||
base::FilePath non_existing_path = base::FilePath("Foo"); | ||
EXPECT_CALL(mock_callback, | ||
Run(testing::UnorderedElementsAre( | ||
Field(&Account::key, AccountKey{"A", kGaiaType}), | ||
Field(&Account::key, AccountKey{"B", kGaiaType}), | ||
Field(&Account::key, AccountKey{"C", kGaiaType}), | ||
Field(&Account::key, AccountKey{"D", kGaiaType}), | ||
Field(&Account::key, AccountKey{"E", kGaiaType})))) | ||
.Times(2); | ||
GetAccountsAvailableAsSecondary(mapper.get(), non_existing_path, | ||
mock_callback.Get()); | ||
GetAccountsAvailableAsSecondary(mapper.get(), base::FilePath(), | ||
mock_callback.Get()); | ||
testing::Mock::VerifyAndClearExpectations(&mock_callback); | ||
} |
Oops, something went wrong.