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

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: Eric's comment Created 4 years 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 const char* kDifferentInterval = "2";
tschumann 2016/12/21 09:41:02 as it is, this as very little context. I'd probabl
jkrcal 2016/12/21 11:54:39 Agreed, I think this is actually clear enough with
56
57 class MockPersistentScheduler : public PersistentScheduler {
58 public:
59 MOCK_METHOD2(Schedule,
60 bool(base::TimeDelta period_wifi,
61 base::TimeDelta period_fallback));
62 MOCK_METHOD0(Unschedule, bool());
63 };
64
65 class MockRemoteSuggestionsProvider : public RemoteSuggestionsProvider {
tschumann 2016/12/21 09:41:01 this guy should probably go into it's on library s
jkrcal 2016/12/21 11:54:40 I am not sure which other tests need it in the clo
66 public:
67 MockRemoteSuggestionsProvider(Observer* observer)
68 : RemoteSuggestionsProvider(observer),
69 provider_status_callback_(nullptr),
70 fetch_status_callback_(nullptr) {}
71
72 void SetProviderStatusCallback(
tschumann 2016/12/21 09:41:02 a comment might be nice, something like: // Sched
jkrcal 2016/12/21 11:54:40 Added the comment.
73 std::unique_ptr<RemoteSuggestionsProvider::ProviderStatusCallback>
74 callback) {
75 provider_status_callback_ = std::move(callback);
76 }
77
78 void ChangeStatus(RemoteSuggestionsProvider::ProviderStatus new_status) {
79 provider_status_callback_->Run(new_status);
80 }
81
82 // Move-only params are not supported by GMock.
83 void RefetchInTheBackground(
84 std::unique_ptr<RemoteSuggestionsProvider::FetchStatusCallback>
85 callback) {
tschumann 2016/12/21 09:41:02 that method is overriding RemoteSuggestionsProvide
jkrcal 2016/12/21 11:54:40 Done.
86 RefetchInTheBackground(callback.get());
87 fetch_status_callback_ = std::move(callback);
tschumann 2016/12/21 09:41:01 this is fishy as you're adding fake semantics. The
jkrcal 2016/12/21 11:54:40 I am puzzled by your solution. Would not the uniqu
88 }
89 MOCK_METHOD1(RefetchInTheBackground,
90 void(RemoteSuggestionsProvider::FetchStatusCallback*));
91 void CompleteBackgroundFetch(Status status_code) {
92 fetch_status_callback_->Run(status_code);
93 fetch_status_callback_.reset();
94 }
95
96 MOCK_CONST_METHOD0(snippets_fetcher_for_testing_and_debugging,
97 const NTPSnippetsFetcher*());
98
99 MOCK_METHOD1(GetCategoryStatus, CategoryStatus(Category));
100 MOCK_METHOD1(GetCategoryInfo, CategoryInfo(Category));
101 MOCK_METHOD3(ClearHistory,
102 void(base::Time begin,
103 base::Time end,
104 const base::Callback<bool(const GURL& url)>& filter));
105 MOCK_METHOD3(Fetch,
106 void(const Category&,
107 const std::set<std::string>&,
108 const FetchDoneCallback&));
109 MOCK_METHOD1(ClearCachedSuggestions, void(Category));
110 MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category));
111 MOCK_METHOD1(DismissSuggestion, void(const ContentSuggestion::ID&));
112 MOCK_METHOD2(FetchSuggestionImage,
113 void(const ContentSuggestion::ID&, const ImageFetchedCallback&));
114 MOCK_METHOD2(GetDismissedSuggestionsForDebugging,
115 void(Category, const DismissedSuggestionsCallback&));
116 MOCK_METHOD0(OnSignInStateChanged, void());
117
118 std::unique_ptr<RemoteSuggestionsProvider::ProviderStatusCallback>
119 provider_status_callback_;
120 std::unique_ptr<RemoteSuggestionsProvider::FetchStatusCallback>
121 fetch_status_callback_;
122 };
123
124 } // namespace
125
126 class SchedulingRemoteSuggestionsProviderTest
127 : public ::testing::Test {
128 public:
129 SchedulingRemoteSuggestionsProviderTest()
130 : underlying_provider_(nullptr),
131 scheduling_provider_(nullptr),
132 user_classifier_(/*pref_service=*/nullptr) {
133 SchedulingRemoteSuggestionsProvider::RegisterProfilePrefs(
134 utils_.pref_service()->registry());
135
136 auto underlying_provider =
137 base::MakeUnique<StrictMock<MockRemoteSuggestionsProvider>>(
138 /*observer=*/nullptr);
139 underlying_provider_ = underlying_provider.get();
140
141 scheduling_provider_ =
142 base::MakeUnique<SchedulingRemoteSuggestionsProvider>(
143 /*observer=*/nullptr, std::move(underlying_provider),
144 &persistent_scheduler_, &user_classifier_, utils_.pref_service());
145 }
146
147 protected:
148 StrictMock<MockPersistentScheduler> persistent_scheduler_;
149 StrictMock<MockRemoteSuggestionsProvider>* underlying_provider_;
150 std::unique_ptr<SchedulingRemoteSuggestionsProvider> scheduling_provider_;
151
152 private:
153 test::RemoteSuggestionsTestUtils utils_;
154 UserClassifier user_classifier_;
155
156 DISALLOW_COPY_AND_ASSIGN(SchedulingRemoteSuggestionsProviderTest);
157 };
158
159 TEST_F(SchedulingRemoteSuggestionsProviderTest,
160 ShouldFetchOnPersistentSchedulerWakeUp) {
161 EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
162 scheduling_provider_->OnPersistentSchedulerWakeUp();
163 }
164
165 TEST_F(SchedulingRemoteSuggestionsProviderTest,
166 ShouldRescheduleOnRescheduleFetching) {
167 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
168 scheduling_provider_->RescheduleFetching();
169 }
170
171 TEST_F(SchedulingRemoteSuggestionsProviderTest, ShouldScheduleOnActivation) {
172 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
173 underlying_provider_->ChangeStatus(
174 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
175 }
176
177 TEST_F(SchedulingRemoteSuggestionsProviderTest,
178 ShouldUnscheduleOnLaterInactivation) {
179 {
180 InSequence s;
181 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
182 EXPECT_CALL(persistent_scheduler_, Unschedule());
183 }
184 underlying_provider_->ChangeStatus(
185 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
186 underlying_provider_->ChangeStatus(
187 RemoteSuggestionsProvider::ProviderStatus::INACTIVE);
188 }
189
190 TEST_F(SchedulingRemoteSuggestionsProviderTest,
191 ShouldScheduleOnLaterActivation) {
192 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
193 // There is no schedule yet, so inactivation does not trigger unschedule.
194 underlying_provider_->ChangeStatus(
195 RemoteSuggestionsProvider::ProviderStatus::INACTIVE);
196 underlying_provider_->ChangeStatus(
197 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
198 }
199
200 TEST_F(SchedulingRemoteSuggestionsProviderTest,
201 ShouldRescheduleAfterSuccessfulFetch) {
202 // First reschedule on becoming active.
203 EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
204 underlying_provider_->ChangeStatus(
205 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
206
207 // Trigger a fetch.
208 EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
209 scheduling_provider_->OnPersistentSchedulerWakeUp();
210 // Second reschedule after a successful fetch.
211 underlying_provider_->CompleteBackgroundFetch(Status::Success());
212 }
213
214 TEST_F(SchedulingRemoteSuggestionsProviderTest,
215 ShouldNotRescheduleAfterFailedFetch) {
216 // Only reschedule on becoming active.
217 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
218 underlying_provider_->ChangeStatus(
219 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
220
221 // Trigger a fetch.
222 EXPECT_CALL(*underlying_provider_, RefetchInTheBackground(_));
223 scheduling_provider_->OnPersistentSchedulerWakeUp();
224 // No furter reschedule after a failure.
225 underlying_provider_->CompleteBackgroundFetch(
226 Status(StatusCode::PERMANENT_ERROR, ""));
227 }
228
229 TEST_F(SchedulingRemoteSuggestionsProviderTest, ShouldScheduleOnlyOnce) {
230 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
231 underlying_provider_->ChangeStatus(
232 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
233 // No further call to Schedule on a second status callback.
234 underlying_provider_->ChangeStatus(
235 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
236 }
237
238 TEST_F(SchedulingRemoteSuggestionsProviderTest, ShouldUnscheduleOnlyOnce) {
239 {
240 InSequence s;
241 EXPECT_CALL(persistent_scheduler_, Schedule(_, _));
242 EXPECT_CALL(persistent_scheduler_, Unschedule());
243 }
244 // First schedule so that later we really unschedule.
245 underlying_provider_->ChangeStatus(
246 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
247 underlying_provider_->ChangeStatus(
248 RemoteSuggestionsProvider::ProviderStatus::INACTIVE);
249 // No further call to Unschedule on second status callback.
250 underlying_provider_->ChangeStatus(
251 RemoteSuggestionsProvider::ProviderStatus::INACTIVE);
252 }
253
254 TEST_F(SchedulingRemoteSuggestionsProviderTest,
255 ReschedulesWhenWifiParamChanges) {
256 EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
257 underlying_provider_->ChangeStatus(
258 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
259
260 // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
261 // null. Change the wifi interval for this class.
262 variations::testing::VariationParamsManager params_manager(
263 ntp_snippets::kStudyName,
264 {{"fetching_interval_hours-wifi-active_ntp_user", kDifferentInterval}},
265 {kArticleSuggestionsFeature.name});
266
267 // Schedule() should get called for the second time after params have changed.
268 underlying_provider_->ChangeStatus(
269 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
270 }
271
272 TEST_F(SchedulingRemoteSuggestionsProviderTest,
273 ReschedulesWhenFallbackParamChanges) {
274 EXPECT_CALL(persistent_scheduler_, Schedule(_, _)).Times(2);
275 underlying_provider_->ChangeStatus(
276 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
277
278 // UserClassifier defaults to UserClass::ACTIVE_NTP_USER if PrefService is
279 // null. Change the wifi interval for this class.
280 variations::testing::VariationParamsManager params_manager(
281 ntp_snippets::kStudyName,
282 {{"fetching_interval_hours-fallback-active_ntp_user",
283 kDifferentInterval}},
284 {kArticleSuggestionsFeature.name});
285
286 // Schedule() should get called for the second time after params have changed.
287 underlying_provider_->ChangeStatus(
288 RemoteSuggestionsProvider::ProviderStatus::ACTIVE);
289 }
290
291 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698