Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(690)

Unified Diff: components/password_manager/core/browser/affiliation_backend_unittest.cc

Issue 2953443002: Revert of Reland: Move the files related to Android <-> Web credentials to a separate folder. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/password_manager/core/browser/affiliation_backend_unittest.cc
diff --git a/components/password_manager/core/browser/affiliation_backend_unittest.cc b/components/password_manager/core/browser/affiliation_backend_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9c10c76274ccd90d85ef9ed9fd3ecb001e2253e4
--- /dev/null
+++ b/components/password_manager/core/browser/affiliation_backend_unittest.cc
@@ -0,0 +1,925 @@
+// Copyright 2015 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/password_manager/core/browser/affiliation_backend.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/time/clock.h"
+#include "base/time/tick_clock.h"
+#include "components/password_manager/core/browser/affiliation_database.h"
+#include "components/password_manager/core/browser/affiliation_fetch_throttler.h"
+#include "components/password_manager/core/browser/affiliation_fetch_throttler_delegate.h"
+#include "components/password_manager/core/browser/facet_manager.h"
+#include "components/password_manager/core/browser/fake_affiliation_api.h"
+#include "components/password_manager/core/browser/mock_affiliation_consumer.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+namespace {
+
+using StrategyOnCacheMiss = AffiliationBackend::StrategyOnCacheMiss;
+
+// Mock fetch throttler that has some extra logic to accurately portray the real
+// AffiliationFetchThrottler in how it ignores SignalNetworkRequestNeeded()
+// requests when a request is already known to be needed or one is already in
+// flight, and in how it goes back to the idle state afterwards.
+class MockAffiliationFetchThrottler : public AffiliationFetchThrottler {
+ public:
+ MockAffiliationFetchThrottler(AffiliationFetchThrottlerDelegate* delegate)
+ : AffiliationFetchThrottler(delegate, nullptr, nullptr),
+ signaled_network_request_needed_(false) {
+ EXPECT_CALL(*this, OnInformOfNetworkRequestComplete(testing::_)).Times(0);
+ }
+
+ ~MockAffiliationFetchThrottler() {
+ EXPECT_FALSE(signaled_network_request_needed_);
+ }
+
+ // Expects that InformOfNetworkRequestComplete() will be called to indicate
+ // either success or failure, depending on |expected_success|.
+ void ExpectInformOfNetworkRequestComplete(bool expected_success) {
+ EXPECT_CALL(*this, OnInformOfNetworkRequestComplete(expected_success));
+ }
+
+ // Informs the |delegate_| that it can send the needed network request.
+ // Returns true if the |delegate_| reported that it actually ended up issuing
+ // a request.
+ bool LetNetworkRequestBeSent() {
+ EXPECT_TRUE(has_signaled_network_request_needed());
+ if (!delegate_->OnCanSendNetworkRequest()) {
+ reset_signaled_network_request_needed();
+ return false;
+ }
+ return true;
+ }
+
+ // Whether or not the throttler is 'signaled', meaning that the real throttler
+ // would eventually call OnCanSendNetworkRequest() on the |delegate_|.
+ bool has_signaled_network_request_needed() const {
+ return signaled_network_request_needed_;
+ }
+
+ // Forces the mock throttler back to 'non-signaled' state. Normally, this does
+ // not need to be manually called, as this is done by the mock automatically.
+ void reset_signaled_network_request_needed() {
+ signaled_network_request_needed_ = false;
+ }
+
+ private:
+ MOCK_METHOD1(OnInformOfNetworkRequestComplete, void(bool));
+
+ // AffiliationFetchThrottler:
+ void SignalNetworkRequestNeeded() override {
+ signaled_network_request_needed_ = true;
+ }
+
+ void InformOfNetworkRequestComplete(bool success) override {
+ OnInformOfNetworkRequestComplete(success);
+ reset_signaled_network_request_needed();
+ }
+
+ bool signaled_network_request_needed_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockAffiliationFetchThrottler);
+};
+
+const char kTestFacetURIAlpha1[] = "https://one.alpha.example.com";
+const char kTestFacetURIAlpha2[] = "https://two.alpha.example.com";
+const char kTestFacetURIAlpha3[] = "https://three.alpha.example.com";
+const char kTestFacetURIBeta1[] = "https://one.beta.example.com";
+const char kTestFacetURIBeta2[] = "https://two.beta.example.com";
+const char kTestFacetURIGamma1[] = "https://gamma.example.com";
+
+AffiliatedFacets GetTestEquivalenceClassAlpha() {
+ AffiliatedFacets affiliated_facets;
+ affiliated_facets.push_back(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+ affiliated_facets.push_back(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2));
+ affiliated_facets.push_back(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha3));
+ return affiliated_facets;
+}
+
+AffiliatedFacets GetTestEquivalenceClassBeta() {
+ AffiliatedFacets affiliated_facets;
+ affiliated_facets.push_back(FacetURI::FromCanonicalSpec(kTestFacetURIBeta1));
+ affiliated_facets.push_back(FacetURI::FromCanonicalSpec(kTestFacetURIBeta2));
+ return affiliated_facets;
+}
+
+AffiliatedFacets GetTestEquivalenceClassGamma() {
+ AffiliatedFacets affiliated_facets;
+ affiliated_facets.push_back(FacetURI::FromCanonicalSpec(kTestFacetURIGamma1));
+ return affiliated_facets;
+}
+
+base::TimeDelta GetCacheHardExpiryPeriod() {
+ return base::TimeDelta::FromHours(FacetManager::kCacheHardExpiryInHours);
+}
+
+base::TimeDelta GetCacheSoftExpiryPeriod() {
+ return base::TimeDelta::FromHours(FacetManager::kCacheSoftExpiryInHours);
+}
+
+base::TimeDelta GetShortTestPeriod() {
+ return base::TimeDelta::FromHours(1);
+}
+
+// Returns a smallest time difference that this test cares about.
+base::TimeDelta Epsilon() {
+ return base::TimeDelta::FromMicroseconds(1);
+}
+
+} // namespace
+
+class AffiliationBackendTest : public testing::Test {
+ public:
+ AffiliationBackendTest()
+ : backend_task_runner_(new base::TestMockTimeTaskRunner),
+ consumer_task_runner_(new base::TestSimpleTaskRunner),
+ mock_fetch_throttler_(nullptr) {}
+ ~AffiliationBackendTest() override {}
+
+ protected:
+ void GetAffiliations(MockAffiliationConsumer* consumer,
+ const FacetURI& facet_uri,
+ StrategyOnCacheMiss cache_miss_strategy) {
+ backend_->GetAffiliations(facet_uri, cache_miss_strategy,
+ consumer->GetResultCallback(),
+ consumer_task_runner());
+ }
+
+ void Prefetch(const FacetURI& facet_uri, base::Time keep_fresh_until) {
+ backend_->Prefetch(facet_uri, keep_fresh_until);
+ }
+
+ void CancelPrefetch(const FacetURI& facet_uri, base::Time keep_fresh_until) {
+ backend_->CancelPrefetch(facet_uri, keep_fresh_until);
+ }
+
+ void ExpectNeedForFetchAndLetItBeSent() {
+ ASSERT_FALSE(fake_affiliation_api()->HasPendingRequest());
+ ASSERT_TRUE(mock_fetch_throttler()->has_signaled_network_request_needed());
+ ASSERT_TRUE(mock_fetch_throttler()->LetNetworkRequestBeSent());
+ }
+
+ void ExpectAndCompleteFetch(
+ const std::vector<FacetURI>& expected_requested_facet_uris) {
+ ASSERT_TRUE(fake_affiliation_api()->HasPendingRequest());
+ EXPECT_THAT(
+ fake_affiliation_api()->GetNextRequestedFacets(),
+ testing::UnorderedElementsAreArray(expected_requested_facet_uris));
+ mock_fetch_throttler()->ExpectInformOfNetworkRequestComplete(true);
+ fake_affiliation_api()->ServeNextRequest();
+ testing::Mock::VerifyAndClearExpectations(mock_fetch_throttler());
+ }
+
+ void ExpectAndCompleteFetch(const FacetURI& expected_requested_facet_uri) {
+ std::vector<FacetURI> expected_facet_uris;
+ expected_facet_uris.push_back(expected_requested_facet_uri);
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(expected_facet_uris));
+ }
+
+ void ExpectAndFailFetch(const FacetURI& expected_requested_facet_uri) {
+ ASSERT_TRUE(fake_affiliation_api()->HasPendingRequest());
+ EXPECT_THAT(fake_affiliation_api()->GetNextRequestedFacets(),
+ testing::UnorderedElementsAre(expected_requested_facet_uri));
+ mock_fetch_throttler()->ExpectInformOfNetworkRequestComplete(false);
+ fake_affiliation_api()->FailNextRequest();
+ testing::Mock::VerifyAndClearExpectations(mock_fetch_throttler());
+ }
+
+ void ExpectNoFetchNeeded() {
+ ASSERT_FALSE(fake_affiliation_api()->HasPendingRequest());
+ ASSERT_FALSE(mock_fetch_throttler()->has_signaled_network_request_needed());
+ }
+
+ void ExpectFailureWithoutFetch(MockAffiliationConsumer* consumer) {
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ consumer->ExpectFailure();
+ consumer_task_runner_->RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(consumer);
+ }
+
+ void GetAffiliationsAndExpectFetchAndThenResult(
+ const FacetURI& facet_uri,
+ const AffiliatedFacets& expected_result) {
+ GetAffiliations(mock_consumer(), facet_uri,
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(facet_uri));
+ mock_consumer()->ExpectSuccessWithResult(expected_result);
+ consumer_task_runner_->RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_consumer());
+ }
+
+ void GetAffiliationsAndExpectResultWithoutFetch(
+ const FacetURI& facet_uri,
+ StrategyOnCacheMiss cache_miss_strategy,
+ const AffiliatedFacets& expected_result) {
+ GetAffiliations(mock_consumer(), facet_uri, cache_miss_strategy);
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ mock_consumer()->ExpectSuccessWithResult(expected_result);
+ consumer_task_runner_->RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_consumer());
+ }
+
+ // TODO(engedy): Within this test fixture, the word "failure" refers to GTest
+ // failures, simulated network failures (above), and also AffiliationService
+ // failure callbacks. Make this less ambiguous.
+ void GetAffiliationsAndExpectFailureWithoutFetch(const FacetURI& facet_uri) {
+ GetAffiliations(mock_consumer(), facet_uri, StrategyOnCacheMiss::FAIL);
+ ASSERT_NO_FATAL_FAILURE(ExpectFailureWithoutFetch(mock_consumer()));
+ }
+
+ void PrefetchAndExpectFetch(const FacetURI& facet_uri,
+ base::Time keep_fresh_until) {
+ Prefetch(facet_uri, keep_fresh_until);
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(facet_uri));
+ }
+
+ // Verifies that both on-demand and cached-only GetAffiliations() requests for
+ // each facet in |affiliated_facets| are served from cache with no fetches.
+ void ExpectThatEquivalenceClassIsServedFromCache(
+ const AffiliatedFacets& affiliated_facets) {
+ for (const FacetURI& facet_uri : affiliated_facets) {
+ SCOPED_TRACE(facet_uri);
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+ facet_uri, StrategyOnCacheMiss::FAIL, affiliated_facets));
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+ facet_uri, StrategyOnCacheMiss::FAIL, affiliated_facets));
+ }
+ }
+
+ void DestroyBackend() { backend_.reset(); }
+
+ void AdvanceTime(base::TimeDelta delta) {
+ backend_task_runner_->FastForwardBy(delta);
+ }
+
+ // Directly opens the database and returns the number of equivalence classes
+ // stored therein.
+ size_t GetNumOfEquivalenceClassInDatabase() {
+ AffiliationDatabase database;
+ EXPECT_TRUE(database.Init(db_path()));
+ std::vector<AffiliatedFacetsWithUpdateTime> all_affiliations;
+ database.GetAllAffiliations(&all_affiliations);
+ return all_affiliations.size();
+ }
+
+ size_t backend_facet_manager_count() {
+ return backend()->facet_manager_count_for_testing();
+ }
+
+ bool IsCachedDataFreshForFacet(const FacetURI& facet_uri) {
+ std::unique_ptr<base::Clock> clock(backend_task_runner_->GetMockClock());
+ return FacetManager(facet_uri, backend(), clock.get()).IsCachedDataFresh();
+ }
+
+ bool IsCachedDataNearStaleForFacet(const FacetURI& facet_uri) {
+ std::unique_ptr<base::Clock> clock(backend_task_runner_->GetMockClock());
+ return FacetManager(facet_uri, backend(), clock.get())
+ .IsCachedDataNearStale();
+ }
+
+ AffiliationBackend* backend() { return backend_.get(); }
+
+ const base::FilePath& db_path() const { return db_path_; }
+
+ base::TestMockTimeTaskRunner* backend_task_runner() {
+ return backend_task_runner_.get();
+ }
+
+ base::TestSimpleTaskRunner* consumer_task_runner() {
+ return consumer_task_runner_.get();
+ }
+
+ ScopedFakeAffiliationAPI* fake_affiliation_api() {
+ return &fake_affiliation_api_;
+ }
+
+ MockAffiliationConsumer* mock_consumer() { return &mock_consumer_; }
+
+ MockAffiliationFetchThrottler* mock_fetch_throttler() {
+ return mock_fetch_throttler_;
+ }
+
+ private:
+ // testing::Test:
+ void SetUp() override {
+ ASSERT_TRUE(CreateTemporaryFile(&db_path_));
+ backend_.reset(new AffiliationBackend(
+ NULL, backend_task_runner_, backend_task_runner_->GetMockClock(),
+ backend_task_runner_->GetMockTickClock()));
+ backend_->Initialize(db_path());
+ mock_fetch_throttler_ = new MockAffiliationFetchThrottler(backend_.get());
+ backend_->SetThrottlerForTesting(
+ base::WrapUnique<AffiliationFetchThrottler>(mock_fetch_throttler_));
+
+ fake_affiliation_api_.AddTestEquivalenceClass(
+ GetTestEquivalenceClassAlpha());
+ fake_affiliation_api_.AddTestEquivalenceClass(
+ GetTestEquivalenceClassBeta());
+ fake_affiliation_api_.AddTestEquivalenceClass(
+ GetTestEquivalenceClassGamma());
+ }
+
+ scoped_refptr<base::TestMockTimeTaskRunner> backend_task_runner_;
+ scoped_refptr<base::TestSimpleTaskRunner> consumer_task_runner_;
+
+ base::FilePath db_path_;
+ ScopedFakeAffiliationAPI fake_affiliation_api_;
+ MockAffiliationConsumer mock_consumer_;
+ std::unique_ptr<AffiliationBackend> backend_;
+ MockAffiliationFetchThrottler* mock_fetch_throttler_; // Owned by |backend_|.
+
+ DISALLOW_COPY_AND_ASSIGN(AffiliationBackendTest);
+};
+
+TEST_F(AffiliationBackendTest, OnDemandRequestSucceedsWithFetch) {
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ GetTestEquivalenceClassAlpha()));
+ EXPECT_EQ(0u, backend_facet_manager_count());
+
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIBeta1),
+ GetTestEquivalenceClassBeta()));
+ EXPECT_EQ(0u, backend_facet_manager_count());
+}
+
+// This test also verifies that the FacetManager is immediately discarded.
+TEST_F(AffiliationBackendTest, CachedOnlyRequestFailsDueToCacheMiss) {
+ GetAffiliationsAndExpectFailureWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2));
+ EXPECT_EQ(0u, backend_facet_manager_count());
+}
+
+TEST_F(AffiliationBackendTest, PrefetchTriggersInitialFetch) {
+ ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max()));
+}
+
+// This test also verifies that the FacetManager is immediately discarded.
+TEST_F(AffiliationBackendTest, ExpiredPrefetchTriggersNoInitialFetch) {
+ // Prefetch intervals are open from the right, thus intervals ending Now() are
+ // already expired.
+ Prefetch(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ backend_task_runner()->Now());
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ EXPECT_EQ(0u, backend_facet_manager_count());
+ EXPECT_FALSE(backend_task_runner()->HasPendingTask());
+}
+
+// One additional GetAffiliations() and one Prefetch() request come in, both for
+// unrelated facets, shortly after an initial GetAffiliations() request.
+//
+// Suppose that the network request triggered by the first GetAffiliations()
+// request has already been initiated when the other requests arrive. As there
+// should be no simultaneous requests, the additional facets should be queried
+// together in a second fetch after the first fetch completes.
+TEST_F(AffiliationBackendTest, ConcurrentUnrelatedRequests) {
+ FacetURI facet_alpha(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+ FacetURI facet_beta(FacetURI::FromCanonicalSpec(kTestFacetURIBeta1));
+ FacetURI facet_gamma(FacetURI::FromCanonicalSpec(kTestFacetURIGamma1));
+
+ // Pretend the fetch is already away when the two other requests come in.
+ MockAffiliationConsumer second_consumer;
+ GetAffiliations(mock_consumer(), facet_alpha,
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ GetAffiliations(&second_consumer, facet_beta,
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ Prefetch(facet_gamma, base::Time::Max());
+
+ std::vector<FacetURI> second_fetch_uris;
+ second_fetch_uris.push_back(facet_beta);
+ second_fetch_uris.push_back(facet_gamma);
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(facet_alpha));
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(second_fetch_uris));
+
+ mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
+ second_consumer.ExpectSuccessWithResult(GetTestEquivalenceClassBeta());
+ consumer_task_runner()->RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_consumer());
+
+ // Now that the two GetAffiliation() requests have been completed, the first
+ // two FacetManagers should be discarded. The third FacetManager corresponding
+ // to the prefetched facet should be kept.
+ EXPECT_GE(1u, backend_facet_manager_count());
+}
+
+// Now suppose that the first fetch is somewhat delayed (e.g., because network
+// requests are throttled), so the other requests arrive before it is actually
+// issued. In this case, all facet URIs should be queried together in one fetch.
+TEST_F(AffiliationBackendTest, ConcurrentUnrelatedRequests2) {
+ FacetURI facet_alpha(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+ FacetURI facet_beta(FacetURI::FromCanonicalSpec(kTestFacetURIBeta1));
+ FacetURI facet_gamma(FacetURI::FromCanonicalSpec(kTestFacetURIGamma1));
+
+ MockAffiliationConsumer second_consumer;
+ GetAffiliations(mock_consumer(), facet_alpha,
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ GetAffiliations(&second_consumer, facet_beta,
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ Prefetch(facet_gamma, base::Time::Max());
+
+ std::vector<FacetURI> fetched_uris;
+ fetched_uris.push_back(facet_alpha);
+ fetched_uris.push_back(facet_beta);
+ fetched_uris.push_back(facet_gamma);
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(fetched_uris));
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+
+ mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
+ second_consumer.ExpectSuccessWithResult(GetTestEquivalenceClassBeta());
+ consumer_task_runner()->RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_consumer());
+
+ // Now that the two GetAffiliation() requests have been completed, the first
+ // two FacetManagers should be discarded. The third FacetManager corresponding
+ // to the prefetched facet should be kept.
+ EXPECT_GE(1u, backend_facet_manager_count());
+}
+
+TEST_F(AffiliationBackendTest, RetryIsMadeOnFailedFetch) {
+ FacetURI facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+
+ GetAffiliations(mock_consumer(), facet_uri,
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ ASSERT_NO_FATAL_FAILURE(ExpectAndFailFetch(facet_uri));
+ EXPECT_EQ(1u, backend_facet_manager_count());
+
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(facet_uri));
+
+ mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
+ consumer_task_runner()->RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_consumer());
+
+ EXPECT_EQ(0u, backend_facet_manager_count());
+}
+
+// The Prefetch() request expires before fetching corresponding affiliation
+// information would be allowed. The fetch should be abandoned.
+TEST_F(AffiliationBackendTest, FetchIsNoLongerNeededOnceAllowed) {
+ Prefetch(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ backend_task_runner()->Now() + GetShortTestPeriod());
+ ASSERT_TRUE(mock_fetch_throttler()->has_signaled_network_request_needed());
+ ASSERT_FALSE(fake_affiliation_api()->HasPendingRequest());
+
+ AdvanceTime(GetShortTestPeriod() + Epsilon());
+
+ bool did_send_request = mock_fetch_throttler()->LetNetworkRequestBeSent();
+ EXPECT_FALSE(did_send_request);
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ EXPECT_EQ(0u, backend_facet_manager_count());
+}
+
+TEST_F(AffiliationBackendTest, CacheServesSubsequentRequestForSameFacet) {
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ GetTestEquivalenceClassAlpha()));
+
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassAlpha()));
+
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha()));
+
+ EXPECT_EQ(0u, backend_facet_manager_count());
+}
+
+TEST_F(AffiliationBackendTest, CacheServesSubsequentRequestForAffiliatedFacet) {
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ GetTestEquivalenceClassAlpha()));
+
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+
+ EXPECT_EQ(0u, backend_facet_manager_count());
+}
+
+TEST_F(AffiliationBackendTest, CacheServesRequestsForPrefetchedFacets) {
+ ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max()));
+
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK, GetTestEquivalenceClassAlpha()));
+
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectResultWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassAlpha()));
+}
+
+TEST_F(AffiliationBackendTest,
+ CacheServesRequestsForFacetsAffiliatedWithPrefetchedFacets) {
+ ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max()));
+
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+}
+
+// A second GetAffiliations() request for the same facet and a third request
+// for an affiliated facet comes in while the network fetch triggered by the
+// first request is in flight.
+//
+// There should be no simultaneous requests, and once the fetch completes, all
+// three requests should be served without further fetches (they have the data).
+TEST_F(AffiliationBackendTest,
+ CacheServesConcurrentRequestsForAffiliatedFacets) {
+ FacetURI facet_uri1(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+ FacetURI facet_uri2(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2));
+
+ MockAffiliationConsumer second_consumer;
+ MockAffiliationConsumer third_consumer;
+ GetAffiliations(mock_consumer(), facet_uri1,
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ GetAffiliations(&second_consumer, facet_uri1,
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ GetAffiliations(&third_consumer, facet_uri2,
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(facet_uri1));
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+
+ mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
+ second_consumer.ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
+ third_consumer.ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
+ consumer_task_runner()->RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_consumer());
+
+ EXPECT_EQ(0u, backend_facet_manager_count());
+}
+
+// A second Prefetch() request for the same facet and a third request for an
+// affiliated facet comes in while the initial fetch triggered by the first
+// request is in flight.
+//
+// There should be no simultaneous requests, and once the fetch completes, there
+// should be no further initial fetches as the data needed is already there.
+TEST_F(AffiliationBackendTest,
+ CacheServesConcurrentPrefetchesForAffiliatedFacets) {
+ FacetURI facet_uri1(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+ FacetURI facet_uri2(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2));
+
+ Prefetch(facet_uri1, base::Time::Max());
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ Prefetch(facet_uri1, base::Time::Max());
+ Prefetch(facet_uri2, base::Time::Max());
+
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(facet_uri1));
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+}
+
+TEST_F(AffiliationBackendTest, SimpleCacheExpiryWithoutPrefetches) {
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ GetTestEquivalenceClassAlpha()));
+
+ AdvanceTime(GetCacheHardExpiryPeriod() - Epsilon());
+
+ EXPECT_TRUE(IsCachedDataFreshForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+
+ AdvanceTime(Epsilon());
+
+ // After the data becomes stale, the cached-only request should fail, but the
+ // subsequent on-demand request should fetch the data again and succeed.
+ EXPECT_FALSE(IsCachedDataFreshForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ GetAffiliationsAndExpectFailureWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2),
+ GetTestEquivalenceClassAlpha()));
+
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+
+ EXPECT_EQ(0u, backend_facet_manager_count());
+}
+
+// A Prefetch() request for a finite period. It should trigger an initial fetch
+// and exactly one refetch, as the Prefetch() request expires exactly when the
+// cached data obtained with the refetch expires.
+TEST_F(AffiliationBackendTest,
+ PrefetchTriggersOneInitialFetchAndOneRefetchBeforeExpiring) {
+ ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ backend_task_runner()->Now() + GetCacheHardExpiryPeriod() +
+ GetCacheSoftExpiryPeriod()));
+
+ AdvanceTime(GetCacheSoftExpiryPeriod() - Epsilon());
+
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ EXPECT_FALSE(IsCachedDataNearStaleForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+
+ AdvanceTime(Epsilon());
+
+ EXPECT_TRUE(IsCachedDataNearStaleForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ ASSERT_NO_FATAL_FAILURE(
+ ExpectAndCompleteFetch(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+
+ AdvanceTime(GetCacheHardExpiryPeriod() - Epsilon());
+
+ EXPECT_TRUE(IsCachedDataFreshForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ EXPECT_TRUE(IsCachedDataNearStaleForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+
+ AdvanceTime(Epsilon());
+
+ // The data should be allowed to expire and the FacetManager discarded.
+ EXPECT_FALSE(IsCachedDataFreshForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ EXPECT_EQ(0u, backend_facet_manager_count());
+ EXPECT_FALSE(backend_task_runner()->HasPendingTask());
+
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFailureWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFailureWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2)));
+
+ // However, a subsequent on-demand request should be able to trigger a fetch.
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ GetTestEquivalenceClassAlpha()));
+}
+
+// Affiliation data for prefetched facets should be automatically refetched once
+// every 23 hours, and GetAffiliations() requests regarding affiliated facets
+// should be continuously served from cache.
+TEST_F(AffiliationBackendTest, PrefetchTriggersPeriodicRefetch) {
+ ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max()));
+
+ for (int cycle = 0; cycle < 3; ++cycle) {
+ SCOPED_TRACE(cycle);
+
+ AdvanceTime(GetCacheSoftExpiryPeriod() - Epsilon());
+
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ EXPECT_TRUE(IsCachedDataFreshForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ EXPECT_FALSE(IsCachedDataNearStaleForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+
+ AdvanceTime(Epsilon());
+
+ EXPECT_TRUE(IsCachedDataNearStaleForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ ASSERT_NO_FATAL_FAILURE(ExpectAndCompleteFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+ }
+}
+
+TEST_F(AffiliationBackendTest,
+ PrefetchTriggersNoInitialFetchIfDataIsAlreadyFresh) {
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ GetTestEquivalenceClassAlpha()));
+
+ EXPECT_FALSE(IsCachedDataNearStaleForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+
+ Prefetch(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max());
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+}
+
+TEST_F(AffiliationBackendTest, CancelPrefetch) {
+ ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max()));
+
+ AdvanceTime(GetCacheSoftExpiryPeriod() - Epsilon());
+
+ // Cancel the prefetch the last microsecond before a refetch would take place.
+ backend()->CancelPrefetch(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ base::Time::Max());
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ EXPECT_EQ(0u, backend_facet_manager_count());
+ EXPECT_TRUE(backend_task_runner()->HasPendingTask());
+
+ AdvanceTime(GetCacheHardExpiryPeriod() - GetCacheSoftExpiryPeriod() +
+ Epsilon());
+
+ // The data should be allowed to expire.
+ EXPECT_FALSE(backend_task_runner()->HasPendingTask());
+ EXPECT_TRUE(IsCachedDataNearStaleForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFailureWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFailureWithoutFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2)));
+}
+
+TEST_F(AffiliationBackendTest, CancelDuplicatePrefetch) {
+ ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max()));
+ Prefetch(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1), base::Time::Max());
+
+ AdvanceTime(GetCacheSoftExpiryPeriod() - Epsilon());
+
+ // Cancel the prefetch the last microsecond before a refetch would take place.
+ backend()->CancelPrefetch(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ base::Time::Max());
+
+ AdvanceTime(Epsilon());
+
+ // However, there is a second Prefetch() request which should keep the data
+ // fresh.
+ EXPECT_EQ(1u, backend_facet_manager_count());
+ EXPECT_TRUE(IsCachedDataNearStaleForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(ExpectNeedForFetchAndLetItBeSent());
+ ASSERT_NO_FATAL_FAILURE(
+ ExpectAndCompleteFetch(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+
+ AdvanceTime(GetCacheHardExpiryPeriod() - GetCacheSoftExpiryPeriod());
+
+ EXPECT_TRUE(IsCachedDataFreshForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1)));
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+}
+
+// Canceling a non-existing prefetch request for a non-prefetched facet.
+TEST_F(AffiliationBackendTest, CancelingNonExistingPrefetchIsSilentlyIgnored) {
+ CancelPrefetch(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ backend_task_runner()->Now() + base::TimeDelta::FromHours(24));
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ EXPECT_EQ(0u, backend_facet_manager_count());
+ EXPECT_FALSE(backend_task_runner()->HasPendingTask());
+}
+
+// Verify removal of equivalence classes that contain only facets for which
+// there are no FacetManagers.
+TEST_F(AffiliationBackendTest, TrimCacheDiscardsDataWithoutFacetManagers) {
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ GetTestEquivalenceClassAlpha()));
+ ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIBeta1),
+ backend_task_runner()->Now() + GetShortTestPeriod()));
+ Prefetch(FacetURI::FromCanonicalSpec(kTestFacetURIBeta2), base::Time::Max());
+ ASSERT_NO_FATAL_FAILURE(ExpectNoFetchNeeded());
+ EXPECT_EQ(2u, GetNumOfEquivalenceClassInDatabase());
+
+ AdvanceTime(GetShortTestPeriod());
+
+ // Worst-case scenario: the first prefetch has just expired, the other has
+ // just been canceled when TrimCache() is called; plus immediately afterwards
+ // the backend is destroyed.
+ ASSERT_NO_FATAL_FAILURE(CancelPrefetch(
+ FacetURI::FromCanonicalSpec(kTestFacetURIBeta2), base::Time::Max()));
+ backend()->TrimCache();
+ DestroyBackend();
+ EXPECT_EQ(0u, GetNumOfEquivalenceClassInDatabase());
+}
+
+// Verify removal of equivalence classes that contain only facets for which
+// there are only FacetManagers that do not need the data.
+TEST_F(AffiliationBackendTest,
+ TrimCacheDiscardsDataNoLongerNeededByFacetManagers) {
+ FacetURI facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+
+ // Set up some stale data in the database.
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ facet_uri, GetTestEquivalenceClassAlpha()));
+ AdvanceTime(GetCacheHardExpiryPeriod());
+ EXPECT_FALSE(IsCachedDataFreshForFacet(facet_uri));
+
+ // Now start prefetching the same facet, but keep the network fetch hanging.
+ Prefetch(facet_uri, base::Time::Max());
+ ASSERT_TRUE(mock_fetch_throttler()->has_signaled_network_request_needed());
+ EXPECT_EQ(1u, GetNumOfEquivalenceClassInDatabase());
+
+ // The already stale data should be removed regardless of the active prefetch.
+ backend()->TrimCache();
+ EXPECT_EQ(0u, GetNumOfEquivalenceClassInDatabase());
+
+ mock_fetch_throttler()->reset_signaled_network_request_needed();
+}
+
+// Verify preservation of equivalence classes that contain >= 1 facet for which
+// there is a FacetManager claiming that it needs to keep the data.
+TEST_F(AffiliationBackendTest, TrimCacheRetainsDataThatNeededByFacetManagers) {
+ FacetURI facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1));
+
+ ASSERT_NO_FATAL_FAILURE(PrefetchAndExpectFetch(
+ facet_uri, backend_task_runner()->Now() + GetCacheHardExpiryPeriod()));
+ backend()->TrimCache();
+
+ // Also verify that the last update time of the affiliation data is preserved,
+ // i.e., that it expires when it would normally have expired.
+ AdvanceTime(GetCacheHardExpiryPeriod() - Epsilon());
+ EXPECT_TRUE(IsCachedDataFreshForFacet(facet_uri));
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassAlpha()));
+ AdvanceTime(Epsilon());
+ EXPECT_FALSE(IsCachedDataFreshForFacet(facet_uri));
+ ASSERT_NO_FATAL_FAILURE(
+ GetAffiliationsAndExpectFailureWithoutFetch(facet_uri));
+}
+
+// Verify that TrimCacheForFacet() only removes the equivalence class for the
+// given facet, and preserves others (even if they could be discarded).
+TEST_F(AffiliationBackendTest,
+ TrimCacheForFacetOnlyRemovesDataForTheGivenFacet) {
+ FacetURI preserved_facet_uri(FacetURI::FromCanonicalSpec(kTestFacetURIBeta1));
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1),
+ GetTestEquivalenceClassAlpha()));
+ ASSERT_NO_FATAL_FAILURE(GetAffiliationsAndExpectFetchAndThenResult(
+ preserved_facet_uri, GetTestEquivalenceClassBeta()));
+ EXPECT_EQ(2u, GetNumOfEquivalenceClassInDatabase());
+
+ backend()->TrimCacheForFacet(
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2));
+ EXPECT_EQ(1u, GetNumOfEquivalenceClassInDatabase());
+
+ // Also verify that the last update time of the affiliation data is preserved,
+ // i.e., that it expires when it would normally have expired.
+ AdvanceTime(GetCacheHardExpiryPeriod() - Epsilon());
+ EXPECT_TRUE(IsCachedDataFreshForFacet(preserved_facet_uri));
+ ASSERT_NO_FATAL_FAILURE(ExpectThatEquivalenceClassIsServedFromCache(
+ GetTestEquivalenceClassBeta()));
+ AdvanceTime(Epsilon());
+ EXPECT_FALSE(IsCachedDataFreshForFacet(preserved_facet_uri));
+ ASSERT_NO_FATAL_FAILURE(
+ GetAffiliationsAndExpectFailureWithoutFetch(preserved_facet_uri));
+}
+
+TEST_F(AffiliationBackendTest, NothingExplodesWhenShutDownDuringFetch) {
+ GetAffiliations(mock_consumer(),
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2),
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ ASSERT_TRUE(mock_fetch_throttler()->has_signaled_network_request_needed());
+ mock_fetch_throttler()->reset_signaled_network_request_needed();
+ DestroyBackend();
+}
+
+TEST_F(AffiliationBackendTest,
+ FailureCallbacksAreCalledIfBackendIsDestroyedWithPendingRequest) {
+ GetAffiliations(mock_consumer(),
+ FacetURI::FromCanonicalSpec(kTestFacetURIAlpha2),
+ StrategyOnCacheMiss::FETCH_OVER_NETWORK);
+ // Currently, a GetAffiliations() request can only be blocked due to fetch in
+ // flight -- so emulate this condition when destroying the backend.
+ ASSERT_TRUE(mock_fetch_throttler()->has_signaled_network_request_needed());
+ mock_fetch_throttler()->reset_signaled_network_request_needed();
+ DestroyBackend();
+ mock_consumer()->ExpectFailure();
+ consumer_task_runner()->RunUntilIdle();
+ testing::Mock::VerifyAndClearExpectations(mock_consumer());
+}
+
+TEST_F(AffiliationBackendTest, DeleteCache) {
+ DestroyBackend();
+ ASSERT_TRUE(base::PathExists(db_path()));
+ AffiliationBackend::DeleteCache(db_path());
+ ASSERT_FALSE(base::PathExists(db_path()));
+}
+
+} // namespace password_manager

Powered by Google App Engine
This is Rietveld 408576698