// Copyright 2015 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/40285824): Remove this and convert code to safer constructs. #pragma allow_unsafe_buffers #endif #include "components/affiliations/core/browser/facet_manager.h" #include <stddef.h> #include <algorithm> #include <memory> #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/location.h" #include "base/memory/raw_ptr.h" #include "base/memory/ref_counted.h" #include "base/rand_util.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/time.h" #include "components/affiliations/core/browser/facet_manager_host.h" #include "components/affiliations/core/browser/mock_affiliation_consumer.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" namespace affiliations { // Helpers -------------------------------------------------------------------- namespace { StrategyOnCacheMiss; enum class NotificationAccuracy { … }; // Helper class to post callbacks to FacetManager::NotifyAtRequestedTime(), // delayed by the requested time plus/minus a configurable error term to // simulate a real-life task runner. class TestFacetManagerNotifier { … }; // Stub/mock implementation for FacetManagerHost. class MockFacetManagerHost : public FacetManagerHost { … }; const bool kFalseTrue[] = …; const char kTestFacetURI1[] = …; const char kTestFacetURI2[] = …; const char kTestFacetURI3[] = …; AffiliatedFacets GetTestEquivalenceClass() { … } AffiliatedFacetsWithUpdateTime GetTestEquivalenceClassWithUpdateTime( base::Time last_update_time) { … } base::TimeDelta GetCacheHardExpiryPeriod() { … } base::TimeDelta GetCacheSoftExpiryPeriod() { … } base::TimeDelta GetShortTestPeriod() { … } // Returns a smallest time difference that this test cares about. base::TimeDelta Epsilon() { … } // Returns |time| + |delay| or the maximum time if |delay| is the maximum delta. base::Time SafeAdd(base::Time time, base::TimeDelta delay) { … } // Subdivides a time interval of a given |duration| into zero or more intervals // that lend themselves to be used for sampling a quantity every that often. // More specifically, returns the minimum number of intervals so that each // sub-interval is at most GetTestShortInterval() long, and that the last of the // sub-intervals (if any) is exactly Epsilon() long. No intervals are returned // if |duration| is of length zero. std::vector<base::TimeDelta> SamplingPoints(base::TimeDelta duration) { … } } // namespace // Test framework ------------------------------------------------------------- class FacetManagerTest : public testing::Test { … }; // Tests ---------------------------------------------------------------------- TEST_F(FacetManagerTest, NewInstanceCanBeDiscarded) { … } // Both cached-only and on-demand GetAffiliationsAndBranding() requests should // be served from cache if it contains fresh data. Nothing should happen on // cache expiry. TEST_F(FacetManagerTest, GetAffiliationsAndBrandingServedFromCache) { … } // On-demand GetAffiliationsAndBranding() requests should trigger a fetch if the // cache has already stale data, or no corresponding data whatsoever. Nothing // should happen once the newly fetched data expires. TEST_F(FacetManagerTest, OnDemandGetAffiliationsAndBrandingRequestTriggersFetch) { … } TEST_F(FacetManagerTest, CachedOnlyGetAffiliationsAndBrandingFailsDueToStaleCache) { … } TEST_F(FacetManagerTest, GetAffiliationsAndBrandingFailureCallbackInvokedOnDestruction) { … } // The following tests verify both typical and edge case behavior of Prefetch() // requests: they should prevent the FacetManager from being discarded, and keep // the data fresh by initial fetches and refetches (scheduled as described in // facet_manager.cc). // // Legend: // [---): Interval representing a finite Prefetch request (open from right). // The data should be kept fresh, the FacetManager not discarded. // [--->: Interval representing a indefinite Prefetch request. // The data should be kept fresh, the FacetManager not discarded. // F: Fetch (initial or refetch) should take place here. // Fn: The time of the n-th fetch (starting from 1). // D: Time interval equal to GetShortTestPeriod(). // N: Fetch is signaled to be needed here. // X: A corresponding CancelPrefetch call is placed here. // S: |kCacheSoftExpiryInHours| hours // H: |kCacheHardExpiryInHours| hours // // Note: It is guaranteed that S < H and that H < 2*S. // // Prefetches with the cache is initially stale/empty: // // t=0 S H F2+S F2+H // / / / / / // ---o--------------------------o-------o---------------o-------o---------> t // : : : : : // [) : : : : // [F--) : : : : // [F------------------------): : : : // [F--------------------------------): : : // [F-------------------------F----------) : : // [F-------------------------F----------------------): : // [F-------------------------F------------------------------): // [F-------------------------F-----------------------F------------------> // TEST_F(FacetManagerTest, PrefetchWithEmptyOrStaleCache) { … } // Prefetches with cached affiliation data that is fresh to some extent: // // Suppose an unrelated fetch at t=0 has resulted in affiliation information // being stored into the cache (freshness interval marked with '='). See legend // above. // // t=0 S H F2+S F2+H // / / / / / // ---o--------------------------o-------o---------------o-------o-----> t // [F================================): : : // : : : : : // [) : : : : // [--) : : : : // [-------------------------): : : : // [---------------------------------): : : // [--------------------------F-----------) : : // [--------------------------F----------------------): : // [--------------------------F------------------------------): // [--------------------------F-----------------------F-------------> // : : : : // [) : : : : // [--) : : : : // [---------------------): : : : // [-----------------------------): : : // [----------------------F-----------) : : // [----------------------F----------------------): : // [----------------------F------------------------------): // [----------------------F-----------------------F-------------> // : : : : // [) : : : // [----) : : : // [------): : : // [F----------) : : // [F---------------------): : // [F-----------------------------): // [F----------------------F-------------> // // t=0 S S+D H F2+S F2+H // / \ / / \ / // ---o--------------------------o-o-----o-----------------o-------o-----> t // [F================================): : : // : : : : // : [) : : : // : [----): : : // : [F------) : : // : [F---------------------): : // : [F-----------------------------): // : [F----------------------F-------------> // TEST_F(FacetManagerTest, PrefetchTriggeredFetchSchedulingAfterNonEmptyCache) { … } // Last block of tests from above. TEST_F(FacetManagerTest, PrefetchTriggeredFetchSchedulingAfterNonEmptyCache2) { … } // Prefetches from above that have zero length. TEST_F(FacetManagerTest, ExpiredPrefetchDoesNothing) { … } // Nested prefetches. See legend above. // // t=0 S H F2+S F2+H // / / / / / // ---o--------------------------o-------o---------------o-------o---------> t // : : : : : // [F=========================F==============================): // [F=========================F=======================F===========> // [--) : : : : // : [--) : : : : // : [----------------------): : : : // : [------------------------------): : : // : [----------------------------------------------): : // : [------------------------------------------------------): // : [------): : : // : [----------------------): : // : [------------------------------): // : : [----): : : // : : [--------------------): : // : : [----------------------------): // : : [------): // : : : [----): // TEST_F(FacetManagerTest, NestedPrefetches) { … } // Overlapping prefetches. See legend above. // // t=0 S H F2+S F2+H // / / / / / // ---o--------------------------o-------o---------------o-------o---------> t // : : : : : // [F================================): : : // : [--------------------F------------------------------): // : [--------------------F-----------------------F-----------> // : [F-----------------------------): // : [F----------------------F-----------> // TEST_F(FacetManagerTest, OverlappingPrefetches) { … } // Prefetches with network fetches taking non-zero time. See legend above. // // t=0 S S+D H S+H S+H+2*D // / \ / / \ / // ---o--------------------------o-o-----o-----------------------o-o-o-----> t // : : : : : : : // [NNF------------------------------): : : : // [F-------------------------NNF----------------------------): : : // [NNNNNNNNNNNNNNNNNNNNNNNNNNF------------------------------): : : // : : : : : : : // [NNF----------------------------------) : : : // [F-------------------------NNF------------------------------): : // [NNNNNNNNNNNNNNNNNNNNNNNNNNNNF------------------------------): : // [NNF-------------------------NNF------------------------------): // : : : : : // [NNN) : : : : // [NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN): : // [F-------------------------NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN): // [NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN): // [NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN... // TEST_F(FacetManagerTest, PrefetchWithNonInstantFetches) { … } // Canceling prefetches. See legend above. // // t=0 S H F2+S F2+H // / / / / / // ---o--------------------------o-------o---------------o-------o---------> t // : : : : : // [F--X- - - - - - - - - - - - - - -): : : // [F-------------------------X - - -): : : // [F----------------------------X- -): : : // [F--X- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -> // [F-------------------------X - - - - - - - - - - - - - - - - - -> // [F-------------------------F--X- - - - - - - - - - - - - - - - -> // [F-------------------------F----------X- - - - - - - - - - - - -> // [F-------------------------F-----------------------X - - - - - -> // [F-------------------------F-----------------------F--X- - - - -> // TEST_F(FacetManagerTest, CancelPrefetch) { … } // Canceling in case of multiple nested prefetches. See legend above. // // t=0 S H F2+S F2+H // / / / / / // ---o--------------------------o-------o---------------o-------o---------> t // : : : : : // [F-------------------------F---------------------------X- ): // [---------------------------------X- - - - - - - - - - - -) // [--X- - - - - - - - - - - - - - - - - - - - - - - - - - -) // TEST_F(FacetManagerTest, CancelNestedPrefetches) { … } // Canceling in case of duplicate prefetches with the same |until| value. See // legend above. // // t=0 S H F2+S F2+H // / / / / / // ---o--------------------------o-------o---------------o-------o---------> t // : : : : : // [F-------------------------F-----------------------F--X- - - - -> // [--------------------------X - - - - - - - - - - - - - - - - - -> // [--X - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -> // TEST_F(FacetManagerTest, CancelNestedPrefetchesWithMultiplicity) { … } TEST_F(FacetManagerTest, CancelingNonexistentPrefetchesIsSilentlyIgnored) { … } TEST_F(FacetManagerTest, CachedDataCannotBeDiscarded) { … } // RequestNotificationAtTime() ends up calling NotifyAtRequestedTime() always // a bit earlier than needed. This should result in NotifyAtRequestedTime() // being called repeatedly until the callback is finally on time, but should // not otherwise result in a change of behavior. TEST_F(FacetManagerTest, RequestedNotificationsComeTooEarly) { … } // RequestNotificationAtTime() ends up calling NotifyAtRequestedTime() always // a short time after desired. This may result in SignalNeedNetworkRequest() // coming in late, but DoesRequireFetch() should get set at the correct time. TEST_F(FacetManagerTest, RequestedNotificationsComeTooLate) { … } // RequestNotificationAtTime() ends up not calling NotifyAtRequestedTime() at // all. This should result in SignalNeedNetworkRequest() not being called, but // DoesRequireFetch() should be set as long as the prefetch is active. TEST_F(FacetManagerTest, RequestedNotificationsNeverCome) { … } TEST_F(FacetManagerTest, StaleCachedDataBeCanDiscardedWhilePendingFetch) { … } TEST_F(FacetManagerTest, CachedDataBeCanDiscardedAfterOnDemandGetAffiliatons) { … } // The cached data can be discarded (indicated by 'd') if and only if it is no // longer needed to be kept fresh, or if it already stale. // // t=0 S H F2+S F2+H // / / / / / // ---o--------------------------o-------o------------------o-------o------> t // : : : // [F-------------------------NNNNNNNNNNNF---) // ddd ddd... // TEST_F(FacetManagerTest, CachedDataCanBeDiscardedAfterAndSometimesDuringPrefetch) { … } TEST_F(FacetManagerTest, CachedDataBeCanDiscardedAfterCancelledPrefetch) { … } TEST_F(FacetManagerTest, GetAffiliationsAndBrandingOnceOverNetworkSuccess) { … } TEST_F(FacetManagerTest, GetAffiliationsAndBrandingOnceOverNetworkFailure) { … } } // namespace affiliations