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

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

Issue 2379113002: Extended the ProtoDatabase to provide LoadKeys() functionality. (Closed)
Patch Set: Garbage Collect orphaned images on service start-up. Created 4 years, 2 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
« no previous file with comments | « components/ntp_snippets/remote/ntp_snippets_service.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/ntp_snippets/remote/ntp_snippets_service.h" 5 #include "components/ntp_snippets/remote/ntp_snippets_service.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 // fail to parse as snippets. 218 // fail to parse as snippets.
219 size_t pos = json_str.find("\"fullPageUrl\""); 219 size_t pos = json_str.find("\"fullPageUrl\"");
220 if (pos == std::string::npos) { 220 if (pos == std::string::npos) {
221 NOTREACHED(); 221 NOTREACHED();
222 return std::string(); 222 return std::string();
223 } 223 }
224 json_str[pos + 1] = 'x'; 224 json_str[pos + 1] = 'x';
225 return json_str; 225 return json_str;
226 } 226 }
227 227
228 using ServeImageCallback = base::Callback<void(
229 const std::string&,
230 base::Callback<void(const std::string&, const gfx::Image&)>)>;
231
228 void ServeOneByOneImage( 232 void ServeOneByOneImage(
233 image_fetcher::ImageFetcherDelegate* notify,
229 const std::string& id, 234 const std::string& id,
230 base::Callback<void(const std::string&, const gfx::Image&)> callback) { 235 base::Callback<void(const std::string&, const gfx::Image&)> callback) {
231 base::ThreadTaskRunnerHandle::Get()->PostTask( 236 base::ThreadTaskRunnerHandle::Get()->PostTask(
232 FROM_HERE, base::Bind(callback, id, gfx::test::CreateImage(1, 1))); 237 FROM_HERE, base::Bind(callback, id, gfx::test::CreateImage(1, 1)));
238 notify->OnImageDataFetched(id, "1-by-1-image-data");
239 }
240
241 void ServeEmptyImage(
242 const std::string& id,
243 base::Callback<void(const std::string&, const gfx::Image&)> callback) {
244 base::ThreadTaskRunnerHandle::Get()->PostTask(
245 FROM_HERE, base::Bind(callback, id, gfx::Image()));
233 } 246 }
234 247
235 void ParseJson( 248 void ParseJson(
236 const std::string& json, 249 const std::string& json,
237 const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback, 250 const ntp_snippets::NTPSnippetsFetcher::SuccessCallback& success_callback,
238 const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) { 251 const ntp_snippets::NTPSnippetsFetcher::ErrorCallback& error_callback) {
239 base::JSONReader json_reader; 252 base::JSONReader json_reader;
240 std::unique_ptr<base::Value> value = json_reader.ReadToValue(json); 253 std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
241 if (value) { 254 if (value) {
242 success_callback.Run(std::move(value)); 255 success_callback.Run(std::move(value));
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 344
332 private: 345 private:
333 base::WaitableEvent loaded_; 346 base::WaitableEvent loaded_;
334 std::map<Category, CategoryStatus, Category::CompareByID> statuses_; 347 std::map<Category, CategoryStatus, Category::CompareByID> statuses_;
335 std::map<Category, std::vector<ContentSuggestion>, Category::CompareByID> 348 std::map<Category, std::vector<ContentSuggestion>, Category::CompareByID>
336 suggestions_; 349 suggestions_;
337 350
338 DISALLOW_COPY_AND_ASSIGN(FakeContentSuggestionsProviderObserver); 351 DISALLOW_COPY_AND_ASSIGN(FakeContentSuggestionsProviderObserver);
339 }; 352 };
340 353
354 class FakeImageDecoder : public image_fetcher::ImageDecoder {
355 public:
356 FakeImageDecoder() {}
357 ~FakeImageDecoder() override {}
358 void DecodeImage(
359 const std::string& image_data,
360 const image_fetcher::ImageDecodedCallback& callback) override {
361 callback.Run(decoded_image_);
362 }
363
364 void SetDecodedImage(const gfx::Image& image) { decoded_image_ = image; }
365
366 private:
367 gfx::Image decoded_image_;
368 };
369
341 } // namespace 370 } // namespace
342 371
343 class NTPSnippetsServiceTest : public ::testing::Test { 372 class NTPSnippetsServiceTest : public ::testing::Test {
344 public: 373 public:
345 NTPSnippetsServiceTest() 374 NTPSnippetsServiceTest()
346 : params_manager_(ntp_snippets::kStudyName, 375 : params_manager_(ntp_snippets::kStudyName,
347 {{"content_suggestions_backend", 376 {{"content_suggestions_backend",
348 kTestContentSuggestionsServerEndpoint}}), 377 kTestContentSuggestionsServerEndpoint}}),
349 fake_url_fetcher_factory_( 378 fake_url_fetcher_factory_(
350 /*default_factory=*/&failing_url_fetcher_factory_), 379 /*default_factory=*/&failing_url_fetcher_factory_),
351 test_url_(kTestContentSuggestionsServerWithAPIKey), 380 test_url_(kTestContentSuggestionsServerWithAPIKey),
352 image_fetcher_(nullptr) { 381 image_fetcher_(nullptr),
382 image_decoder_(nullptr) {
353 NTPSnippetsService::RegisterProfilePrefs(utils_.pref_service()->registry()); 383 NTPSnippetsService::RegisterProfilePrefs(utils_.pref_service()->registry());
354 RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry()); 384 RequestThrottler::RegisterProfilePrefs(utils_.pref_service()->registry());
355 385
356 // Since no SuggestionsService is injected in tests, we need to force the 386 // Since no SuggestionsService is injected in tests, we need to force the
357 // service to fetch from all hosts. 387 // service to fetch from all hosts.
358 base::CommandLine::ForCurrentProcess()->AppendSwitch( 388 base::CommandLine::ForCurrentProcess()->AppendSwitch(
359 switches::kDontRestrict); 389 switches::kDontRestrict);
360 EXPECT_TRUE(database_dir_.CreateUniqueTempDir()); 390 EXPECT_TRUE(database_dir_.CreateUniqueTempDir());
361 } 391 }
362 392
(...skipping 23 matching lines...) Expand all
386 base::MakeUnique<NTPSnippetsFetcher>( 416 base::MakeUnique<NTPSnippetsFetcher>(
387 utils_.fake_signin_manager(), fake_token_service_.get(), 417 utils_.fake_signin_manager(), fake_token_service_.get(),
388 std::move(request_context_getter), utils_.pref_service(), 418 std::move(request_context_getter), utils_.pref_service(),
389 &category_factory_, base::Bind(&ParseJson), kAPIKey); 419 &category_factory_, base::Bind(&ParseJson), kAPIKey);
390 420
391 utils_.fake_signin_manager()->SignIn("foo@bar.com"); 421 utils_.fake_signin_manager()->SignIn("foo@bar.com");
392 snippets_fetcher->SetPersonalizationForTesting( 422 snippets_fetcher->SetPersonalizationForTesting(
393 NTPSnippetsFetcher::Personalization::kNonPersonal); 423 NTPSnippetsFetcher::Personalization::kNonPersonal);
394 424
395 auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>(); 425 auto image_fetcher = base::MakeUnique<NiceMock<MockImageFetcher>>();
426
396 image_fetcher_ = image_fetcher.get(); 427 image_fetcher_ = image_fetcher.get();
428 EXPECT_CALL(*image_fetcher, SetImageFetcherDelegate(_));
429 auto image_decoder = base::MakeUnique<FakeImageDecoder>();
430 image_decoder_ = image_decoder.get();
397 EXPECT_FALSE(observer_); 431 EXPECT_FALSE(observer_);
398 observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>(); 432 observer_ = base::MakeUnique<FakeContentSuggestionsProviderObserver>();
399 return base::MakeUnique<NTPSnippetsService>( 433 return base::MakeUnique<NTPSnippetsService>(
400 observer_.get(), &category_factory_, utils_.pref_service(), nullptr, 434 observer_.get(), &category_factory_, utils_.pref_service(), nullptr,
401 "fr", &scheduler_, std::move(snippets_fetcher), 435 "fr", &scheduler_, std::move(snippets_fetcher),
402 std::move(image_fetcher), /*image_decoder=*/nullptr, 436 std::move(image_fetcher), std::move(image_decoder),
403 base::MakeUnique<NTPSnippetsDatabase>(database_dir_.GetPath(), 437 base::MakeUnique<NTPSnippetsDatabase>(database_dir_.GetPath(),
404 task_runner), 438 task_runner),
405 base::MakeUnique<NTPSnippetsStatusService>(utils_.fake_signin_manager(), 439 base::MakeUnique<NTPSnippetsStatusService>(utils_.fake_signin_manager(),
406 utils_.pref_service())); 440 utils_.pref_service()));
407 } 441 }
408 442
409 void WaitForSnippetsServiceInitialization(bool set_empty_response = true) { 443 void WaitForSnippetsServiceInitialization(bool set_empty_response = true) {
410 EXPECT_TRUE(observer_); 444 EXPECT_TRUE(observer_);
411 EXPECT_FALSE(observer_->Loaded()); 445 EXPECT_FALSE(observer_->Loaded());
412 446
(...skipping 24 matching lines...) Expand all
437 return ContentSuggestion::ID(other_category(), id_within_category); 471 return ContentSuggestion::ID(other_category(), id_within_category);
438 } 472 }
439 473
440 Category other_category() { return category_factory_.FromRemoteCategory(2); } 474 Category other_category() { return category_factory_.FromRemoteCategory(2); }
441 475
442 protected: 476 protected:
443 const GURL& test_url() { return test_url_; } 477 const GURL& test_url() { return test_url_; }
444 FakeContentSuggestionsProviderObserver& observer() { return *observer_; } 478 FakeContentSuggestionsProviderObserver& observer() { return *observer_; }
445 MockScheduler& mock_scheduler() { return scheduler_; } 479 MockScheduler& mock_scheduler() { return scheduler_; }
446 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; } 480 NiceMock<MockImageFetcher>* image_fetcher() { return image_fetcher_; }
481 FakeImageDecoder* image_decoder() { return image_decoder_; }
447 482
448 // Provide the json to be returned by the fake fetcher. 483 // Provide the json to be returned by the fake fetcher.
449 void SetUpFetchResponse(const std::string& json) { 484 void SetUpFetchResponse(const std::string& json) {
450 fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK, 485 fake_url_fetcher_factory_.SetFakeResponse(test_url_, json, net::HTTP_OK,
451 net::URLRequestStatus::SUCCESS); 486 net::URLRequestStatus::SUCCESS);
452 } 487 }
453 488
454 void LoadFromJSONString(NTPSnippetsService* service, 489 void LoadFromJSONString(NTPSnippetsService* service,
455 const std::string& json) { 490 const std::string& json) {
456 SetUpFetchResponse(json); 491 SetUpFetchResponse(json);
457 service->FetchSnippets(true); 492 service->FetchSnippets(true);
458 base::RunLoop().RunUntilIdle(); 493 base::RunLoop().RunUntilIdle();
459 } 494 }
460 495
461 private: 496 private:
462 variations::testing::VariationParamsManager params_manager_; 497 variations::testing::VariationParamsManager params_manager_;
463 test::NTPSnippetsTestUtils utils_; 498 test::NTPSnippetsTestUtils utils_;
464 base::MessageLoop message_loop_; 499 base::MessageLoop message_loop_;
465 FailingFakeURLFetcherFactory failing_url_fetcher_factory_; 500 FailingFakeURLFetcherFactory failing_url_fetcher_factory_;
466 // Instantiation of factory automatically sets itself as URLFetcher's factory. 501 // Instantiation of factory automatically sets itself as URLFetcher's factory.
467 net::FakeURLFetcherFactory fake_url_fetcher_factory_; 502 net::FakeURLFetcherFactory fake_url_fetcher_factory_;
468 const GURL test_url_; 503 const GURL test_url_;
469 std::unique_ptr<OAuth2TokenService> fake_token_service_; 504 std::unique_ptr<OAuth2TokenService> fake_token_service_;
470 NiceMock<MockScheduler> scheduler_; 505 NiceMock<MockScheduler> scheduler_;
471 std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_; 506 std::unique_ptr<FakeContentSuggestionsProviderObserver> observer_;
472 CategoryFactory category_factory_; 507 CategoryFactory category_factory_;
473 NiceMock<MockImageFetcher>* image_fetcher_; 508 NiceMock<MockImageFetcher>* image_fetcher_;
509 FakeImageDecoder* image_decoder_;
474 510
475 base::ScopedTempDir database_dir_; 511 base::ScopedTempDir database_dir_;
476 512
477 DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest); 513 DISALLOW_COPY_AND_ASSIGN(NTPSnippetsServiceTest);
478 }; 514 };
479 515
480 TEST_F(NTPSnippetsServiceTest, ScheduleOnStart) { 516 TEST_F(NTPSnippetsServiceTest, ScheduleOnStart) {
481 // We should get two |Schedule| calls: The first when initialization 517 // We should get two |Schedule| calls: The first when initialization
482 // completes, the second one after the automatic (since the service doesn't 518 // completes, the second one after the automatic (since the service doesn't
483 // have any data yet) fetch finishes. 519 // have any data yet) fetch finishes.
(...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after
1011 EXPECT_FALSE(service->GetSnippetsForTesting(articles_category()).empty()); 1047 EXPECT_FALSE(service->GetSnippetsForTesting(articles_category()).empty());
1012 } 1048 }
1013 1049
1014 TEST_F(NTPSnippetsServiceTest, ImageReturnedWithTheSameId) { 1050 TEST_F(NTPSnippetsServiceTest, ImageReturnedWithTheSameId) {
1015 auto service = MakeSnippetsService(); 1051 auto service = MakeSnippetsService();
1016 1052
1017 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()})); 1053 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
1018 1054
1019 gfx::Image image; 1055 gfx::Image image;
1020 MockFunction<void(const gfx::Image&)> image_fetched; 1056 MockFunction<void(const gfx::Image&)> image_fetched;
1057 ServeImageCallback cb = base::Bind(&ServeOneByOneImage, service.get());
1021 { 1058 {
1022 InSequence s; 1059 InSequence s;
1023 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) 1060 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
1024 .WillOnce(WithArgs<0, 2>(Invoke(ServeOneByOneImage))); 1061 .WillOnce(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
1025 EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image)); 1062 EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image));
1026 } 1063 }
1027 1064
1028 service->FetchSuggestionImage( 1065 service->FetchSuggestionImage(
1029 MakeArticleID(kSnippetUrl), 1066 MakeArticleID(kSnippetUrl),
1030 base::Bind(&MockFunction<void(const gfx::Image&)>::Call, 1067 base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
1031 base::Unretained(&image_fetched))); 1068 base::Unretained(&image_fetched)));
1032 base::RunLoop().RunUntilIdle(); 1069 base::RunLoop().RunUntilIdle();
1033 // Check that the image by ServeOneByOneImage is really served. 1070 // Check that the image by ServeOneByOneImage is really served.
1034 EXPECT_EQ(1, image.Width()); 1071 EXPECT_EQ(1, image.Width());
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1068 base::Time begin = base::Time::FromTimeT(123), 1105 base::Time begin = base::Time::FromTimeT(123),
1069 end = base::Time::FromTimeT(456); 1106 end = base::Time::FromTimeT(456);
1070 base::Callback<bool(const GURL& url)> filter; 1107 base::Callback<bool(const GURL& url)> filter;
1071 service->ClearHistory(begin, end, filter); 1108 service->ClearHistory(begin, end, filter);
1072 1109
1073 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty()); 1110 EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
1074 EXPECT_THAT(service->GetDismissedSnippetsForTesting(articles_category()), 1111 EXPECT_THAT(service->GetDismissedSnippetsForTesting(articles_category()),
1075 IsEmpty()); 1112 IsEmpty());
1076 } 1113 }
1077 1114
1115 namespace {
1116
1117 gfx::Image FetchImage(NTPSnippetsService* service,
1118 const ContentSuggestion::ID& suggestion_id) {
1119 gfx::Image result;
1120 base::RunLoop run_loop;
1121 service->FetchSuggestionImage(suggestion_id,
1122 base::Bind(
1123 [](base::Closure signal, gfx::Image* output,
1124 const gfx::Image& loaded) {
1125 *output = loaded;
1126 signal.Run();
1127 LOG(INFO) << "signalling loop out";
1128 },
1129 run_loop.QuitClosure(), &result));
1130 run_loop.Run();
1131 return result;
1132 }
1133
1134 } // namespace
1135
1136 TEST_F(NTPSnippetsServiceTest, ShouldClearOrphanedImages) {
1137 auto service = MakeSnippetsService();
1138
1139 LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
1140 ServeImageCallback cb = base::Bind(&ServeOneByOneImage, service.get());
1141
1142 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _))
1143 .WillOnce(WithArgs<0, 2>(Invoke(&cb, &ServeImageCallback::Run)));
1144 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1));
1145
1146 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSnippetUrl));
1147 EXPECT_EQ(1, image.Width());
1148 EXPECT_FALSE(image.IsEmpty());
1149
1150 // Send new suggestion which don't include the snippet referencing the image.
1151 LoadFromJSONString(service.get(),
1152 GetTestJson({GetSnippetWithUrl(
1153 "http://something.com/pletely/unrelated")}));
1154 // The image should still be available until a restart happens.
1155 EXPECT_FALSE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty());
1156 ResetSnippetsService(&service);
1157 // After the restart, the image should be garbage collected.
1158 EXPECT_TRUE(FetchImage(service.get(), MakeArticleID(kSnippetUrl)).IsEmpty());
1159 }
1160
1078 } // namespace ntp_snippets 1161 } // namespace ntp_snippets
OLDNEW
« no previous file with comments | « components/ntp_snippets/remote/ntp_snippets_service.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698