Commit 1cdf916d authored by Nela Kaczmarek's avatar Nela Kaczmarek Committed by Commit Bot

[Passwords] Affiliation Service implementation.

This change covers the implementation of AffiliationService, the AffiliationFetcherDelegate interface implementation and unit tests.
It prefetches data with a help of AffiliationFetcher and provides an API to get change password urls for requested origin.
This change includes only preparing data for prefetch without processing the response.

Bug: 1108279
Change-Id: I3f47a3b1f7c0b99726b4107d484387a77b1345b3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2332604
Commit-Queue: Nela Kaczmarek <nelakaczmarek@google.com>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799852}
parent 93c3b06a
......@@ -36,5 +36,10 @@ KeyedService* AffiliationServiceFactory::BuildServiceInstanceFor(
Profile* profile = Profile::FromBrowserContext(context);
syncer::SyncService* sync_service =
ProfileSyncServiceFactory::GetForProfile(profile);
return new password_manager::AffiliationServiceImpl(sync_service);
network::SharedURLLoaderFactory* url_loader_factory =
context->GetDefaultStoragePartition(profile)
->GetURLLoaderFactoryForBrowserProcess()
.get();
return new password_manager::AffiliationServiceImpl(sync_service,
url_loader_factory);
}
......@@ -40,7 +40,7 @@ class PendingSharedURLLoaderFactory;
namespace password_manager {
class AffiliationDatabase;
class AffiliationFetcher;
class AffiliationFetcherInterface;
class AffiliationFetchThrottler;
class FacetManager;
......@@ -151,7 +151,7 @@ class AffiliationBackend : public FacetManagerHost,
const base::TickClock* tick_clock_;
std::unique_ptr<AffiliationDatabase> cache_;
std::unique_ptr<AffiliationFetcher> fetcher_;
std::unique_ptr<AffiliationFetcherInterface> fetcher_;
std::unique_ptr<AffiliationFetchThrottler> throttler_;
base::Time construction_time_;
......
......@@ -55,7 +55,7 @@ AffiliationFetcher::AffiliationFetcher(
AffiliationFetcher::~AffiliationFetcher() = default;
// static
AffiliationFetcher* AffiliationFetcher::Create(
AffiliationFetcherInterface* AffiliationFetcher::Create(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AffiliationFetcherDelegate* delegate) {
if (g_testing_factory) {
......
......@@ -30,6 +30,8 @@ class TestAffiliationFetcherFactory;
//
// An instance is good for exactly one fetch, and may be used from any thread
// that runs a message loop (i.e. not a worker pool thread).
// TODO(crbug.com/1117447): Create and SetFactoryForTesting methods should be
// moved to a factory responsible for creating AffiliationFetcher instances.
class AffiliationFetcher : public AffiliationFetcherInterface {
public:
~AffiliationFetcher() override;
......@@ -37,7 +39,7 @@ class AffiliationFetcher : public AffiliationFetcherInterface {
// Constructs a fetcher using the specified |url_loader_factory|, and will
// provide the results to the |delegate| on the same thread that creates the
// instance.
static AffiliationFetcher* Create(
static AffiliationFetcherInterface* Create(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AffiliationFetcherDelegate* delegate);
......
......@@ -13,6 +13,7 @@
#include "base/test/null_task_runner.h"
#include "base/test/task_environment.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_api.pb.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher_interface.h"
#include "net/base/url_util.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
......@@ -152,7 +153,7 @@ TEST_F(AffiliationFetcherTest, BasicReqestAndResponse) {
SetupSuccessfulResponse(test_response.SerializeAsString());
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnFetchSucceededProxy());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(requested_uris);
WaitForResponse();
......@@ -191,7 +192,7 @@ TEST_F(AffiliationFetcherTest, AndroidBrandingInfoIsReturnedIfPresent) {
SetupSuccessfulResponse(test_response.SerializeAsString());
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnFetchSucceededProxy());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(requested_uris);
WaitForResponse();
......@@ -222,7 +223,7 @@ TEST_F(AffiliationFetcherTest, MissingEquivalenceClassesAreCreated) {
SetupSuccessfulResponse(empty_test_response.SerializeAsString());
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnFetchSucceededProxy());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(requested_uris);
WaitForResponse();
......@@ -253,7 +254,7 @@ TEST_F(AffiliationFetcherTest, DuplicateEquivalenceClassesAreIgnored) {
SetupSuccessfulResponse(test_response.SerializeAsString());
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnFetchSucceededProxy());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(requested_uris);
WaitForResponse();
......@@ -281,7 +282,7 @@ TEST_F(AffiliationFetcherTest, EmptyEquivalenceClassesAreIgnored) {
SetupSuccessfulResponse(test_response.SerializeAsString());
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnFetchSucceededProxy());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(requested_uris);
WaitForResponse();
......@@ -313,7 +314,7 @@ TEST_F(AffiliationFetcherTest, UnrecognizedFacetURIsAreIgnored) {
SetupSuccessfulResponse(test_response.SerializeAsString());
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnFetchSucceededProxy());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(requested_uris);
WaitForResponse();
......@@ -337,7 +338,7 @@ TEST_F(AffiliationFetcherTest, FailureBecauseResponseIsNotAProtobuf) {
SetupSuccessfulResponse(kMalformedResponse);
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnMalformedResponse());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(uris);
WaitForResponse();
......@@ -361,7 +362,7 @@ TEST_F(AffiliationFetcherTest,
SetupSuccessfulResponse(test_response.SerializeAsString());
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnMalformedResponse());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(uris);
WaitForResponse();
......@@ -374,7 +375,7 @@ TEST_F(AffiliationFetcherTest, FailOnServerError) {
SetupServerErrorResponse();
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnFetchFailed());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(uris);
WaitForResponse();
......@@ -387,7 +388,7 @@ TEST_F(AffiliationFetcherTest, FailOnNetworkError) {
SetupNetworkErrorResponse();
MockAffiliationFetcherDelegate mock_delegate;
EXPECT_CALL(mock_delegate, OnFetchFailed());
std::unique_ptr<AffiliationFetcher> fetcher(
std::unique_ptr<AffiliationFetcherInterface> fetcher(
AffiliationFetcher::Create(test_shared_loader_factory(), &mock_delegate));
fetcher->StartRequest(uris);
WaitForResponse();
......
......@@ -47,7 +47,7 @@ FakeAffiliationFetcher* ScopedFakeAffiliationFetcherFactory::PeekNextFetcher() {
return pending_fetchers_.front();
}
AffiliationFetcher* ScopedFakeAffiliationFetcherFactory::CreateInstance(
FakeAffiliationFetcher* ScopedFakeAffiliationFetcherFactory::CreateInstance(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AffiliationFetcherDelegate* delegate) {
FakeAffiliationFetcher* fetcher =
......
......@@ -17,6 +17,8 @@ namespace password_manager {
// A fake AffiliationFetcher that can be used in tests to return fake API
// responses to users of AffiliationFetcher.
// TODO(crbug.com/1117445): FakeAffiliationFetcher should implement
// AffiliationFetcherInterface.
class FakeAffiliationFetcher : public AffiliationFetcher {
public:
FakeAffiliationFetcher(
......@@ -63,7 +65,7 @@ class ScopedFakeAffiliationFetcherFactory
bool has_pending_fetchers() const { return !pending_fetchers_.empty(); }
// AffiliationFetcherFactory:
AffiliationFetcher* CreateInstance(
FakeAffiliationFetcher* CreateInstance(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AffiliationFetcherDelegate* delegate) override;
......
......@@ -5,7 +5,7 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_TEST_AFFILIATION_FETCHER_FACTORY_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_TEST_AFFILIATION_FETCHER_FACTORY_H_
#include <vector>
#include "base/memory/scoped_refptr.h"
namespace network {
class SharedURLLoaderFactory;
......@@ -13,6 +13,7 @@ class SharedURLLoaderFactory;
namespace password_manager {
class AffiliationFetcherInterface;
class AffiliationFetcherDelegate;
// Interface for a factory to be used by AffiliationFetcher::Create() in tests
......@@ -21,15 +22,20 @@ class AffiliationFetcherDelegate;
// The factory is registered with AffiliationFetcher::SetFactoryForTesting().
class TestAffiliationFetcherFactory {
public:
TestAffiliationFetcherFactory(const TestAffiliationFetcherFactory&) = delete;
TestAffiliationFetcherFactory& operator=(
const TestAffiliationFetcherFactory&) = delete;
// Constructs a fetcher to retrieve affiliations for each facet in |facet_ids|
// using the specified |url_loader_factory|, and will provide the results
// to the |delegate| on the same thread that creates the instance.
virtual AffiliationFetcher* CreateInstance(
virtual AffiliationFetcherInterface* CreateInstance(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AffiliationFetcherDelegate* delegate) = 0;
protected:
virtual ~TestAffiliationFetcherFactory() {}
TestAffiliationFetcherFactory() = default;
virtual ~TestAffiliationFetcherFactory() = default;
};
} // namespace password_manager
......
......@@ -22,13 +22,6 @@ namespace password_manager {
namespace {
bool ShouldAffiliationBasedMatchingBeActive(syncer::SyncService* sync_service) {
return sync_service && sync_service->IsSyncFeatureActive() &&
sync_service->GetUserSettings()->GetSelectedTypes().Has(
syncer::UserSelectableType::kPasswords) &&
!sync_service->GetUserSettings()->IsUsingSecondaryPassphrase();
}
void ActivateAffiliationBasedMatching(
PasswordStore* password_store,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
......@@ -117,4 +110,11 @@ base::FilePath GetLoginDatabaseForAccountStoragePathForTesting(
return profile_path.Append(kLoginDataForAccountFileName);
}
bool ShouldAffiliationBasedMatchingBeActive(syncer::SyncService* sync_service) {
return sync_service && sync_service->IsSyncFeatureActive() &&
sync_service->GetUserSettings()->GetSelectedTypes().Has(
syncer::UserSelectableType::kPasswords) &&
!sync_service->GetUserSettings()->IsUsingSecondaryPassphrase();
}
} // namespace password_manager
......@@ -50,6 +50,15 @@ void DeleteLoginDatabaseForAccountStorageFiles(
base::FilePath GetLoginDatabaseForAccountStoragePathForTesting(
const base::FilePath& profile_path);
// Determines if affiliation based matching can be performed.
// It checks whether the user
// 1) has password syncing across multiple devices enabled
// (first setup must be completed)
// 2) does not have secondary passphrase set.
// Failure to meet both of those requirements results in preventing Chrome from
// sending requests to Google Affiliation Service API.
bool ShouldAffiliationBasedMatchingBeActive(syncer::SyncService* sync_service);
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_STORE_FACTORY_UTIL_H_
......@@ -7,13 +7,12 @@
#include <vector>
#include "base/optional.h"
#include "components/keyed_service/core/keyed_service.h"
class GURL;
namespace url {
class Origin;
class SchemeHostPort;
}
namespace password_manager {
......@@ -22,13 +21,14 @@ class AffiliationService : public KeyedService {
public:
// Prefetches change password URLs for sites requested.
virtual void PrefetchChangePasswordURLs(
const std::vector<url::Origin>& origins) = 0;
const std::vector<url::SchemeHostPort>& tuple_origins) = 0;
// Clears the result of URLs fetch.
virtual void Clear() = 0;
// Returns a URL with change password form for a site requested.
virtual GURL GetChangePasswordURL(const url::Origin& origin) = 0;
virtual GURL GetChangePasswordURL(
const url::SchemeHostPort& scheme_host_port) const = 0;
};
} // namespace password_manager
......
......@@ -4,47 +4,68 @@
#include "components/password_manager/core/browser/site_affiliation/affiliation_service_impl.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher.h"
#include "components/password_manager/core/browser/password_store_factory_util.h"
#include "components/sync/driver/sync_service.h"
#include "components/sync/driver/sync_user_settings.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace {
// Checks if a user is synced.
bool IsUserSynced(syncer::SyncService* sync_service) {
return sync_service->IsSyncFeatureEnabled();
}
// Checks if a user has a custom passphrase set.
bool IsPassphraseSet(syncer::SyncService* sync_service) {
return sync_service->GetUserSettings()->IsPassphraseRequired();
}
} // namespace
#include "url/scheme_host_port.h"
namespace password_manager {
AffiliationServiceImpl::AffiliationServiceImpl(
syncer::SyncService* sync_service)
: sync_service_(sync_service) {}
syncer::SyncService* sync_service,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: sync_service_(sync_service),
url_loader_factory_(std::move(url_loader_factory)) {}
AffiliationServiceImpl::~AffiliationServiceImpl() = default;
void AffiliationServiceImpl::PrefetchChangePasswordURLs(
const std::vector<url::Origin>& origins) {
if (IsUserSynced(sync_service_) && !IsPassphraseSet(sync_service_)) {
// AffiliationFetcher::Create and AffiliationFetcher::StartRequest
const std::vector<url::SchemeHostPort>& tuple_origins) {
if (ShouldAffiliationBasedMatchingBeActive(sync_service_)) {
RequestFacetsAffiliations(
ConvertMissingSchemeHostPortsToFacets(tuple_origins));
}
}
void AffiliationServiceImpl::Clear() {
fetcher_.reset();
change_password_urls_.clear();
}
GURL AffiliationServiceImpl::GetChangePasswordURL(const url::Origin& origin) {
auto it = change_password_urls_.find(origin);
GURL AffiliationServiceImpl::GetChangePasswordURL(
const url::SchemeHostPort& tuple) const {
auto it = change_password_urls_.find(tuple);
return it != change_password_urls_.end() ? it->second : GURL();
}
void AffiliationServiceImpl::OnFetchSucceeded(
std::unique_ptr<AffiliationFetcherDelegate::Result> result) {}
void AffiliationServiceImpl::OnFetchFailed() {}
void AffiliationServiceImpl::OnMalformedResponse() {}
std::vector<FacetURI>
AffiliationServiceImpl::ConvertMissingSchemeHostPortsToFacets(
const std::vector<url::SchemeHostPort>& tuple_origins) {
std::vector<FacetURI> facets;
for (const auto& tuple : tuple_origins) {
if (tuple.IsValid() && !base::Contains(change_password_urls_, tuple)) {
requested_tuple_origins_.push_back(tuple);
facets.push_back(FacetURI::FromCanonicalSpec(tuple.Serialize()));
}
}
return facets;
}
// TODO(crbug.com/1117045): New request resets the pointer to
// AffiliationFetcher, therefore the previous request gets canceled.
void AffiliationServiceImpl::RequestFacetsAffiliations(
const std::vector<FacetURI>& facets) {
fetcher_.reset(AffiliationFetcher::Create(url_loader_factory_, this));
fetcher_->StartRequest(facets);
}
} // namespace password_manager
......@@ -6,9 +6,14 @@
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SITE_AFFILIATION_AFFILIATION_SERVICE_IMPL_H_
#include <map>
#include <memory>
#include <vector>
#include "components/password_manager/core/browser/site_affiliation/affiliation_service.h"
#include "base/memory/scoped_refptr.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher_delegate.h"
namespace network {
class SharedURLLoaderFactory;
}
......@@ -19,28 +24,53 @@ class SyncService;
namespace password_manager {
class AffiliationServiceImpl : public password_manager::AffiliationService {
class AffiliationFetcherInterface;
class AffiliationServiceImpl : public AffiliationService,
public AffiliationFetcherDelegate {
public:
explicit AffiliationServiceImpl(syncer::SyncService* sync_service);
explicit AffiliationServiceImpl(
syncer::SyncService* sync_service,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
~AffiliationServiceImpl() override;
// Prefetches change password URLs and saves them to changePasswordUrls map.
// The verification if a user is synced and does not use a passphrase must be
// Prefetches change password URLs and saves them to |change_password_urls_|
// map. The verification if affiliation based matching is enabled must be
// performed.
void PrefetchChangePasswordURLs(
const std::vector<url::Origin>& origins) override;
const std::vector<url::SchemeHostPort>& tuple_origins) override;
// Clears the map of URL and cancels prefetch if still running.
// Clears the |change_password_urls_| map and cancels prefetch if still
// running.
void Clear() override;
// Returns a URL with change password form for a site requested.
// In case no valid URL was found, the entry in map for |origin| still exists
// and a method returns an empty URL.
GURL GetChangePasswordURL(const url::Origin& origin) override;
// In case no valid URL was found, a method returns an empty URL.
GURL GetChangePasswordURL(
const url::SchemeHostPort& scheme_host_port) const override;
AffiliationFetcherInterface* GetFetcherForTesting() { return fetcher_.get(); }
private:
// AffiliationFetcherDelegate:
void OnFetchSucceeded(
std::unique_ptr<AffiliationFetcherDelegate::Result> result) override;
void OnFetchFailed() override;
void OnMalformedResponse() override;
// Converts new |tuple_origins| to facets and inserts them to the
// |change_password_urls_|.
std::vector<FacetURI> ConvertMissingSchemeHostPortsToFacets(
const std::vector<url::SchemeHostPort>& tuple_origins);
// Calls Affiliation Fetcher and starts a request for |facets| affiliations.
void RequestFacetsAffiliations(const std::vector<FacetURI>& facets);
syncer::SyncService* sync_service_;
std::map<url::Origin, GURL> change_password_urls_;
const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
std::vector<url::SchemeHostPort> requested_tuple_origins_;
std::map<url::SchemeHostPort, GURL> change_password_urls_;
// TODO(crbug.com/1117045): A vector of pending fetchers to be created.
std::unique_ptr<AffiliationFetcherInterface> fetcher_;
};
} // namespace password_manager
......
......@@ -2,8 +2,182 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <vector>
#include "base/test/task_environment.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_fetcher.h"
#include "components/password_manager/core/browser/android_affiliation/mock_affiliation_fetcher.h"
#include "components/password_manager/core/browser/android_affiliation/test_affiliation_fetcher_factory.h"
#include "components/password_manager/core/browser/site_affiliation/affiliation_service_impl.h"
#include "components/sync/driver/test_sync_service.h"
#include "services/network/test/test_shared_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace password_manager {} // namespace password_manager
using ::testing::_;
using ::testing::Return;
namespace password_manager {
namespace {
constexpr char kTestUrlChar1[] = "https://1.example.com";
constexpr char kTestUrlChar2[] = "https://2.example.com";
constexpr char kTestUrlChar3[] = "https://3.example.com";
constexpr char kTestUrlChar4[] = "https://4.example.com";
constexpr char kTestUrlChar5[] = "https://5.example.com";
url::SchemeHostPort ToSchemeHostPort(const std::string& url) {
return url::SchemeHostPort(GURL(url));
}
std::vector<FacetURI> SchemeHostPortsToFacetsURIs(
const std::vector<url::SchemeHostPort>& scheme_host_ports) {
std::vector<FacetURI> facet_URIs;
for (const auto& scheme_host_port : scheme_host_ports) {
facet_URIs.push_back(
FacetURI::FromCanonicalSpec(scheme_host_port.Serialize()));
}
return facet_URIs;
}
} // namespace
class MockAffiliationFetcherFactory : public TestAffiliationFetcherFactory {
public:
MockAffiliationFetcherFactory() = default;
~MockAffiliationFetcherFactory() override = default;
MOCK_METHOD(
AffiliationFetcherInterface*,
CreateInstance,
(scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
AffiliationFetcherDelegate* delegate),
(override));
};
class AffiliationServiceImplTest : public testing::Test {
public:
AffiliationServiceImplTest()
: sync_service_(std::make_unique<syncer::TestSyncService>()),
service_(sync_service_.get(),
base::MakeRefCounted<network::TestSharedURLLoaderFactory>()) {
AffiliationFetcher::SetFactoryForTesting(mock_fetcher_factory());
}
~AffiliationServiceImplTest() override {
AffiliationFetcher::SetFactoryForTesting(nullptr);
}
syncer::TestSyncService* sync_service() { return sync_service_.get(); }
AffiliationServiceImpl* service() { return &service_; }
MockAffiliationFetcherFactory* mock_fetcher_factory() {
return &mock_fetcher_factory_;
}
// Sets TestSyncService flags.
void SetSyncServiceStates(bool is_setup_completed, bool is_passphrase_set) {
sync_service()->SetFirstSetupComplete(is_setup_completed);
sync_service()->SetIsUsingSecondaryPassphrase(is_passphrase_set);
}
private:
base::test::TaskEnvironment task_env_;
std::unique_ptr<syncer::TestSyncService> sync_service_;
AffiliationServiceImpl service_;
MockAffiliationFetcherFactory mock_fetcher_factory_;
};
TEST_F(AffiliationServiceImplTest, GetChangePasswordURLReturnsEmpty) {
auto scheme_host_port = ToSchemeHostPort(kTestUrlChar1);
EXPECT_EQ(GURL(), service()->GetChangePasswordURL(scheme_host_port));
}
TEST_F(AffiliationServiceImplTest, ClearStopsOngoingAffiliationFetcherRequest) {
auto tuple_origins = {ToSchemeHostPort(kTestUrlChar1),
ToSchemeHostPort(kTestUrlChar2)};
MockAffiliationFetcher* mock_fetcher = new MockAffiliationFetcher();
EXPECT_CALL(*mock_fetcher_factory(), CreateInstance)
.WillOnce(Return(mock_fetcher));
EXPECT_CALL(*mock_fetcher,
StartRequest(SchemeHostPortsToFacetsURIs(tuple_origins)));
service()->PrefetchChangePasswordURLs(tuple_origins);
EXPECT_NE(nullptr, service()->GetFetcherForTesting());
service()->Clear();
EXPECT_EQ(nullptr, service()->GetFetcherForTesting());
}
TEST_F(AffiliationServiceImplTest,
EachPrefetchCallCreatesNewAffiliationFetcherInstance) {
auto scheme_host_port1 = ToSchemeHostPort(kTestUrlChar1);
auto scheme_host_port2 = ToSchemeHostPort(kTestUrlChar2);
auto scheme_host_port3 = ToSchemeHostPort(kTestUrlChar3);
auto scheme_host_port4 = ToSchemeHostPort(kTestUrlChar4);
auto scheme_host_port5 = ToSchemeHostPort(kTestUrlChar5);
auto tuple_origins_1 = {scheme_host_port1, scheme_host_port2,
scheme_host_port3};
auto tuple_origins_2 = {scheme_host_port3, scheme_host_port4,
scheme_host_port5};
MockAffiliationFetcher* mock_fetcher = new MockAffiliationFetcher();
MockAffiliationFetcher* new_mock_fetcher = new MockAffiliationFetcher();
EXPECT_CALL(*mock_fetcher,
StartRequest(SchemeHostPortsToFacetsURIs(tuple_origins_1)));
EXPECT_CALL(*new_mock_fetcher,
StartRequest(SchemeHostPortsToFacetsURIs(tuple_origins_2)));
EXPECT_CALL(*mock_fetcher_factory(), CreateInstance)
.WillOnce(Return(mock_fetcher))
.WillOnce(Return(new_mock_fetcher));
service()->PrefetchChangePasswordURLs(tuple_origins_1);
service()->PrefetchChangePasswordURLs(tuple_origins_2);
}
TEST_F(AffiliationServiceImplTest,
FetchRequiresCompleteSetupAndPassphraseDisabled) {
auto tuple_origins = {ToSchemeHostPort(kTestUrlChar1),
ToSchemeHostPort(kTestUrlChar2)};
MockAffiliationFetcher* mock_fetcher = new MockAffiliationFetcher();
// The only scenario when the StartRequest() should be called.
// Setup is completed and secondary passphrase feature is disabled.
SetSyncServiceStates(/*is_setup_completed=*/true,
/*is_passphrase_set=*/false);
EXPECT_CALL(*mock_fetcher_factory(), CreateInstance)
.WillOnce(Return(mock_fetcher));
EXPECT_CALL(*mock_fetcher,
StartRequest(SchemeHostPortsToFacetsURIs(tuple_origins)));
service()->PrefetchChangePasswordURLs(tuple_origins);
}
TEST_F(AffiliationServiceImplTest, SecondaryPassphraseSetPreventsFetch) {
auto tuple_origins = {ToSchemeHostPort(kTestUrlChar1),
ToSchemeHostPort(kTestUrlChar2)};
SetSyncServiceStates(/*is_setup_completed=*/true, /*is_passphrase_set=*/true);
EXPECT_CALL(*mock_fetcher_factory(), CreateInstance).Times(0);
service()->PrefetchChangePasswordURLs(tuple_origins);
}
TEST_F(AffiliationServiceImplTest, SetupNotCompletedPreventsFetch) {
auto tuple_origins = {ToSchemeHostPort(kTestUrlChar1),
ToSchemeHostPort(kTestUrlChar2)};
SetSyncServiceStates(/*is_setup_completed=*/false,
/*is_passphrase_set=*/false);
EXPECT_CALL(*mock_fetcher_factory(), CreateInstance).Times(0);
service()->PrefetchChangePasswordURLs(tuple_origins);
}
} // namespace password_manager
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