Index: components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc |
diff --git a/components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc b/components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc |
index bad71569fb693ce62a5ddae880c70fa15656eef6..fb71e8d92cf9e6b42fa8ae39c1074d738d8235f4 100644 |
--- a/components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc |
+++ b/components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc |
@@ -34,6 +34,7 @@ |
using testing::ElementsAre; |
using testing::Eq; |
+using testing::Field; |
using testing::InSequence; |
using testing::Invoke; |
using testing::IsEmpty; |
@@ -98,6 +99,7 @@ class MockRemoteSuggestionsProvider : public RemoteSuggestionsProvider { |
void(const Category&, |
const std::set<std::string>&, |
const FetchDoneCallback&)); |
+ MOCK_METHOD0(ReloadSuggestions, void()); |
MOCK_METHOD1(ClearCachedSuggestions, void(Category)); |
MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category)); |
MOCK_METHOD1(DismissSuggestion, void(const ContentSuggestion::ID&)); |
@@ -126,6 +128,7 @@ class SchedulingRemoteSuggestionsProviderTest |
user_classifier_(/*pref_service=*/nullptr) { |
SchedulingRemoteSuggestionsProvider::RegisterProfilePrefs( |
utils_.pref_service()->registry()); |
+ RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry()); |
ResetProvider(); |
} |
@@ -157,6 +160,17 @@ class SchedulingRemoteSuggestionsProviderTest |
{ntp_snippets::kArticleSuggestionsFeature.name}); |
} |
+ // GMock cannot deal with move-only types. We need to pass the vector to the |
+ // mock function as const ref using this wrapper callback. |
+ void FetchDoneWrapper( |
+ MockFunction<void(Status status_code, |
+ const std::vector<ContentSuggestion>& suggestions)>* |
+ fetch_done, |
+ Status status_code, |
+ std::vector<ContentSuggestion> suggestions) { |
+ fetch_done->Call(status_code, suggestions); |
+ } |
+ |
protected: |
std::map<std::string, std::string> default_variation_params_; |
variations::testing::VariationParamsManager params_manager_; |
@@ -671,4 +685,86 @@ TEST_F(SchedulingRemoteSuggestionsProviderTest, |
scheduling_provider_->OnBrowserForegrounded(); |
} |
+TEST_F(SchedulingRemoteSuggestionsProviderTest, |
+ ShouldThrottleInteractiveRequests) { |
+ // Change the quota for interactive requests ("active NTP user" is the default |
+ // class in tests). |
+ SetVariationParameter("interactive_quota_SuggestionFetcherActiveNTPUser", |
+ "10"); |
+ ResetProvider(); |
+ |
+ Category category = Category::FromKnownCategory(KnownCategories::ARTICLES); |
+ std::set<std::string> known_suggestions; |
+ |
+ // Both Fetch(..) and ReloadSuggestions() consume the same quota. As long as |
+ // the quota suffices, the call gets through. |
+ EXPECT_CALL(*underlying_provider_, ReloadSuggestions()).Times(5); |
+ for (int x = 0; x < 5; ++x) { |
+ scheduling_provider_->ReloadSuggestions(); |
+ } |
+ |
+ // Expect underlying provider being called and store the callback to inform |
+ // scheduling provider. |
+ FetchDoneCallback signal_fetch_done_from_underlying_provider; |
+ EXPECT_CALL(*underlying_provider_, Fetch(_, _, _)) |
+ .Times(5) |
+ .WillRepeatedly(SaveArg<2>(&signal_fetch_done_from_underlying_provider)); |
+ // Expect scheduling provider to pass the information through. |
+ MockFunction<void(Status status_code, |
+ const std::vector<ContentSuggestion>& suggestions)> |
+ fetch_done_from_scheduling_provider; |
+ EXPECT_CALL(fetch_done_from_scheduling_provider, |
+ Call(Field(&Status::code, StatusCode::SUCCESS), _)) |
+ .Times(5); |
+ // Scheduling is not activated, each successful fetch results in Unschedule(). |
+ EXPECT_CALL(persistent_scheduler_, Unschedule()).Times(5); |
+ for (int x = 0; x < 5; ++x) { |
+ scheduling_provider_->Fetch( |
+ category, known_suggestions, |
+ base::Bind(&SchedulingRemoteSuggestionsProviderTest::FetchDoneWrapper, |
+ base::Unretained(this), |
+ &fetch_done_from_scheduling_provider)); |
+ // Inform scheduling provider the fetc is successful (with no suggestions). |
+ signal_fetch_done_from_underlying_provider.Run( |
+ Status::Success(), std::vector<ContentSuggestion>{}); |
+ } |
+ |
+ // When the quota expires, it is blocked by the scheduling provider, directly |
+ // calling the callback. |
+ EXPECT_CALL(fetch_done_from_scheduling_provider, |
+ Call(Field(&Status::code, StatusCode::TEMPORARY_ERROR), _)); |
+ scheduling_provider_->ReloadSuggestions(); |
+ scheduling_provider_->Fetch( |
+ category, known_suggestions, |
+ base::Bind(&SchedulingRemoteSuggestionsProviderTest::FetchDoneWrapper, |
+ base::Unretained(this), &fetch_done_from_scheduling_provider)); |
+} |
+ |
+TEST_F(SchedulingRemoteSuggestionsProviderTest, |
+ ShouldThrottleNonInteractiveRequests) { |
+ // Change the quota for interactive requests ("active NTP user" is the default |
+ // class in tests). |
+ SetVariationParameter("quota_SuggestionFetcherActiveNTPUser", "5"); |
+ ResetProvider(); |
+ |
+ // One scheduling on start, 5 times after successful fetches. |
+ EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(6); |
+ |
+ // First enable the scheduler -- this will trigger the persistent scheduling. |
+ ActivateUnderlyingProvider(); |
+ |
+ // As long as the quota suffices, the call gets through. |
+ RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done; |
+ EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_)) |
+ .Times(5) |
+ .WillRepeatedly(SaveArg<0>(&signal_fetch_done)); |
+ for (int x = 0; x < 5; ++x) { |
+ scheduling_provider_->OnPersistentSchedulerWakeUp(); |
+ signal_fetch_done.Run(Status::Success()); |
+ } |
+ |
+ // For the 6th time, it is blocked by the scheduling provider. |
+ scheduling_provider_->OnPersistentSchedulerWakeUp(); |
+} |
+ |
} // namespace ntp_snippets |