fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 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 | |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 5 | #include "components/ntp_snippets/remote/json_request.h" |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 6 | |
| 7 | #include <set> |
| 8 | #include <utility> |
| 9 | |
| 10 | #include "base/json/json_reader.h" |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 11 | #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" |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 18 | #include "components/ntp_snippets/remote/request_params.h" |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 19 | #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 | |
| 26 | namespace ntp_snippets { |
| 27 | |
| 28 | namespace internal { |
| 29 | |
| 30 | namespace { |
| 31 | |
| 32 | using testing::_; |
| 33 | using testing::Eq; |
| 34 | using testing::Not; |
| 35 | using testing::NotNull; |
| 36 | using testing::StrEq; |
| 37 | |
| 38 | MATCHER_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 | } |
jdoerrie | 8551f92 | 2017-07-25 10:55:13 | [diff] [blame] | 54 | return *expected == *actual; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | } // namespace |
| 58 | |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 59 | class JsonRequestTest : public testing::Test { |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 60 | public: |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 61 | JsonRequestTest() |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 62 | : params_manager_( |
sfiera | 0500d4a | 2017-03-30 11:58:44 | [diff] [blame] | 63 | ntp_snippets::kArticleSuggestionsFeature.name, |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 64 | {{"send_top_languages", "true"}, {"send_user_class", "true"}}, |
| 65 | {ntp_snippets::kArticleSuggestionsFeature.name}), |
Jinho Bang | edffb4ee | 2018-01-02 15:38:30 | [diff] [blame^] | 66 | pref_service_(std::make_unique<TestingPrefServiceSimple>()), |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 67 | mock_task_runner_(new base::TestMockTimeTaskRunner()), |
markusheintz | 05b1e88 | 2017-02-15 14:38:19 | [diff] [blame] | 68 | clock_(mock_task_runner_->GetMockClock()), |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 69 | request_context_getter_( |
| 70 | new net::TestURLRequestContextGetter(mock_task_runner_.get())) { |
Michael Martis | 98cd873 | 2017-07-14 03:26:19 | [diff] [blame] | 71 | language::UrlLanguageHistogram::RegisterProfilePrefs( |
| 72 | pref_service_->registry()); |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 73 | } |
| 74 | |
Michael Martis | 98cd873 | 2017-07-14 03:26:19 | [diff] [blame] | 75 | std::unique_ptr<language::UrlLanguageHistogram> MakeLanguageHistogram( |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 76 | const std::set<std::string>& codes) { |
Michael Martis | 98cd873 | 2017-07-14 03:26:19 | [diff] [blame] | 77 | std::unique_ptr<language::UrlLanguageHistogram> language_histogram = |
Jinho Bang | edffb4ee | 2018-01-02 15:38:30 | [diff] [blame^] | 78 | std::make_unique<language::UrlLanguageHistogram>(pref_service_.get()); |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 79 | // 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 Martis | 98cd873 | 2017-07-14 03:26:19 | [diff] [blame] | 82 | language_histogram->OnPageVisited(code); |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 83 | } |
| 84 | } |
Michael Martis | 98cd873 | 2017-07-14 03:26:19 | [diff] [blame] | 85 | return language_histogram; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 86 | } |
| 87 | |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 88 | JsonRequest::Builder CreateMinimalBuilder() { |
| 89 | JsonRequest::Builder builder; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 90 | builder.SetUrl(GURL("http://valid-url.test")) |
markusheintz | 05b1e88 | 2017-02-15 14:38:19 | [diff] [blame] | 91 | .SetClock(clock_.get()) |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 92 | .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_; |
markusheintz | 05b1e88 | 2017-02-15 14:38:19 | [diff] [blame] | 100 | std::unique_ptr<base::Clock> clock_; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 101 | scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_; |
| 102 | net::TestURLFetcherFactory fetcher_factory_; |
| 103 | |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 104 | DISALLOW_COPY_AND_ASSIGN(JsonRequestTest); |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 105 | }; |
| 106 | |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 107 | TEST_F(JsonRequestTest, BuildRequestAuthenticated) { |
| 108 | JsonRequest::Builder builder = CreateMinimalBuilder(); |
| 109 | RequestParams params; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 110 | 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")) |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 115 | .SetAuthentication("0BFUSGAIA", "headerstuff") |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 116 | .SetUserClassForTesting("ACTIVE_NTP_USER") |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 117 | .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("{" |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 125 | " \"priority\": \"BACKGROUND_PREFETCH\"," |
| 126 | " \"excludedSuggestionIds\": [" |
| 127 | " \"1234567890\"" |
| 128 | " ]," |
| 129 | " \"userActivenessClass\": \"ACTIVE_NTP_USER\"" |
| 130 | "}")); |
| 131 | } |
| 132 | |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 133 | TEST_F(JsonRequestTest, BuildRequestUnauthenticated) { |
| 134 | JsonRequest::Builder builder; |
| 135 | RequestParams params; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 136 | params.interactive_request = true; |
| 137 | params.count_to_fetch = 10; |
treib | a57f51e | 2017-03-23 14:47:52 | [diff] [blame] | 138 | builder.SetParams(params).SetUserClassForTesting("ACTIVE_NTP_USER"); |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 139 | |
| 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("{" |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 145 | " \"priority\": \"USER_ACTION\"," |
| 146 | " \"excludedSuggestionIds\": []," |
| 147 | " \"userActivenessClass\": \"ACTIVE_NTP_USER\"" |
| 148 | "}")); |
| 149 | } |
| 150 | |
Vitalii Iarko | 15d451cf | 2017-06-09 13:57:29 | [diff] [blame] | 151 | TEST_F(JsonRequestTest, ShouldNotTruncateExcludedIdsList) { |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 152 | JsonRequest::Builder builder; |
| 153 | RequestParams params; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 154 | params.interactive_request = false; |
| 155 | for (int i = 0; i < 200; ++i) { |
| 156 | params.excluded_ids.insert(base::StringPrintf("%03d", i)); |
| 157 | } |
treib | a57f51e | 2017-03-23 14:47:52 | [diff] [blame] | 158 | builder.SetParams(params).SetUserClassForTesting("ACTIVE_NTP_USER"); |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 159 | |
| 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 Iarko | 15d451cf | 2017-06-09 13:57:29 | [diff] [blame] | 183 | " \"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\"" |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 204 | " ]," |
| 205 | " \"userActivenessClass\": \"ACTIVE_NTP_USER\"" |
| 206 | "}")); |
| 207 | } |
| 208 | |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 209 | TEST_F(JsonRequestTest, BuildRequestNoUserClass) { |
| 210 | JsonRequest::Builder builder; |
| 211 | RequestParams params; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 212 | params.interactive_request = false; |
treib | a57f51e | 2017-03-23 14:47:52 | [diff] [blame] | 213 | builder.SetParams(params); |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 214 | |
| 215 | EXPECT_THAT(builder.PreviewRequestBodyForTesting(), |
| 216 | EqualsJSON("{" |
| 217 | " \"priority\": \"BACKGROUND_PREFETCH\"," |
| 218 | " \"excludedSuggestionIds\": []" |
| 219 | "}")); |
| 220 | } |
| 221 | |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 222 | TEST_F(JsonRequestTest, BuildRequestWithTwoLanguages) { |
| 223 | JsonRequest::Builder builder; |
Michael Martis | 98cd873 | 2017-07-14 03:26:19 | [diff] [blame] | 224 | std::unique_ptr<language::UrlLanguageHistogram> language_histogram = |
| 225 | MakeLanguageHistogram({"de", "en"}); |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 226 | RequestParams params; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 227 | params.interactive_request = true; |
| 228 | params.language_code = "en"; |
Michael Martis | 98cd873 | 2017-07-14 03:26:19 | [diff] [blame] | 229 | builder.SetParams(params).SetLanguageHistogram(language_histogram.get()); |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 230 | |
| 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 | |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 249 | TEST_F(JsonRequestTest, BuildRequestWithUILanguageOnly) { |
| 250 | JsonRequest::Builder builder; |
Michael Martis | 98cd873 | 2017-07-14 03:26:19 | [diff] [blame] | 251 | std::unique_ptr<language::UrlLanguageHistogram> language_histogram = |
| 252 | MakeLanguageHistogram({"en"}); |
treib | 9de525a | 2017-01-19 12:20:37 | [diff] [blame] | 253 | RequestParams params; |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 254 | params.interactive_request = true; |
| 255 | params.language_code = "en"; |
Michael Martis | 98cd873 | 2017-07-14 03:26:19 | [diff] [blame] | 256 | builder.SetParams(params).SetLanguageHistogram(language_histogram.get()); |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 257 | |
| 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 Iarko | 3fdb9f91 | 2017-09-21 08:28:25 | [diff] [blame] | 270 | TEST_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. |
| 296 | TEST_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 | |
fhorschig | cb5d7fc0 | 2016-12-20 13:14:55 | [diff] [blame] | 314 | } // namespace internal |
| 315 | |
| 316 | } // namespace ntp_snippets |