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

Side by Side Diff: components/ntp_snippets/remote/scheduling_remote_suggestions_provider_unittest.cc

Issue 2557363002: [NTP Snippets] Refactor background scheduling for remote suggestions (Closed)
Patch Set: Fixing the last changes :) Created 3 years, 12 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/ntp_snippets/remote/scheduling_remote_suggestions_provider. h"
6
7 #include <memory>
8 #include <set>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/command_line.h"
14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/run_loop.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/time/time.h"
20 #include "components/ntp_snippets/features.h"
21 #include "components/ntp_snippets/ntp_snippets_constants.h"
22 #include "components/ntp_snippets/pref_names.h"
23 #include "components/ntp_snippets/remote/persistent_scheduler.h"
24 #include "components/ntp_snippets/remote/remote_suggestions_provider.h"
25 #include "components/ntp_snippets/remote/test_utils.h"
26 #include "components/ntp_snippets/status.h"
27 #include "components/ntp_snippets/user_classifier.h"
28 #include "components/prefs/testing_pref_service.h"
29 #include "components/variations/variations_params_manager.h"
30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 using testing::ElementsAre;
34 using testing::Eq;
35 using testing::InSequence;
36 using testing::Invoke;
37 using testing::IsEmpty;
38 using testing::Mock;
39 using testing::MockFunction;
40 using testing::Not;
41 using testing::SaveArg;
42 using testing::SaveArgPointee;
43 using testing::SizeIs;
44 using testing::StartsWith;
45 using testing::StrictMock;
46 using testing::WithArgs;
47 using testing::_;
48
49 namespace ntp_snippets {
50
51 class NTPSnippetsFetcher;
52
53 namespace {
54
55 class MockPersistentScheduler : public PersistentScheduler {
56 public:
57 MOCK_METHOD2(Schedule,
58 bool(base::TimeDelta period_wifi,
59 base::TimeDelta period_fallback));
60 MOCK_METHOD0(Unschedule, bool());
61 };
62
63 // TODO(jkrcal): Move into its own library to reuse in other unit-tests?
64 class MockRemoteSuggestionsProvider : public RemoteSuggestionsProvider {
65 public:
66 MockRemoteSuggestionsProvider(Observer* observer)
67 : RemoteSuggestionsProvider(observer) {}
68
69 // Move-only params are not supported by GMock. We want to mock out
70 // RefetchInTheBackground() which takes a unique_ptr<>. Instead, we add a new
71 // mock function which takes a copy of the callback and override the
72 // RemoteSuggestionsProvider's method to forward the call into the new mock
73 // function.
74 void SetProviderStatusCallback(
75 std::unique_ptr<RemoteSuggestionsProvider::ProviderStatusCallback>
76 callback) override {
77 SetProviderStatusCallback(*callback);
78 }
79 MOCK_METHOD1(SetProviderStatusCallback,
80 void(RemoteSuggestionsProvider::ProviderStatusCallback));
81
82 // Move-only params are not supported by GMock (same work-around as above).
83 void RefetchInTheBackground(
84 std::unique_ptr<RemoteSuggestionsProvider::FetchStatusCallback> callback)
85 override {
86 RefetchInTheBackground(*callback);
87 }
88 MOCK_METHOD1(RefetchInTheBackground,
89 void(RemoteSuggestionsProvider::FetchStatusCallback));
90
91 MOCK_CONST_METHOD0(snippets_fetcher_for_testing_and_debugging,
92 const NTPSnippetsFetcher*());
93
94 MOCK_METHOD1(GetCategoryStatus, CategoryStatus(Category));
95 MOCK_METHOD1(GetCategoryInfo, CategoryInfo(Category));
96 MOCK_METHOD3(ClearHistory,
97 void(base::Time begin,
98 base::Time end,
99 const base::Callback<bool(const GURL& url)>& filter));
100 MOCK_METHOD3(Fetch,
101 void(const Category&,
102 const std::set<std::string>&,
103 const FetchDoneCallback&));
104 MOCK_METHOD1(ClearCachedSuggestions, void(Category));
105 MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category));
106 MOCK_METHOD1(DismissSuggestion, void(const ContentSuggestion::ID&));
107 MOCK_METHOD2(FetchSuggestionImage,
108 void(const ContentSuggestion::ID&, const ImageFetchedCallback&));
109 MOCK_METHOD2(GetDismissedSuggestionsForDebugging,
110 void(Category, const DismissedSuggestionsCallback&));
111 MOCK_METHOD0(OnSignInStateChanged, void());
112 };
113
114 } // namespace
115
116 class SchedulingRemoteSuggestionsProviderTest
117 : public ::testing::Test {
118 public:
119 SchedulingRemoteSuggestionsProviderTest()
120 : underlying_provider_(nullptr),
121 scheduling_provider_(nullptr),
122 user_classifier_(/*pref_service=*/nullptr) {
123 SchedulingRemoteSuggestionsProvider::RegisterProfilePrefs(
124 utils_.pref_service()->registry());
125
126 auto underlying_provider =
127 base::MakeUnique<StrictMock<MockRemoteSuggestionsProvider>>(
128 /*observer=*/nullptr);
129 underlying_provider_ = underlying_provider.get();
130
131 // SchedulingRemoteSuggestionsProvider calls SetProviderStatusCallback(_) to
132 // stay in the loop of status changes.
133 EXPECT_CALL(*underlying_provider_, SetProviderStatusCallback(_))
134 .WillOnce(SaveArg<0>(&provider_status_callback_));
135
136 scheduling_provider_ =
137 base::MakeUnique<SchedulingRemoteSuggestionsProvider>(
138 /*observer=*/nullptr, std::move(underlying_provider),
139 &persistent_scheduler_, &user_classifier_, utils_.pref_service());
140 }
141
142 protected:
143 StrictMock<MockPersistentScheduler> persistent_scheduler_;
144 StrictMock<MockRemoteSuggestionsProvider>* underlying_provider_;
145 std::unique_ptr<SchedulingRemoteSuggestionsProvider> scheduling_provider_;
146 RemoteSuggestionsProvider::ProviderStatusCallback provider_status_callback_;
147
148 void ChangeStatusOfUnderlyingProvider(
149 RemoteSuggestionsProvider::ProviderStatus new_status) {
150 provider_status_callback_.Run(new_status);
151 }
152
153 private:
154 test::RemoteSuggestionsTestUtils utils_;
155 UserClassifier user_classifier_;
156
157 DISALLOW_COPY_AND_ASSIGN(SchedulingRemoteSuggestionsProviderTest);
158 };
159
160 TEST_F(SchedulingRemoteSuggestionsProviderTest,
161 ShouldFetchOnPersistentSchedulerWakeUp) {
162 EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
163 scheduling_provider_->OnPersistentSchedulerWakeUp();
164 }
165
166 TEST_F(SchedulingRemoteSuggestionsProviderTest,
167 ShouldRescheduleOnRescheduleFetching) {
168 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
169 scheduling_provider_->RescheduleFetching();
170 }
171
172 TEST_F(SchedulingRemoteSuggestionsProviderTest, ShouldScheduleOnActivation) {
173 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
174 ChangeStatusOfUnderlyingProvider(
175 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
176 }
177
178 TEST_F(SchedulingRemoteSuggestionsProviderTest,
179 ShouldUnscheduleOnLaterInactivation) {
180 {
181 InSequence s;
182 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
183 EXPECT_CALL(persistent_scheduler_, Unschedule());
184 }
185 ChangeStatusOfUnderlyingProvider(
186 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
187 ChangeStatusOfUnderlyingProvider(
188 RemoteSuggestionsProvider::ProviderStatus::INACTIVE);
189 }
190
191 TEST_F(SchedulingRemoteSuggestionsProviderTest,
192 ShouldScheduleOnLaterActivation) {
193 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
194 // There is no schedule yet, so inactivation does not trigger unschedule.
195 ChangeStatusOfUnderlyingProvider(
196 RemoteSuggestionsProvider::ProviderStatus::INACTIVE);
197 ChangeStatusOfUnderlyingProvider(
198 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
199 }
200
201 TEST_F(SchedulingRemoteSuggestionsProviderTest,
202 ShouldRescheduleAfterSuccessfulFetch) {
203 // First reschedule on becoming active.
204 EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
205 ChangeStatusOfUnderlyingProvider(
206 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
207
208 RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
209 EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
210 .WillOnce(SaveArg<0>(&signal_fetch_done));
211
212 // Trigger a fetch.
213 scheduling_provider_->OnPersistentSchedulerWakeUp();
214 // Second reschedule after a successful fetch.
215 signal_fetch_done.Run(Status::Success());
216 }
217
218 TEST_F(SchedulingRemoteSuggestionsProviderTest,
219 ShouldNotRescheduleAfterFailedFetch) {
220 // Only reschedule on becoming active.
221 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
222 ChangeStatusOfUnderlyingProvider(
223 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
224
225 RemoteSuggestionsProvider::FetchStatusCallback signal_fetch_done;
226 EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_))
227 .WillOnce(SaveArg<0>(&signal_fetch_done));
228
229 // Trigger a fetch.
230 scheduling_provider_->OnPersistentSchedulerWakeUp();
231 // No furter reschedule after a failure.
232 signal_fetch_done.Run(Status(StatusCode::PERMANENT_ERROR, ""));
233 }
234
235 TEST_F(SchedulingRemoteSuggestionsProviderTest, ShouldScheduleOnlyOnce) {
236 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
237 ChangeStatusOfUnderlyingProvider(
238 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
239 // No further call to Schedule on a second status callback.
240 ChangeStatusOfUnderlyingProvider(
241 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
242 }
243
244 TEST_F(SchedulingRemoteSuggestionsProviderTest, ShouldUnscheduleOnlyOnce) {
245 {
246 InSequence s;
247 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
248 EXPECT_CALL(persistent_scheduler_, Unschedule());
249 }
250 // First schedule so that later we really unschedule.
251 ChangeStatusOfUnderlyingProvider(
252 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
253 ChangeStatusOfUnderlyingProvider(
254 RemoteSuggestionsProvider::ProviderStatus::INACTIVE);
255 // No further call to Unschedule on second status callback.
256 ChangeStatusOfUnderlyingProvider(
257 RemoteSuggestionsProvider::ProviderStatus::INACTIVE);
258 }
259
260 TEST_F(SchedulingRemoteSuggestionsProviderTest,
261 ReschedulesWhenWifiParamChanges) {
262 EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
263 ChangeStatusOfUnderlyingProvider(
264 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
265
266 // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
267 // null. Change the wifi interval for this class.
268 variations::testing::VariationParamsManager params_manager(
269 ntp_snippets::kStudyName,
270 {{"fetching_interval_hours-wifi-active_ntp_user", "2"}},
271 {kArticleSuggestionsFeature.name});
272
273 // Schedule() should get called for the second time after params have changed.
274 ChangeStatusOfUnderlyingProvider(
275 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
276 }
277
278 TEST_F(SchedulingRemoteSuggestionsProviderTest,
279 ReschedulesWhenFallbackParamChanges) {
280 EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
281 ChangeStatusOfUnderlyingProvider(
282 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
283
284 // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
285 // null. Change the wifi interval for this class.
286 variations::testing::VariationParamsManager params_manager(
287 ntp_snippets::kStudyName,
288 {{"fetching_interval_hours-fallback-active_ntp_user", "2"}},
289 {kArticleSuggestionsFeature.name});
290
291 // Schedule() should get called for the second time after params have changed.
292 ChangeStatusOfUnderlyingProvider(
293 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
294 }
295
296 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698