blob: 08af1967adbe87336efc3f05a593efc6c077a893 [file] [log] [blame]
fhorschigcb5d7fc02016-12-20 13:14:551// 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
treib9de525a2017-01-19 12:20:375#include "components/ntp_snippets/remote/json_request.h"
fhorschigcb5d7fc02016-12-20 13:14:556
7#include <set>
8#include <utility>
9
10#include "base/json/json_reader.h"
fhorschigcb5d7fc02016-12-20 13:14:5511#include "base/strings/stringprintf.h"
12#include "base/test/test_mock_time_task_runner.h"
13#include "base/time/tick_clock.h"
14#include "base/time/time.h"
15#include "base/values.h"
16#include "components/ntp_snippets/features.h"
17#include "components/ntp_snippets/ntp_snippets_constants.h"
treib9de525a2017-01-19 12:20:3718#include "components/ntp_snippets/remote/request_params.h"
fhorschigcb5d7fc02016-12-20 13:14:5519#include "components/prefs/testing_pref_service.h"
20#include "components/variations/variations_params_manager.h"
21#include "net/url_request/test_url_fetcher_factory.h"
22#include "net/url_request/url_request_test_util.h"
23#include "testing/gmock/include/gmock/gmock.h"
24#include "testing/gtest/include/gtest/gtest.h"
25
26namespace ntp_snippets {
27
28namespace internal {
29
30namespace {
31
32using testing::_;
33using testing::Eq;
34using testing::Not;
35using testing::NotNull;
36using testing::StrEq;
37
38MATCHER_P(EqualsJSON, json, "equals JSON") {
39 std::unique_ptr<base::Value> expected = base::JSONReader::Read(json);
40 if (!expected) {
41 *result_listener << "INTERNAL ERROR: couldn't parse expected JSON";
42 return false;
43 }
44
45 std::string err_msg;
46 int err_line, err_col;
47 std::unique_ptr<base::Value> actual = base::JSONReader::ReadAndReturnError(
48 arg, base::JSON_PARSE_RFC, nullptr, &err_msg, &err_line, &err_col);
49 if (!actual) {
50 *result_listener << "input:" << err_line << ":" << err_col << ": "
51 << "parse error: " << err_msg;
52 return false;
53 }
jdoerrie8551f922017-07-25 10:55:1354 return *expected == *actual;
fhorschigcb5d7fc02016-12-20 13:14:5555}
56
57} // namespace
58
treib9de525a2017-01-19 12:20:3759class JsonRequestTest : public testing::Test {
fhorschigcb5d7fc02016-12-20 13:14:5560 public:
treib9de525a2017-01-19 12:20:3761 JsonRequestTest()
fhorschigcb5d7fc02016-12-20 13:14:5562 : params_manager_(
sfiera0500d4a2017-03-30 11:58:4463 ntp_snippets::kArticleSuggestionsFeature.name,
fhorschigcb5d7fc02016-12-20 13:14:5564 {{"send_top_languages", "true"}, {"send_user_class", "true"}},
65 {ntp_snippets::kArticleSuggestionsFeature.name}),
Jinho Bangedffb4ee2018-01-02 15:38:3066 pref_service_(std::make_unique<TestingPrefServiceSimple>()),
fhorschigcb5d7fc02016-12-20 13:14:5567 mock_task_runner_(new base::TestMockTimeTaskRunner()),
markusheintz05b1e882017-02-15 14:38:1968 clock_(mock_task_runner_->GetMockClock()),
fhorschigcb5d7fc02016-12-20 13:14:5569 request_context_getter_(
70 new net::TestURLRequestContextGetter(mock_task_runner_.get())) {
Michael Martis98cd8732017-07-14 03:26:1971 language::UrlLanguageHistogram::RegisterProfilePrefs(
72 pref_service_->registry());
fhorschigcb5d7fc02016-12-20 13:14:5573 }
74
Michael Martis98cd8732017-07-14 03:26:1975 std::unique_ptr<language::UrlLanguageHistogram> MakeLanguageHistogram(
fhorschigcb5d7fc02016-12-20 13:14:5576 const std::set<std::string>& codes) {
Michael Martis98cd8732017-07-14 03:26:1977 std::unique_ptr<language::UrlLanguageHistogram> language_histogram =
Jinho Bangedffb4ee2018-01-02 15:38:3078 std::make_unique<language::UrlLanguageHistogram>(pref_service_.get());
fhorschigcb5d7fc02016-12-20 13:14:5579 // There must be at least 10 visits before the top languages are defined.
80 for (int i = 0; i < 10; i++) {
81 for (const std::string& code : codes) {
Michael Martis98cd8732017-07-14 03:26:1982 language_histogram->OnPageVisited(code);
fhorschigcb5d7fc02016-12-20 13:14:5583 }
84 }
Michael Martis98cd8732017-07-14 03:26:1985 return language_histogram;
fhorschigcb5d7fc02016-12-20 13:14:5586 }
87
treib9de525a2017-01-19 12:20:3788 JsonRequest::Builder CreateMinimalBuilder() {
89 JsonRequest::Builder builder;
fhorschigcb5d7fc02016-12-20 13:14:5590 builder.SetUrl(GURL("http://valid-url.test"))
markusheintz05b1e882017-02-15 14:38:1991 .SetClock(clock_.get())
fhorschigcb5d7fc02016-12-20 13:14:5592 .SetUrlRequestContextGetter(request_context_getter_.get());
93 return builder;
94 }
95
96 private:
97 variations::testing::VariationParamsManager params_manager_;
98 std::unique_ptr<TestingPrefServiceSimple> pref_service_;
99 scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_;
markusheintz05b1e882017-02-15 14:38:19100 std::unique_ptr<base::Clock> clock_;
fhorschigcb5d7fc02016-12-20 13:14:55101 scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
102 net::TestURLFetcherFactory fetcher_factory_;
103
treib9de525a2017-01-19 12:20:37104 DISALLOW_COPY_AND_ASSIGN(JsonRequestTest);
fhorschigcb5d7fc02016-12-20 13:14:55105};
106
treib9de525a2017-01-19 12:20:37107TEST_F(JsonRequestTest, BuildRequestAuthenticated) {
108 JsonRequest::Builder builder = CreateMinimalBuilder();
109 RequestParams params;
fhorschigcb5d7fc02016-12-20 13:14:55110 params.excluded_ids = {"1234567890"};
111 params.count_to_fetch = 25;
112 params.interactive_request = false;
113 builder.SetParams(params)
114 .SetUrl(GURL("http://valid-url.test"))
fhorschigcb5d7fc02016-12-20 13:14:55115 .SetAuthentication("0BFUSGAIA", "headerstuff")
fhorschigcb5d7fc02016-12-20 13:14:55116 .SetUserClassForTesting("ACTIVE_NTP_USER")
fhorschigcb5d7fc02016-12-20 13:14:55117 .Build();
118
119 EXPECT_THAT(builder.PreviewRequestHeadersForTesting(),
120 StrEq("Content-Type: application/json; charset=UTF-8\r\n"
121 "Authorization: headerstuff\r\n"
122 "\r\n"));
123 EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
124 EqualsJSON("{"
fhorschigcb5d7fc02016-12-20 13:14:55125 " \"priority\": \"BACKGROUND_PREFETCH\","
126 " \"excludedSuggestionIds\": ["
127 " \"1234567890\""
128 " ],"
129 " \"userActivenessClass\": \"ACTIVE_NTP_USER\""
130 "}"));
131}
132
treib9de525a2017-01-19 12:20:37133TEST_F(JsonRequestTest, BuildRequestUnauthenticated) {
134 JsonRequest::Builder builder;
135 RequestParams params;
fhorschigcb5d7fc02016-12-20 13:14:55136 params.interactive_request = true;
137 params.count_to_fetch = 10;
treiba57f51e2017-03-23 14:47:52138 builder.SetParams(params).SetUserClassForTesting("ACTIVE_NTP_USER");
fhorschigcb5d7fc02016-12-20 13:14:55139
140 EXPECT_THAT(builder.PreviewRequestHeadersForTesting(),
141 StrEq("Content-Type: application/json; charset=UTF-8\r\n"
142 "\r\n"));
143 EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
144 EqualsJSON("{"
fhorschigcb5d7fc02016-12-20 13:14:55145 " \"priority\": \"USER_ACTION\","
146 " \"excludedSuggestionIds\": [],"
147 " \"userActivenessClass\": \"ACTIVE_NTP_USER\""
148 "}"));
149}
150
Vitalii Iarko15d451cf2017-06-09 13:57:29151TEST_F(JsonRequestTest, ShouldNotTruncateExcludedIdsList) {
treib9de525a2017-01-19 12:20:37152 JsonRequest::Builder builder;
153 RequestParams params;
fhorschigcb5d7fc02016-12-20 13:14:55154 params.interactive_request = false;
155 for (int i = 0; i < 200; ++i) {
156 params.excluded_ids.insert(base::StringPrintf("%03d", i));
157 }
treiba57f51e2017-03-23 14:47:52158 builder.SetParams(params).SetUserClassForTesting("ACTIVE_NTP_USER");
fhorschigcb5d7fc02016-12-20 13:14:55159
160 EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
161 EqualsJSON("{"
162 " \"priority\": \"BACKGROUND_PREFETCH\","
163 " \"excludedSuggestionIds\": ["
164 " \"000\", \"001\", \"002\", \"003\", \"004\","
165 " \"005\", \"006\", \"007\", \"008\", \"009\","
166 " \"010\", \"011\", \"012\", \"013\", \"014\","
167 " \"015\", \"016\", \"017\", \"018\", \"019\","
168 " \"020\", \"021\", \"022\", \"023\", \"024\","
169 " \"025\", \"026\", \"027\", \"028\", \"029\","
170 " \"030\", \"031\", \"032\", \"033\", \"034\","
171 " \"035\", \"036\", \"037\", \"038\", \"039\","
172 " \"040\", \"041\", \"042\", \"043\", \"044\","
173 " \"045\", \"046\", \"047\", \"048\", \"049\","
174 " \"050\", \"051\", \"052\", \"053\", \"054\","
175 " \"055\", \"056\", \"057\", \"058\", \"059\","
176 " \"060\", \"061\", \"062\", \"063\", \"064\","
177 " \"065\", \"066\", \"067\", \"068\", \"069\","
178 " \"070\", \"071\", \"072\", \"073\", \"074\","
179 " \"075\", \"076\", \"077\", \"078\", \"079\","
180 " \"080\", \"081\", \"082\", \"083\", \"084\","
181 " \"085\", \"086\", \"087\", \"088\", \"089\","
182 " \"090\", \"091\", \"092\", \"093\", \"094\","
Vitalii Iarko15d451cf2017-06-09 13:57:29183 " \"095\", \"096\", \"097\", \"098\", \"099\","
184 " \"100\", \"101\", \"102\", \"103\", \"104\","
185 " \"105\", \"106\", \"107\", \"108\", \"109\","
186 " \"110\", \"111\", \"112\", \"113\", \"114\","
187 " \"115\", \"116\", \"117\", \"118\", \"119\","
188 " \"120\", \"121\", \"122\", \"123\", \"124\","
189 " \"125\", \"126\", \"127\", \"128\", \"129\","
190 " \"130\", \"131\", \"132\", \"133\", \"134\","
191 " \"135\", \"136\", \"137\", \"138\", \"139\","
192 " \"140\", \"141\", \"142\", \"143\", \"144\","
193 " \"145\", \"146\", \"147\", \"148\", \"149\","
194 " \"150\", \"151\", \"152\", \"153\", \"154\","
195 " \"155\", \"156\", \"157\", \"158\", \"159\","
196 " \"160\", \"161\", \"162\", \"163\", \"164\","
197 " \"165\", \"166\", \"167\", \"168\", \"169\","
198 " \"170\", \"171\", \"172\", \"173\", \"174\","
199 " \"175\", \"176\", \"177\", \"178\", \"179\","
200 " \"180\", \"181\", \"182\", \"183\", \"184\","
201 " \"185\", \"186\", \"187\", \"188\", \"189\","
202 " \"190\", \"191\", \"192\", \"193\", \"194\","
203 " \"195\", \"196\", \"197\", \"198\", \"199\""
fhorschigcb5d7fc02016-12-20 13:14:55204 " ],"
205 " \"userActivenessClass\": \"ACTIVE_NTP_USER\""
206 "}"));
207}
208
treib9de525a2017-01-19 12:20:37209TEST_F(JsonRequestTest, BuildRequestNoUserClass) {
210 JsonRequest::Builder builder;
211 RequestParams params;
fhorschigcb5d7fc02016-12-20 13:14:55212 params.interactive_request = false;
treiba57f51e2017-03-23 14:47:52213 builder.SetParams(params);
fhorschigcb5d7fc02016-12-20 13:14:55214
215 EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
216 EqualsJSON("{"
217 " \"priority\": \"BACKGROUND_PREFETCH\","
218 " \"excludedSuggestionIds\": []"
219 "}"));
220}
221
treib9de525a2017-01-19 12:20:37222TEST_F(JsonRequestTest, BuildRequestWithTwoLanguages) {
223 JsonRequest::Builder builder;
Michael Martis98cd8732017-07-14 03:26:19224 std::unique_ptr<language::UrlLanguageHistogram> language_histogram =
225 MakeLanguageHistogram({"de", "en"});
treib9de525a2017-01-19 12:20:37226 RequestParams params;
fhorschigcb5d7fc02016-12-20 13:14:55227 params.interactive_request = true;
228 params.language_code = "en";
Michael Martis98cd8732017-07-14 03:26:19229 builder.SetParams(params).SetLanguageHistogram(language_histogram.get());
fhorschigcb5d7fc02016-12-20 13:14:55230
231 EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
232 EqualsJSON("{"
233 " \"priority\": \"USER_ACTION\","
234 " \"uiLanguage\": \"en\","
235 " \"excludedSuggestionIds\": [],"
236 " \"topLanguages\": ["
237 " {"
238 " \"language\" : \"en\","
239 " \"frequency\" : 0.5"
240 " },"
241 " {"
242 " \"language\" : \"de\","
243 " \"frequency\" : 0.5"
244 " }"
245 " ]"
246 "}"));
247}
248
treib9de525a2017-01-19 12:20:37249TEST_F(JsonRequestTest, BuildRequestWithUILanguageOnly) {
250 JsonRequest::Builder builder;
Michael Martis98cd8732017-07-14 03:26:19251 std::unique_ptr<language::UrlLanguageHistogram> language_histogram =
252 MakeLanguageHistogram({"en"});
treib9de525a2017-01-19 12:20:37253 RequestParams params;
fhorschigcb5d7fc02016-12-20 13:14:55254 params.interactive_request = true;
255 params.language_code = "en";
Michael Martis98cd8732017-07-14 03:26:19256 builder.SetParams(params).SetLanguageHistogram(language_histogram.get());
fhorschigcb5d7fc02016-12-20 13:14:55257
258 EXPECT_THAT(builder.PreviewRequestBodyForTesting(),
259 EqualsJSON("{"
260 " \"priority\": \"USER_ACTION\","
261 " \"uiLanguage\": \"en\","
262 " \"excludedSuggestionIds\": [],"
263 " \"topLanguages\": [{"
264 " \"language\" : \"en\","
265 " \"frequency\" : 1.0"
266 " }]"
267 "}"));
268}
269
Vitalii Iarko3fdb9f912017-09-21 08:28:25270TEST_F(JsonRequestTest,
271 ShouldPropagateCountToFetchWhenExclusiveCategoryPresent) {
272 JsonRequest::Builder builder;
273 RequestParams params;
274 params.interactive_request = true;
275 params.language_code = "en";
276 params.exclusive_category =
277 Category::FromKnownCategory(KnownCategories::ARTICLES);
278 params.count_to_fetch = 25;
279 builder.SetParams(params);
280
281 EXPECT_THAT(builder.PreviewRequestBodyForTesting(), EqualsJSON(R"(
282 {
283 "priority": "USER_ACTION",
284 "uiLanguage": "en",
285 "excludedSuggestionIds": [],
286 "categoryParameters": [{
287 "id": 1,
288 "numSuggestions": 25
289 }]
290 }
291 )"));
292}
293
294// TODO(vitaliii): Propagate count to fetch in this case as well and delete this
295// test. Currently the server does not support this.
296TEST_F(JsonRequestTest,
297 ShouldNotPropagateCountToFetchWhenExclusiveCategoryNotPresent) {
298 JsonRequest::Builder builder;
299 RequestParams params;
300 params.interactive_request = true;
301 params.language_code = "en";
302 params.count_to_fetch = 10;
303 builder.SetParams(params);
304
305 EXPECT_THAT(builder.PreviewRequestBodyForTesting(), EqualsJSON(R"(
306 {
307 "priority": "USER_ACTION",
308 "uiLanguage": "en",
309 "excludedSuggestionIds": []
310 }
311 )"));
312}
313
fhorschigcb5d7fc02016-12-20 13:14:55314} // namespace internal
315
316} // namespace ntp_snippets