blob: 93b8b8fb85275755bddbe01e67f5e9d6a1c4b543 [file] [log] [blame]
sfieraacc10b62016-11-07 13:33:411// 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
mastizb06f14242016-12-15 12:32:175#include "components/ntp_tiles/popular_sites_impl.h"
sfieraacc10b62016-11-07 13:33:416
mastizfd2c7ab2017-01-27 19:35:007#include <map>
Gyuyoung Kimcb7965e2018-01-25 00:39:018#include <memory>
sfieraacc10b62016-11-07 13:33:419#include <string>
10#include <utility>
11#include <vector>
12
13#include "base/bind.h"
fhorschig7d16fb22017-02-15 08:28:0814#include "base/command_line.h"
sfieraacc10b62016-11-07 13:33:4115#include "base/json/json_writer.h"
sfieraacc10b62016-11-07 13:33:4116#include "base/run_loop.h"
Friedrich Horschigf48183742017-08-08 16:53:1317#include "base/strings/string_number_conversions.h"
Mark Pilgrim60a21d3a2018-05-30 15:37:4018#include "base/strings/utf_string_conversions.h"
fhorschigf84f9f52017-03-16 12:14:0619#include "base/test/scoped_feature_list.h"
Gabriel Charettec7108742019-08-23 03:31:4020#include "base/test/task_environment.h"
sfieraacc10b62016-11-07 13:33:4121#include "base/threading/thread_task_runner_handle.h"
22#include "base/values.h"
Nico Weber356b3042019-08-23 15:30:4123#include "build/branding_buildflags.h"
Friedrich Horschig2011ecd2017-07-10 17:03:3824#include "build/build_config.h"
Kristi Park01ca1252019-05-10 22:39:0525#include "components/ntp_tiles/features.h"
sfieraacc10b62016-11-07 13:33:4126#include "components/ntp_tiles/pref_names.h"
Friedrich Horschig7706ef62017-08-25 08:20:0027#include "components/ntp_tiles/tile_source.h"
sfieraacc10b62016-11-07 13:33:4128#include "components/pref_registry/pref_registry_syncable.h"
a-v-yb2cf8f82016-12-11 17:35:0729#include "components/sync_preferences/testing_pref_service_syncable.h"
sfieraacc10b62016-11-07 13:33:4130#include "net/http/http_status_code.h"
Ken Rockot67226642019-10-31 16:40:5331#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
Mark Pilgrim60a21d3a2018-05-30 15:37:4032#include "services/network/public/cpp/shared_url_loader_factory.h"
33#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
34#include "services/network/test/test_url_loader_factory.h"
sfieraacc10b62016-11-07 13:33:4135#include "testing/gmock/include/gmock/gmock.h"
36#include "testing/gtest/include/gtest/gtest.h"
Anton Bikineev1156b5f2021-05-15 22:35:3637#include "third_party/abseil-cpp/absl/types/optional.h"
sfieraacc10b62016-11-07 13:33:4138
Friedrich Horschigf48183742017-08-08 16:53:1339using testing::_;
40using testing::Contains;
41using testing::ElementsAre;
sfieraacc10b62016-11-07 13:33:4142using testing::Eq;
fhorschigfed34be2017-03-02 23:16:0943using testing::Gt;
sfierac49f0e42016-11-08 13:49:5444using testing::IsEmpty;
Friedrich Horschigf48183742017-08-08 16:53:1345using testing::Not;
46using testing::Pair;
47using testing::SizeIs;
sfieraacc10b62016-11-07 13:33:4148
49namespace ntp_tiles {
50namespace {
51
52const char kTitle[] = "title";
53const char kUrl[] = "url";
54const char kLargeIconUrl[] = "large_icon_url";
55const char kFaviconUrl[] = "favicon_url";
Friedrich Horschigf48183742017-08-08 16:53:1356const char kSection[] = "section";
57const char kSites[] = "sites";
Friedrich Horschigefec0812017-09-28 18:50:1758const char kTitleSource[] = "title_source";
sfieraacc10b62016-11-07 13:33:4159
sfierac49f0e42016-11-08 13:49:5460using TestPopularSite = std::map<std::string, std::string>;
sfieraacc10b62016-11-07 13:33:4161using TestPopularSiteVector = std::vector<TestPopularSite>;
Friedrich Horschigf48183742017-08-08 16:53:1362using TestPopularSection = std::pair<SectionType, TestPopularSiteVector>;
63using TestPopularSectionVector = std::vector<TestPopularSection>;
sfieraacc10b62016-11-07 13:33:4164
Jan Wilken Dörriefa241ba2021-03-11 17:57:0165::testing::Matcher<const std::u16string&> Str16Eq(const std::string& s) {
sfieraacc10b62016-11-07 13:33:4166 return ::testing::Eq(base::UTF8ToUTF16(s));
67}
68
69::testing::Matcher<const GURL&> URLEq(const std::string& s) {
70 return ::testing::Eq(GURL(s));
71}
72
fhorschig7d16fb22017-02-15 08:28:0873size_t GetNumberOfDefaultPopularSitesForPlatform() {
Friedrich Horschig7f4a97f2017-07-10 17:50:5774#if defined(OS_ANDROID) || defined(OS_IOS)
fhorschig7d16fb22017-02-15 08:28:0875 return 8ul;
76#else
fhorschigf84f9f52017-03-16 12:14:0677 return 0ul;
fhorschig7d16fb22017-02-15 08:28:0878#endif
79}
80
sfieraacc10b62016-11-07 13:33:4181class PopularSitesTest : public ::testing::Test {
82 protected:
83 PopularSitesTest()
sfierac49f0e42016-11-08 13:49:5484 : kWikipedia{
85 {kTitle, "Wikipedia, fhta Ph'nglui mglw'nafh"},
86 {kUrl, "https://zz.m.wikipedia.org/"},
87 {kLargeIconUrl, "https://zz.m.wikipedia.org/wikipedia.png"},
Friedrich Horschigefec0812017-09-28 18:50:1788 {kTitleSource, "3"}, // Title extracted from title tag.
sfierac49f0e42016-11-08 13:49:5489 },
90 kYouTube{
91 {kTitle, "YouTube"},
92 {kUrl, "https://m.youtube.com/"},
93 {kLargeIconUrl, "https://s.ytimg.com/apple-touch-icon.png"},
Friedrich Horschigefec0812017-09-28 18:50:1794 {kTitleSource, "1"}, // Title extracted from manifest.
sfierac49f0e42016-11-08 13:49:5495 },
96 kChromium{
97 {kTitle, "The Chromium Project"},
98 {kUrl, "https://www.chromium.org/"},
99 {kFaviconUrl, "https://www.chromium.org/favicon.ico"},
Friedrich Horschigefec0812017-09-28 18:50:17100 // No "title_source" (like in v5 or earlier). Defaults to TITLE_TAG.
sfierac49f0e42016-11-08 13:49:54101 },
fhorschigf84f9f52017-03-16 12:14:06102 prefs_(new sync_preferences::TestingPrefServiceSyncable()),
Mark Pilgrim60a21d3a2018-05-30 15:37:40103 test_shared_loader_factory_(
104 base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
105 &test_url_loader_factory_)) {
fhorschigf84f9f52017-03-16 12:14:06106 PopularSitesImpl::RegisterProfilePrefs(prefs_->registry());
sfieraacc10b62016-11-07 13:33:41107 }
108
109 void SetCountryAndVersion(const std::string& country,
110 const std::string& version) {
fhorschigf84f9f52017-03-16 12:14:06111 prefs_->SetString(prefs::kPopularSitesOverrideCountry, country);
112 prefs_->SetString(prefs::kPopularSitesOverrideVersion, version);
sfieraacc10b62016-11-07 13:33:41113 }
114
Friedrich Horschigf48183742017-08-08 16:53:13115 std::unique_ptr<base::ListValue> CreateListFromTestSites(
116 const TestPopularSiteVector& sites) {
Gyuyoung Kimcb7965e2018-01-25 00:39:01117 auto sites_value = std::make_unique<base::ListValue>();
sfieraacc10b62016-11-07 13:33:41118 for (const TestPopularSite& site : sites) {
Gyuyoung Kimcb7965e2018-01-25 00:39:01119 auto site_value = std::make_unique<base::DictionaryValue>();
Nico Weber6dcde5b2020-02-22 20:49:20120 for (const std::pair<const std::string, std::string>& kv : site) {
Friedrich Horschigefec0812017-09-28 18:50:17121 if (kv.first == kTitleSource) {
122 int source;
123 bool convert_success = base::StringToInt(kv.second, &source);
124 DCHECK(convert_success);
125 site_value->SetInteger(kv.first, source);
126 continue;
127 }
sfieraacc10b62016-11-07 13:33:41128 site_value->SetString(kv.first, kv.second);
129 }
Friedrich Horschigf48183742017-08-08 16:53:13130 sites_value->Append(std::move(site_value));
131 }
132 return sites_value;
133 }
134
135 void RespondWithV5JSON(const std::string& url,
136 const TestPopularSiteVector& sites) {
137 std::string sites_string;
138 base::JSONWriter::Write(*CreateListFromTestSites(sites), &sites_string);
Mark Pilgrim60a21d3a2018-05-30 15:37:40139 test_url_loader_factory_.AddResponse(url, sites_string);
Friedrich Horschigf48183742017-08-08 16:53:13140 }
141
142 void RespondWithV6JSON(const std::string& url,
143 const TestPopularSectionVector& sections) {
144 base::ListValue sections_value;
145 for (const TestPopularSection& section : sections) {
Gyuyoung Kimcb7965e2018-01-25 00:39:01146 auto section_value = std::make_unique<base::DictionaryValue>();
Friedrich Horschigf48183742017-08-08 16:53:13147 section_value->SetInteger(kSection, static_cast<int>(section.first));
148 section_value->SetList(kSites, CreateListFromTestSites(section.second));
149 sections_value.Append(std::move(section_value));
sfieraacc10b62016-11-07 13:33:41150 }
151 std::string sites_string;
Friedrich Horschigf48183742017-08-08 16:53:13152 base::JSONWriter::Write(sections_value, &sites_string);
Mark Pilgrim60a21d3a2018-05-30 15:37:40153 test_url_loader_factory_.AddResponse(url, sites_string);
sfieraacc10b62016-11-07 13:33:41154 }
155
sfierac49f0e42016-11-08 13:49:54156 void RespondWithData(const std::string& url, const std::string& data) {
Mark Pilgrim60a21d3a2018-05-30 15:37:40157 test_url_loader_factory_.AddResponse(url, data);
sfierac49f0e42016-11-08 13:49:54158 }
159
sfieraacc10b62016-11-07 13:33:41160 void RespondWith404(const std::string& url) {
Mark Pilgrim60a21d3a2018-05-30 15:37:40161 test_url_loader_factory_.AddResponse(url, "", net::HTTP_NOT_FOUND);
sfieraacc10b62016-11-07 13:33:41162 }
163
fhorschigf84f9f52017-03-16 12:14:06164 void ReregisterProfilePrefs() {
Gyuyoung Kimcb7965e2018-01-25 00:39:01165 prefs_ = std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
fhorschigf84f9f52017-03-16 12:14:06166 PopularSitesImpl::RegisterProfilePrefs(prefs_->registry());
167 }
168
mastizfd2c7ab2017-01-27 19:35:00169 // Returns an optional bool representing whether the completion callback was
170 // called at all, and if yes which was the returned bool value.
Anton Bikineev1156b5f2021-05-15 22:35:36171 absl::optional<bool> FetchPopularSites(bool force_download,
mastizfd2c7ab2017-01-27 19:35:00172 PopularSites::SitesVector* sites) {
Friedrich Horschigf48183742017-08-08 16:53:13173 std::map<SectionType, PopularSites::SitesVector> sections;
Anton Bikineev1156b5f2021-05-15 22:35:36174 absl::optional<bool> save_success =
Friedrich Horschigf48183742017-08-08 16:53:13175 FetchAllSections(force_download, &sections);
176 *sites = sections.at(SectionType::PERSONALIZED);
177 return save_success;
178 }
179
180 // Returns an optional bool representing whether the completion callback was
181 // called at all, and if yes which was the returned bool value.
Anton Bikineev1156b5f2021-05-15 22:35:36182 absl::optional<bool> FetchAllSections(
Friedrich Horschigf48183742017-08-08 16:53:13183 bool force_download,
184 std::map<SectionType, PopularSites::SitesVector>* sections) {
Mark Pilgrim60a21d3a2018-05-30 15:37:40185 std::unique_ptr<PopularSites> popular_sites = CreatePopularSites();
sfieraacc10b62016-11-07 13:33:41186
187 base::RunLoop loop;
Anton Bikineev1156b5f2021-05-15 22:35:36188 absl::optional<bool> save_success;
fhorschig7d16fb22017-02-15 08:28:08189 if (popular_sites->MaybeStartFetch(
Ken Rockotc24303b2019-12-20 17:59:32190 force_download, base::BindOnce(
Anton Bikineev1156b5f2021-05-15 22:35:36191 [](absl::optional<bool>* save_success,
mastizfd2c7ab2017-01-27 19:35:00192 base::RunLoop* loop, bool success) {
193 save_success->emplace(success);
194 loop->Quit();
195 },
196 &save_success, &loop))) {
197 loop.Run();
198 }
Friedrich Horschigf48183742017-08-08 16:53:13199 *sections = popular_sites->sections();
sfieraacc10b62016-11-07 13:33:41200 return save_success;
201 }
202
Mark Pilgrim60a21d3a2018-05-30 15:37:40203 std::unique_ptr<PopularSites> CreatePopularSites() {
Ken Rockot67226642019-10-31 16:40:53204 return std::make_unique<PopularSitesImpl>(prefs_.get(),
205 /*template_url_service=*/nullptr,
206 /*variations_service=*/nullptr,
207 test_shared_loader_factory_);
fhorschig7d16fb22017-02-15 08:28:08208 }
209
sfierac49f0e42016-11-08 13:49:54210 const TestPopularSite kWikipedia;
211 const TestPopularSite kYouTube;
212 const TestPopularSite kChromium;
213
Gabriel Charette614b4052019-09-07 14:29:18214 base::test::SingleThreadTaskEnvironment task_environment_{
215 base::test::SingleThreadTaskEnvironment::MainThreadType::UI};
Ken Rockot67226642019-10-31 16:40:53216 data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
fhorschigf84f9f52017-03-16 12:14:06217 std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> prefs_;
Mark Pilgrim60a21d3a2018-05-30 15:37:40218 network::TestURLLoaderFactory test_url_loader_factory_;
219 scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
sfieraacc10b62016-11-07 13:33:41220};
221
fhorschigfed34be2017-03-02 23:16:09222TEST_F(PopularSitesTest, ContainsDefaultTilesRightAfterConstruction) {
Mark Pilgrim60a21d3a2018-05-30 15:37:40223 auto popular_sites = CreatePopularSites();
Friedrich Horschigf48183742017-08-08 16:53:13224 EXPECT_THAT(
225 popular_sites->sections(),
226 ElementsAre(Pair(SectionType::PERSONALIZED,
227 SizeIs(GetNumberOfDefaultPopularSitesForPlatform()))));
fhorschigfed34be2017-03-02 23:16:09228}
229
fhorschigf84f9f52017-03-16 12:14:06230TEST_F(PopularSitesTest, IsEmptyOnConstructionIfDisabledByTrial) {
231 base::test::ScopedFeatureList override_features;
232 override_features.InitAndDisableFeature(kPopularSitesBakedInContentFeature);
233 ReregisterProfilePrefs();
234
Mark Pilgrim60a21d3a2018-05-30 15:37:40235 auto popular_sites = CreatePopularSites();
fhorschigf84f9f52017-03-16 12:14:06236
Friedrich Horschigf48183742017-08-08 16:53:13237 EXPECT_THAT(popular_sites->sections(),
238 ElementsAre(Pair(SectionType::PERSONALIZED, IsEmpty())));
fhorschigf84f9f52017-03-16 12:14:06239}
240
241TEST_F(PopularSitesTest, ShouldSucceedFetching) {
Friedrich Horschigf48183742017-08-08 16:53:13242 SetCountryAndVersion("ZZ", "5");
243 RespondWithV5JSON(
244 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
sfierac49f0e42016-11-08 13:49:54245 {kWikipedia});
sfieraacc10b62016-11-07 13:33:41246
mastiz78efbde2016-12-14 17:07:07247 PopularSites::SitesVector sites;
Friedrich Horschigf48183742017-08-08 16:53:13248 EXPECT_THAT(FetchPopularSites(/*force_download=*/true, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36249 Eq(absl::optional<bool>(true)));
sfieraacc10b62016-11-07 13:33:41250
251 ASSERT_THAT(sites.size(), Eq(1u));
252 EXPECT_THAT(sites[0].title, Str16Eq("Wikipedia, fhta Ph'nglui mglw'nafh"));
253 EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
254 EXPECT_THAT(sites[0].large_icon_url,
255 URLEq("https://zz.m.wikipedia.org/wikipedia.png"));
256 EXPECT_THAT(sites[0].favicon_url, URLEq(""));
Friedrich Horschigefec0812017-09-28 18:50:17257 EXPECT_THAT(sites[0].title_source, Eq(TileTitleSource::TITLE_TAG));
sfieraacc10b62016-11-07 13:33:41258}
259
260TEST_F(PopularSitesTest, Fallback) {
Friedrich Horschigf48183742017-08-08 16:53:13261 SetCountryAndVersion("ZZ", "5");
sfieraacc10b62016-11-07 13:33:41262 RespondWith404(
Friedrich Horschigf48183742017-08-08 16:53:13263 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
264 RespondWithV5JSON(
sfieraacc10b62016-11-07 13:33:41265 "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
sfierac49f0e42016-11-08 13:49:54266 {kYouTube, kChromium});
sfieraacc10b62016-11-07 13:33:41267
mastiz78efbde2016-12-14 17:07:07268 PopularSites::SitesVector sites;
mastizfd2c7ab2017-01-27 19:35:00269 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36270 Eq(absl::optional<bool>(true)));
sfieraacc10b62016-11-07 13:33:41271
272 ASSERT_THAT(sites.size(), Eq(2u));
273 EXPECT_THAT(sites[0].title, Str16Eq("YouTube"));
274 EXPECT_THAT(sites[0].url, URLEq("https://m.youtube.com/"));
275 EXPECT_THAT(sites[0].large_icon_url,
276 URLEq("https://s.ytimg.com/apple-touch-icon.png"));
277 EXPECT_THAT(sites[0].favicon_url, URLEq(""));
Friedrich Horschigefec0812017-09-28 18:50:17278 EXPECT_THAT(sites[0].title_source, Eq(TileTitleSource::MANIFEST));
sfieraacc10b62016-11-07 13:33:41279 EXPECT_THAT(sites[1].title, Str16Eq("The Chromium Project"));
280 EXPECT_THAT(sites[1].url, URLEq("https://www.chromium.org/"));
281 EXPECT_THAT(sites[1].large_icon_url, URLEq(""));
282 EXPECT_THAT(sites[1].favicon_url,
283 URLEq("https://www.chromium.org/favicon.ico"));
Friedrich Horschigefec0812017-09-28 18:50:17284 // Fall back to TITLE_TAG if there is no "title_source". Version 5 or before
285 // haven't had this property and get titles from <title> tags exclusively.
286 EXPECT_THAT(sites[1].title_source, Eq(TileTitleSource::TITLE_TAG));
sfieraacc10b62016-11-07 13:33:41287}
288
fhorschig7d16fb22017-02-15 08:28:08289TEST_F(PopularSitesTest, PopulatesWithDefaultResoucesOnFailure) {
Friedrich Horschigf48183742017-08-08 16:53:13290 SetCountryAndVersion("ZZ", "5");
sfieraacc10b62016-11-07 13:33:41291 RespondWith404(
Friedrich Horschigf48183742017-08-08 16:53:13292 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
sfieraacc10b62016-11-07 13:33:41293 RespondWith404(
294 "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
295
mastiz78efbde2016-12-14 17:07:07296 PopularSites::SitesVector sites;
mastizfd2c7ab2017-01-27 19:35:00297 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36298 Eq(absl::optional<bool>(false)));
fhorschig7d16fb22017-02-15 08:28:08299 EXPECT_THAT(sites.size(), Eq(GetNumberOfDefaultPopularSitesForPlatform()));
300}
301
Friedrich Horschig7706ef62017-08-25 08:20:00302#if defined(OS_ANDROID) || defined(OS_IOS)
fhorschigfed34be2017-03-02 23:16:09303TEST_F(PopularSitesTest, AddsIconResourcesToDefaultPages) {
Mark Pilgrim60a21d3a2018-05-30 15:37:40304 std::unique_ptr<PopularSites> popular_sites = CreatePopularSites();
fhorschigfed34be2017-03-02 23:16:09305
Friedrich Horschigf48183742017-08-08 16:53:13306 const PopularSites::SitesVector& sites =
307 popular_sites->sections().at(SectionType::PERSONALIZED);
308 ASSERT_FALSE(sites.empty());
309 for (const auto& site : sites) {
Friedrich Horschig7706ef62017-08-25 08:20:00310 EXPECT_TRUE(site.baked_in);
Nico Weber356b3042019-08-23 15:30:41311#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
fhorschigfed34be2017-03-02 23:16:09312 EXPECT_THAT(site.default_icon_resource, Gt(0));
fhorschigfed34be2017-03-02 23:16:09313#endif
Friedrich Horschig7706ef62017-08-25 08:20:00314 }
fhorschigfed34be2017-03-02 23:16:09315}
Friedrich Horschig7706ef62017-08-25 08:20:00316#endif
fhorschigfed34be2017-03-02 23:16:09317
fhorschig7d16fb22017-02-15 08:28:08318TEST_F(PopularSitesTest, ProvidesDefaultSitesUntilCallbackReturns) {
Friedrich Horschigf48183742017-08-08 16:53:13319 SetCountryAndVersion("ZZ", "5");
320 RespondWithV5JSON(
321 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
fhorschig7d16fb22017-02-15 08:28:08322 {kWikipedia});
Mark Pilgrim60a21d3a2018-05-30 15:37:40323 std::unique_ptr<PopularSites> popular_sites = CreatePopularSites();
fhorschig7d16fb22017-02-15 08:28:08324
325 base::RunLoop loop;
Anton Bikineev1156b5f2021-05-15 22:35:36326 absl::optional<bool> save_success = false;
fhorschig7d16fb22017-02-15 08:28:08327
328 bool callback_was_scheduled = popular_sites->MaybeStartFetch(
Ken Rockotc24303b2019-12-20 17:59:32329 /*force_download=*/true, base::BindOnce(
Anton Bikineev1156b5f2021-05-15 22:35:36330 [](absl::optional<bool>* save_success,
fhorschig7d16fb22017-02-15 08:28:08331 base::RunLoop* loop, bool success) {
332 save_success->emplace(success);
333 loop->Quit();
334 },
335 &save_success, &loop));
336
337 // Assert that callback was scheduled so we can wait for its completion.
338 ASSERT_TRUE(callback_was_scheduled);
339 // There should be 8 default sites as nothing was fetched yet.
Friedrich Horschigf48183742017-08-08 16:53:13340 EXPECT_THAT(popular_sites->sections().at(SectionType::PERSONALIZED).size(),
fhorschig7d16fb22017-02-15 08:28:08341 Eq(GetNumberOfDefaultPopularSitesForPlatform()));
342
343 loop.Run(); // Wait for the fetch to finish and the callback to return.
344
345 EXPECT_TRUE(save_success.value());
346 // The 1 fetched site should replace the default sites.
Friedrich Horschigf48183742017-08-08 16:53:13347 EXPECT_THAT(popular_sites->sections(),
348 ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(1ul))));
sfierac49f0e42016-11-08 13:49:54349}
350
mastiz5c82ff82017-01-23 17:00:43351TEST_F(PopularSitesTest, UsesCachedJson) {
Friedrich Horschigf48183742017-08-08 16:53:13352 SetCountryAndVersion("ZZ", "5");
353 RespondWithV5JSON(
354 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
sfierac49f0e42016-11-08 13:49:54355 {kWikipedia});
356
357 // First request succeeds and gets cached.
mastiz78efbde2016-12-14 17:07:07358 PopularSites::SitesVector sites;
mastizfd2c7ab2017-01-27 19:35:00359 ASSERT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36360 Eq(absl::optional<bool>(true)));
sfierac49f0e42016-11-08 13:49:54361
362 // File disappears from server, but we don't need it because it's cached.
363 RespondWith404(
Friedrich Horschigf48183742017-08-08 16:53:13364 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
mastizfd2c7ab2017-01-27 19:35:00365 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36366 Eq(absl::nullopt));
sfierac49f0e42016-11-08 13:49:54367 EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
368}
369
370TEST_F(PopularSitesTest, CachesEmptyFile) {
Friedrich Horschigf48183742017-08-08 16:53:13371 SetCountryAndVersion("ZZ", "5");
sfierac49f0e42016-11-08 13:49:54372 RespondWithData(
Friedrich Horschigf48183742017-08-08 16:53:13373 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json", "[]");
374 RespondWithV5JSON(
sfierac49f0e42016-11-08 13:49:54375 "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
376 {kWikipedia});
377
378 // First request succeeds and caches empty suggestions list (no fallback).
mastiz78efbde2016-12-14 17:07:07379 PopularSites::SitesVector sites;
mastizfd2c7ab2017-01-27 19:35:00380 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36381 Eq(absl::optional<bool>(true)));
sfierac49f0e42016-11-08 13:49:54382 EXPECT_THAT(sites, IsEmpty());
383
384 // File appears on server, but we continue to use our cached empty file.
Friedrich Horschigf48183742017-08-08 16:53:13385 RespondWithV5JSON(
386 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
sfierac49f0e42016-11-08 13:49:54387 {kWikipedia});
mastizfd2c7ab2017-01-27 19:35:00388 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36389 Eq(absl::nullopt));
sfierac49f0e42016-11-08 13:49:54390 EXPECT_THAT(sites, IsEmpty());
391}
392
393TEST_F(PopularSitesTest, DoesntUseCachedFileIfDownloadForced) {
Friedrich Horschigf48183742017-08-08 16:53:13394 SetCountryAndVersion("ZZ", "5");
395 RespondWithV5JSON(
396 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
sfierac49f0e42016-11-08 13:49:54397 {kWikipedia});
398
399 // First request succeeds and gets cached.
mastiz78efbde2016-12-14 17:07:07400 PopularSites::SitesVector sites;
mastizfd2c7ab2017-01-27 19:35:00401 EXPECT_THAT(FetchPopularSites(/*force_download=*/true, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36402 Eq(absl::optional<bool>(true)));
sfierac49f0e42016-11-08 13:49:54403 EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
404
405 // File disappears from server. Download is forced, so we get the new file.
Friedrich Horschigf48183742017-08-08 16:53:13406 RespondWithV5JSON(
407 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
sfierac49f0e42016-11-08 13:49:54408 {kChromium});
mastizfd2c7ab2017-01-27 19:35:00409 EXPECT_THAT(FetchPopularSites(/*force_download=*/true, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36410 Eq(absl::optional<bool>(true)));
sfierac49f0e42016-11-08 13:49:54411 EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
412}
413
Friedrich Horschigf48183742017-08-08 16:53:13414TEST_F(PopularSitesTest, DoesntUseCacheWithDeprecatedVersion) {
415 SetCountryAndVersion("ZZ", "5");
416 RespondWithV5JSON(
417 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
sfierac49f0e42016-11-08 13:49:54418 {kWikipedia});
Friedrich Horschigf48183742017-08-08 16:53:13419
420 // First request succeeds and gets cached.
421 PopularSites::SitesVector sites;
422 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36423 Eq(absl::optional<bool>(true)));
Friedrich Horschigf48183742017-08-08 16:53:13424 EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
425 EXPECT_THAT(prefs_->GetInteger(prefs::kPopularSitesVersionPref), Eq(5));
426
427 // The client is updated to use V6. Drop old data and refetch.
428 SetCountryAndVersion("ZZ", "6");
429 RespondWithV6JSON(
430 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
431 {{SectionType::PERSONALIZED, {kChromium}}});
432 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36433 Eq(absl::optional<bool>(true)));
Friedrich Horschigf48183742017-08-08 16:53:13434 EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
435 EXPECT_THAT(prefs_->GetInteger(prefs::kPopularSitesVersionPref), Eq(6));
436}
437
Friedrich Horschigb77dc442017-09-11 13:06:30438TEST_F(PopularSitesTest, FallsBackToDefaultParserIfVersionContainsNoNumber) {
439 SetCountryAndVersion("ZZ", "staging");
440 // The version is used in the URL, as planned when setting it.
441 RespondWithV5JSON(
442 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_staging.json",
443 {kChromium});
444 PopularSites::SitesVector sites;
445 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36446 Eq(absl::optional<bool>(true)));
Friedrich Horschigb77dc442017-09-11 13:06:30447 ASSERT_THAT(sites.size(), Eq(1u));
448 EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
449}
450
Friedrich Horschigf48183742017-08-08 16:53:13451TEST_F(PopularSitesTest, RefetchesAfterCountryMoved) {
452 RespondWithV5JSON(
453 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
454 {kWikipedia});
455 RespondWithV5JSON(
456 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZX_5.json",
sfierac49f0e42016-11-08 13:49:54457 {kChromium});
458
mastiz78efbde2016-12-14 17:07:07459 PopularSites::SitesVector sites;
sfierac49f0e42016-11-08 13:49:54460
461 // First request (in ZZ) saves Wikipedia.
Friedrich Horschigf48183742017-08-08 16:53:13462 SetCountryAndVersion("ZZ", "5");
mastizfd2c7ab2017-01-27 19:35:00463 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36464 Eq(absl::optional<bool>(true)));
sfierac49f0e42016-11-08 13:49:54465 EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
466
467 // Second request (now in ZX) saves Chromium.
Friedrich Horschigf48183742017-08-08 16:53:13468 SetCountryAndVersion("ZX", "5");
mastizfd2c7ab2017-01-27 19:35:00469 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36470 absl::optional<bool>(true));
sfierac49f0e42016-11-08 13:49:54471 EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
472}
473
474TEST_F(PopularSitesTest, DoesntCacheInvalidFile) {
Friedrich Horschigf48183742017-08-08 16:53:13475 SetCountryAndVersion("ZZ", "5");
sfierac49f0e42016-11-08 13:49:54476 RespondWithData(
Friedrich Horschigf48183742017-08-08 16:53:13477 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
sfierac49f0e42016-11-08 13:49:54478 "ceci n'est pas un json");
479 RespondWith404(
480 "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
481
482 // First request falls back and gets nothing there either.
mastiz78efbde2016-12-14 17:07:07483 PopularSites::SitesVector sites;
mastizfd2c7ab2017-01-27 19:35:00484 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36485 Eq(absl::optional<bool>(false)));
sfierac49f0e42016-11-08 13:49:54486
487 // Second request refetches ZZ_9, which now has data.
Friedrich Horschigf48183742017-08-08 16:53:13488 RespondWithV5JSON(
489 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
sfierac49f0e42016-11-08 13:49:54490 {kChromium});
mastizfd2c7ab2017-01-27 19:35:00491 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36492 Eq(absl::optional<bool>(true)));
sfierac49f0e42016-11-08 13:49:54493 ASSERT_THAT(sites.size(), Eq(1u));
494 EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
495}
496
497TEST_F(PopularSitesTest, RefetchesAfterFallback) {
Friedrich Horschigf48183742017-08-08 16:53:13498 SetCountryAndVersion("ZZ", "5");
sfierac49f0e42016-11-08 13:49:54499 RespondWith404(
Friedrich Horschigf48183742017-08-08 16:53:13500 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
501 RespondWithV5JSON(
sfierac49f0e42016-11-08 13:49:54502 "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
503 {kWikipedia});
504
505 // First request falls back.
mastiz78efbde2016-12-14 17:07:07506 PopularSites::SitesVector sites;
mastizfd2c7ab2017-01-27 19:35:00507 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36508 Eq(absl::optional<bool>(true)));
sfierac49f0e42016-11-08 13:49:54509 ASSERT_THAT(sites.size(), Eq(1u));
510 EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
511
512 // Second request refetches ZZ_9, which now has data.
Friedrich Horschigf48183742017-08-08 16:53:13513 RespondWithV5JSON(
514 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
sfierac49f0e42016-11-08 13:49:54515 {kChromium});
mastizfd2c7ab2017-01-27 19:35:00516 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36517 Eq(absl::optional<bool>(true)));
sfierac49f0e42016-11-08 13:49:54518 ASSERT_THAT(sites.size(), Eq(1u));
519 EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
sfieraacc10b62016-11-07 13:33:41520}
521
mastiz7df710a2017-04-26 11:09:10522TEST_F(PopularSitesTest, ShouldOverrideDirectory) {
Friedrich Horschigf48183742017-08-08 16:53:13523 SetCountryAndVersion("ZZ", "5");
mastiz7df710a2017-04-26 11:09:10524 prefs_->SetString(prefs::kPopularSitesOverrideDirectory, "foo/bar/");
Friedrich Horschigf48183742017-08-08 16:53:13525 RespondWithV5JSON("https://www.gstatic.com/foo/bar/suggested_sites_ZZ_5.json",
526 {kWikipedia});
mastiz7df710a2017-04-26 11:09:10527
528 PopularSites::SitesVector sites;
529 EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
Anton Bikineev1156b5f2021-05-15 22:35:36530 Eq(absl::optional<bool>(true)));
mastiz7df710a2017-04-26 11:09:10531
532 EXPECT_THAT(sites.size(), Eq(1u));
533}
534
Natalie Chouinard51f0eb2092019-05-07 18:38:14535TEST_F(PopularSitesTest, DoesNotFetchExplorationSites) {
Friedrich Horschigf48183742017-08-08 16:53:13536 SetCountryAndVersion("ZZ", "6");
537 RespondWithV6JSON(
538 "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
539 {{SectionType::PERSONALIZED, {kChromium}},
540 {SectionType::NEWS, {kYouTube}}});
541
542 std::map<SectionType, PopularSites::SitesVector> sections;
543 EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
Anton Bikineev1156b5f2021-05-15 22:35:36544 Eq(absl::optional<bool>(true)));
Friedrich Horschigf48183742017-08-08 16:53:13545
546 // The fetched news section should not be propagated without enabled feature.
547 EXPECT_THAT(sections, Not(Contains(Pair(SectionType::NEWS, _))));
548}
549
sfieraacc10b62016-11-07 13:33:41550} // namespace
551} // namespace ntp_tiles