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

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

Issue 2223073002: Add per-section clearing and dismissed suggestions to snippets-internals (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix non-Debug builds Created 4 years, 4 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
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/ntp_snippets_service.h" 5 #include "components/ntp_snippets/ntp_snippets_service.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 &scheduler_, std::move(snippets_fetcher), /*image_fetcher=*/nullptr, 334 &scheduler_, std::move(snippets_fetcher), /*image_fetcher=*/nullptr,
335 /*image_fetcher=*/nullptr, base::MakeUnique<NTPSnippetsDatabase>( 335 /*image_fetcher=*/nullptr, base::MakeUnique<NTPSnippetsDatabase>(
336 database_dir_.path(), task_runner), 336 database_dir_.path(), task_runner),
337 base::MakeUnique<NTPSnippetsStatusService>(fake_signin_manager(), 337 base::MakeUnique<NTPSnippetsStatusService>(fake_signin_manager(),
338 pref_service()))); 338 pref_service())));
339 339
340 WaitForDBLoad(&observer_, service_.get()); 340 WaitForDBLoad(&observer_, service_.get());
341 } 341 }
342 342
343 std::string MakeUniqueID(const std::string& within_category_id) { 343 std::string MakeUniqueID(const std::string& within_category_id) {
344 return service()->MakeUniqueID( 344 return service()->MakeUniqueID(articles_category(), within_category_id);
345 category_factory_.FromKnownCategory(KnownCategories::ARTICLES), 345 }
346 within_category_id); 346
347 Category articles_category() {
348 return category_factory_.FromKnownCategory(KnownCategories::ARTICLES);
347 } 349 }
348 350
349 protected: 351 protected:
350 const GURL& test_url() { return test_url_; } 352 const GURL& test_url() { return test_url_; }
351 NTPSnippetsService* service() { return service_.get(); } 353 NTPSnippetsService* service() { return service_.get(); }
352 MockProviderObserver& observer() { return observer_; } 354 MockProviderObserver& observer() { return observer_; }
353 MockScheduler& mock_scheduler() { return scheduler_; } 355 MockScheduler& mock_scheduler() { return scheduler_; }
354 356
355 // Provide the json to be returned by the fake fetcher. 357 // Provide the json to be returned by the fake fetcher.
356 void SetUpFetchResponse(const std::string& json) { 358 void SetUpFetchResponse(const std::string& json) {
(...skipping 30 matching lines...) Expand all
387 389
388 // When we have no snippets are all, loading the service initiates a fetch. 390 // When we have no snippets are all, loading the service initiates a fetch.
389 base::RunLoop().RunUntilIdle(); 391 base::RunLoop().RunUntilIdle();
390 ASSERT_EQ("OK", service()->snippets_fetcher()->last_status()); 392 ASSERT_EQ("OK", service()->snippets_fetcher()->last_status());
391 } 393 }
392 394
393 TEST_F(NTPSnippetsServiceTest, Full) { 395 TEST_F(NTPSnippetsServiceTest, Full) {
394 std::string json_str(GetTestJson({GetSnippet()})); 396 std::string json_str(GetTestJson({GetSnippet()}));
395 397
396 LoadFromJSONString(json_str); 398 LoadFromJSONString(json_str);
397 ASSERT_THAT(service()->snippets(), SizeIs(1)); 399 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
398 const NTPSnippet& snippet = *service()->snippets().front(); 400 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front();
399 401
400 EXPECT_EQ(snippet.id(), kSnippetUrl); 402 EXPECT_EQ(snippet.id(), kSnippetUrl);
401 EXPECT_EQ(snippet.title(), kSnippetTitle); 403 EXPECT_EQ(snippet.title(), kSnippetTitle);
402 EXPECT_EQ(snippet.snippet(), kSnippetText); 404 EXPECT_EQ(snippet.snippet(), kSnippetText);
403 EXPECT_EQ(snippet.salient_image_url(), GURL(kSnippetSalientImage)); 405 EXPECT_EQ(snippet.salient_image_url(), GURL(kSnippetSalientImage));
404 EXPECT_EQ(GetDefaultCreationTime(), snippet.publish_date()); 406 EXPECT_EQ(GetDefaultCreationTime(), snippet.publish_date());
405 EXPECT_EQ(snippet.best_source().publisher_name, kSnippetPublisherName); 407 EXPECT_EQ(snippet.best_source().publisher_name, kSnippetPublisherName);
406 EXPECT_EQ(snippet.best_source().amp_url, GURL(kSnippetAmpUrl)); 408 EXPECT_EQ(snippet.best_source().amp_url, GURL(kSnippetAmpUrl));
407 } 409 }
408 410
409 TEST_F(NTPSnippetsServiceTest, Clear) { 411 TEST_F(NTPSnippetsServiceTest, Clear) {
410 std::string json_str(GetTestJson({GetSnippet()})); 412 std::string json_str(GetTestJson({GetSnippet()}));
411 413
412 LoadFromJSONString(json_str); 414 LoadFromJSONString(json_str);
413 EXPECT_THAT(service()->snippets(), SizeIs(1)); 415 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
414 416
415 service()->ClearCachedSuggestionsForDebugging(); 417 service()->ClearCachedSuggestionsForDebugging(articles_category());
416 EXPECT_THAT(service()->snippets(), IsEmpty()); 418 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
417 } 419 }
418 420
419 TEST_F(NTPSnippetsServiceTest, InsertAtFront) { 421 TEST_F(NTPSnippetsServiceTest, InsertAtFront) {
420 std::string first("http://first"); 422 std::string first("http://first");
421 LoadFromJSONString(GetTestJson({GetSnippetWithUrl(first)})); 423 LoadFromJSONString(GetTestJson({GetSnippetWithUrl(first)}));
422 EXPECT_THAT(service()->snippets(), ElementsAre(IdEq(first))); 424 EXPECT_THAT(service()->GetSnippetsForTesting(), ElementsAre(IdEq(first)));
423 425
424 std::string second("http://second"); 426 std::string second("http://second");
425 LoadFromJSONString(GetTestJson({GetSnippetWithUrl(second)})); 427 LoadFromJSONString(GetTestJson({GetSnippetWithUrl(second)}));
426 // The snippet loaded last should be at the first position in the list now. 428 // The snippet loaded last should be at the first position in the list now.
427 EXPECT_THAT(service()->snippets(), ElementsAre(IdEq(second), IdEq(first))); 429 EXPECT_THAT(service()->GetSnippetsForTesting(),
430 ElementsAre(IdEq(second), IdEq(first)));
428 } 431 }
429 432
430 TEST_F(NTPSnippetsServiceTest, LimitNumSnippets) { 433 TEST_F(NTPSnippetsServiceTest, LimitNumSnippets) {
431 int max_snippet_count = NTPSnippetsService::GetMaxSnippetCountForTesting(); 434 int max_snippet_count = NTPSnippetsService::GetMaxSnippetCountForTesting();
432 int snippets_per_load = max_snippet_count / 2 + 1; 435 int snippets_per_load = max_snippet_count / 2 + 1;
433 char url_format[] = "http://localhost/%i"; 436 char url_format[] = "http://localhost/%i";
434 437
435 std::vector<std::string> snippets1; 438 std::vector<std::string> snippets1;
436 std::vector<std::string> snippets2; 439 std::vector<std::string> snippets2;
437 for (int i = 0; i < snippets_per_load; i++) { 440 for (int i = 0; i < snippets_per_load; i++) {
438 snippets1.push_back(GetSnippetWithUrl(base::StringPrintf(url_format, i))); 441 snippets1.push_back(GetSnippetWithUrl(base::StringPrintf(url_format, i)));
439 snippets2.push_back(GetSnippetWithUrl( 442 snippets2.push_back(GetSnippetWithUrl(
440 base::StringPrintf(url_format, snippets_per_load + i))); 443 base::StringPrintf(url_format, snippets_per_load + i)));
441 } 444 }
442 445
443 LoadFromJSONString(GetTestJson(snippets1)); 446 LoadFromJSONString(GetTestJson(snippets1));
444 ASSERT_THAT(service()->snippets(), SizeIs(snippets1.size())); 447 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(snippets1.size()));
445 448
446 LoadFromJSONString(GetTestJson(snippets2)); 449 LoadFromJSONString(GetTestJson(snippets2));
447 EXPECT_THAT(service()->snippets(), SizeIs(max_snippet_count)); 450 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(max_snippet_count));
448 } 451 }
449 452
450 TEST_F(NTPSnippetsServiceTest, LoadInvalidJson) { 453 TEST_F(NTPSnippetsServiceTest, LoadInvalidJson) {
451 LoadFromJSONString(GetTestJson({GetInvalidSnippet()})); 454 LoadFromJSONString(GetTestJson({GetInvalidSnippet()}));
452 EXPECT_THAT(service()->snippets_fetcher()->last_status(), 455 EXPECT_THAT(service()->snippets_fetcher()->last_status(),
453 StartsWith("Received invalid JSON")); 456 StartsWith("Received invalid JSON"));
454 EXPECT_THAT(service()->snippets(), IsEmpty()); 457 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
455 } 458 }
456 459
457 TEST_F(NTPSnippetsServiceTest, LoadInvalidJsonWithExistingSnippets) { 460 TEST_F(NTPSnippetsServiceTest, LoadInvalidJsonWithExistingSnippets) {
458 LoadFromJSONString(GetTestJson({GetSnippet()})); 461 LoadFromJSONString(GetTestJson({GetSnippet()}));
459 ASSERT_THAT(service()->snippets(), SizeIs(1)); 462 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
460 ASSERT_EQ("OK", service()->snippets_fetcher()->last_status()); 463 ASSERT_EQ("OK", service()->snippets_fetcher()->last_status());
461 464
462 LoadFromJSONString(GetTestJson({GetInvalidSnippet()})); 465 LoadFromJSONString(GetTestJson({GetInvalidSnippet()}));
463 EXPECT_THAT(service()->snippets_fetcher()->last_status(), 466 EXPECT_THAT(service()->snippets_fetcher()->last_status(),
464 StartsWith("Received invalid JSON")); 467 StartsWith("Received invalid JSON"));
465 // This should not have changed the existing snippets. 468 // This should not have changed the existing snippets.
466 EXPECT_THAT(service()->snippets(), SizeIs(1)); 469 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
467 } 470 }
468 471
469 TEST_F(NTPSnippetsServiceTest, LoadIncompleteJson) { 472 TEST_F(NTPSnippetsServiceTest, LoadIncompleteJson) {
470 LoadFromJSONString(GetTestJson({GetIncompleteSnippet()})); 473 LoadFromJSONString(GetTestJson({GetIncompleteSnippet()}));
471 EXPECT_EQ("Invalid / empty list.", 474 EXPECT_EQ("Invalid / empty list.",
472 service()->snippets_fetcher()->last_status()); 475 service()->snippets_fetcher()->last_status());
473 EXPECT_THAT(service()->snippets(), IsEmpty()); 476 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
474 } 477 }
475 478
476 TEST_F(NTPSnippetsServiceTest, LoadIncompleteJsonWithExistingSnippets) { 479 TEST_F(NTPSnippetsServiceTest, LoadIncompleteJsonWithExistingSnippets) {
477 LoadFromJSONString(GetTestJson({GetSnippet()})); 480 LoadFromJSONString(GetTestJson({GetSnippet()}));
478 ASSERT_THAT(service()->snippets(), SizeIs(1)); 481 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
479 482
480 LoadFromJSONString(GetTestJson({GetIncompleteSnippet()})); 483 LoadFromJSONString(GetTestJson({GetIncompleteSnippet()}));
481 EXPECT_EQ("Invalid / empty list.", 484 EXPECT_EQ("Invalid / empty list.",
482 service()->snippets_fetcher()->last_status()); 485 service()->snippets_fetcher()->last_status());
483 // This should not have changed the existing snippets. 486 // This should not have changed the existing snippets.
484 EXPECT_THAT(service()->snippets(), SizeIs(1)); 487 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
485 } 488 }
486 489
487 TEST_F(NTPSnippetsServiceTest, Dismiss) { 490 TEST_F(NTPSnippetsServiceTest, Dismiss) {
488 std::vector<std::string> source_urls, publishers, amp_urls; 491 std::vector<std::string> source_urls, publishers, amp_urls;
489 source_urls.push_back(std::string("http://site.com")); 492 source_urls.push_back(std::string("http://site.com"));
490 publishers.push_back(std::string("Source 1")); 493 publishers.push_back(std::string("Source 1"));
491 amp_urls.push_back(std::string()); 494 amp_urls.push_back(std::string());
492 std::string json_str( 495 std::string json_str(
493 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); 496 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
494 497
495 LoadFromJSONString(json_str); 498 LoadFromJSONString(json_str);
496 499
497 ASSERT_THAT(service()->snippets(), SizeIs(1)); 500 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
498 501
499 // Dismissing a non-existent snippet shouldn't do anything. 502 // Dismissing a non-existent snippet shouldn't do anything.
500 service()->DismissSuggestion(MakeUniqueID("http://othersite.com")); 503 service()->DismissSuggestion(MakeUniqueID("http://othersite.com"));
501 EXPECT_THAT(service()->snippets(), SizeIs(1)); 504 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
502 505
503 // Dismiss the snippet. 506 // Dismiss the snippet.
504 service()->DismissSuggestion(MakeUniqueID(kSnippetUrl)); 507 service()->DismissSuggestion(MakeUniqueID(kSnippetUrl));
505 EXPECT_THAT(service()->snippets(), IsEmpty()); 508 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
506 509
507 // Make sure that fetching the same snippet again does not re-add it. 510 // Make sure that fetching the same snippet again does not re-add it.
508 LoadFromJSONString(json_str); 511 LoadFromJSONString(json_str);
509 EXPECT_THAT(service()->snippets(), IsEmpty()); 512 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
510 513
511 // The snippet should stay dismissed even after re-creating the service. 514 // The snippet should stay dismissed even after re-creating the service.
512 RecreateSnippetsService(); 515 RecreateSnippetsService();
513 LoadFromJSONString(json_str); 516 LoadFromJSONString(json_str);
514 EXPECT_THAT(service()->snippets(), IsEmpty()); 517 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
515 518
516 // The snippet can be added again after clearing dismissed snippets. 519 // The snippet can be added again after clearing dismissed snippets.
517 service()->ClearDismissedSuggestionsForDebugging(); 520 service()->ClearDismissedSuggestionsForDebugging(articles_category());
518 EXPECT_THAT(service()->snippets(), IsEmpty()); 521 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
519 LoadFromJSONString(json_str); 522 LoadFromJSONString(json_str);
520 EXPECT_THAT(service()->snippets(), SizeIs(1)); 523 EXPECT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
521 } 524 }
522 525
523 TEST_F(NTPSnippetsServiceTest, GetDismissed) { 526 TEST_F(NTPSnippetsServiceTest, GetDismissed) {
524 LoadFromJSONString(GetTestJson({GetSnippet()})); 527 LoadFromJSONString(GetTestJson({GetSnippet()}));
525 528
526 service()->DismissSuggestion(MakeUniqueID(kSnippetUrl)); 529 service()->DismissSuggestion(MakeUniqueID(kSnippetUrl));
527 const NTPSnippet::PtrVector& snippets = service()->dismissed_snippets(); 530 std::vector<ContentSuggestion> suggestions =
528 EXPECT_EQ(1u, snippets.size()); 531 service()->GetDismissedSuggestionsForDebugging(articles_category());
529 for (auto& snippet : snippets) { 532 EXPECT_EQ(1u, suggestions.size());
530 EXPECT_EQ(kSnippetUrl, snippet->id()); 533 for (auto& suggestion : suggestions) {
534 EXPECT_EQ(MakeUniqueID(kSnippetUrl), suggestion.id());
531 } 535 }
532 536
533 // There should be no dismissed snippet after clearing the list. 537 // There should be no dismissed snippet after clearing the list.
534 service()->ClearDismissedSuggestionsForDebugging(); 538 service()->ClearDismissedSuggestionsForDebugging(articles_category());
535 EXPECT_EQ(0u, service()->dismissed_snippets().size()); 539 EXPECT_EQ(0u, service()
540 ->GetDismissedSuggestionsForDebugging(articles_category())
541 .size());
536 } 542 }
537 543
538 TEST_F(NTPSnippetsServiceTest, CreationTimestampParseFail) { 544 TEST_F(NTPSnippetsServiceTest, CreationTimestampParseFail) {
539 std::string json_str(GetTestJson({GetSnippetWithTimes( 545 std::string json_str(GetTestJson({GetSnippetWithTimes(
540 "aaa1448459205", 546 "aaa1448459205",
541 NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()))})); 547 NTPSnippet::TimeToJsonString(GetDefaultExpirationTime()))}));
542 548
543 LoadFromJSONString(json_str); 549 LoadFromJSONString(json_str);
544 ASSERT_THAT(service()->snippets(), SizeIs(1)); 550 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
545 const NTPSnippet& snippet = *service()->snippets().front(); 551 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front();
546 EXPECT_EQ(snippet.id(), kSnippetUrl); 552 EXPECT_EQ(snippet.id(), kSnippetUrl);
547 EXPECT_EQ(snippet.title(), kSnippetTitle); 553 EXPECT_EQ(snippet.title(), kSnippetTitle);
548 EXPECT_EQ(snippet.snippet(), kSnippetText); 554 EXPECT_EQ(snippet.snippet(), kSnippetText);
549 EXPECT_EQ(base::Time::UnixEpoch(), snippet.publish_date()); 555 EXPECT_EQ(base::Time::UnixEpoch(), snippet.publish_date());
550 } 556 }
551 557
552 TEST_F(NTPSnippetsServiceTest, RemoveExpiredContent) { 558 TEST_F(NTPSnippetsServiceTest, RemoveExpiredContent) {
553 std::string json_str(GetTestJson({GetExpiredSnippet()})); 559 std::string json_str(GetTestJson({GetExpiredSnippet()}));
554 560
555 LoadFromJSONString(json_str); 561 LoadFromJSONString(json_str);
556 EXPECT_THAT(service()->snippets(), IsEmpty()); 562 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
557 } 563 }
558 564
559 TEST_F(NTPSnippetsServiceTest, TestSingleSource) { 565 TEST_F(NTPSnippetsServiceTest, TestSingleSource) {
560 std::vector<std::string> source_urls, publishers, amp_urls; 566 std::vector<std::string> source_urls, publishers, amp_urls;
561 source_urls.push_back(std::string("http://source1.com")); 567 source_urls.push_back(std::string("http://source1.com"));
562 publishers.push_back(std::string("Source 1")); 568 publishers.push_back(std::string("Source 1"));
563 amp_urls.push_back(std::string("http://source1.amp.com")); 569 amp_urls.push_back(std::string("http://source1.amp.com"));
564 std::string json_str( 570 std::string json_str(
565 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); 571 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
566 572
567 LoadFromJSONString(json_str); 573 LoadFromJSONString(json_str);
568 ASSERT_THAT(service()->snippets(), SizeIs(1)); 574 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
569 const NTPSnippet& snippet = *service()->snippets().front(); 575 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front();
570 EXPECT_EQ(snippet.sources().size(), 1u); 576 EXPECT_EQ(snippet.sources().size(), 1u);
571 EXPECT_EQ(snippet.id(), kSnippetUrl); 577 EXPECT_EQ(snippet.id(), kSnippetUrl);
572 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); 578 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com"));
573 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1")); 579 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1"));
574 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com")); 580 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com"));
575 } 581 }
576 582
577 TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMalformedUrl) { 583 TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMalformedUrl) {
578 std::vector<std::string> source_urls, publishers, amp_urls; 584 std::vector<std::string> source_urls, publishers, amp_urls;
579 source_urls.push_back(std::string("aaaa")); 585 source_urls.push_back(std::string("aaaa"));
580 publishers.push_back(std::string("Source 1")); 586 publishers.push_back(std::string("Source 1"));
581 amp_urls.push_back(std::string("http://source1.amp.com")); 587 amp_urls.push_back(std::string("http://source1.amp.com"));
582 std::string json_str( 588 std::string json_str(
583 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); 589 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
584 590
585 LoadFromJSONString(json_str); 591 LoadFromJSONString(json_str);
586 EXPECT_THAT(service()->snippets(), IsEmpty()); 592 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
587 } 593 }
588 594
589 TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMissingData) { 595 TEST_F(NTPSnippetsServiceTest, TestSingleSourceWithMissingData) {
590 std::vector<std::string> source_urls, publishers, amp_urls; 596 std::vector<std::string> source_urls, publishers, amp_urls;
591 source_urls.push_back(std::string("http://source1.com")); 597 source_urls.push_back(std::string("http://source1.com"));
592 publishers.push_back(std::string()); 598 publishers.push_back(std::string());
593 amp_urls.push_back(std::string()); 599 amp_urls.push_back(std::string());
594 std::string json_str( 600 std::string json_str(
595 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); 601 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
596 602
597 LoadFromJSONString(json_str); 603 LoadFromJSONString(json_str);
598 EXPECT_THAT(service()->snippets(), IsEmpty()); 604 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
599 } 605 }
600 606
601 TEST_F(NTPSnippetsServiceTest, TestMultipleSources) { 607 TEST_F(NTPSnippetsServiceTest, TestMultipleSources) {
602 std::vector<std::string> source_urls, publishers, amp_urls; 608 std::vector<std::string> source_urls, publishers, amp_urls;
603 source_urls.push_back(std::string("http://source1.com")); 609 source_urls.push_back(std::string("http://source1.com"));
604 source_urls.push_back(std::string("http://source2.com")); 610 source_urls.push_back(std::string("http://source2.com"));
605 publishers.push_back(std::string("Source 1")); 611 publishers.push_back(std::string("Source 1"));
606 publishers.push_back(std::string("Source 2")); 612 publishers.push_back(std::string("Source 2"));
607 amp_urls.push_back(std::string("http://source1.amp.com")); 613 amp_urls.push_back(std::string("http://source1.amp.com"));
608 amp_urls.push_back(std::string("http://source2.amp.com")); 614 amp_urls.push_back(std::string("http://source2.amp.com"));
609 std::string json_str( 615 std::string json_str(
610 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); 616 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
611 617
612 LoadFromJSONString(json_str); 618 LoadFromJSONString(json_str);
613 ASSERT_THAT(service()->snippets(), SizeIs(1)); 619 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
614 const NTPSnippet& snippet = *service()->snippets().front(); 620 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front();
615 // Expect the first source to be chosen 621 // Expect the first source to be chosen
616 EXPECT_EQ(snippet.sources().size(), 2u); 622 EXPECT_EQ(snippet.sources().size(), 2u);
617 EXPECT_EQ(snippet.id(), kSnippetUrl); 623 EXPECT_EQ(snippet.id(), kSnippetUrl);
618 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); 624 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com"));
619 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1")); 625 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1"));
620 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com")); 626 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com"));
621 } 627 }
622 628
623 TEST_F(NTPSnippetsServiceTest, TestMultipleIncompleteSources) { 629 TEST_F(NTPSnippetsServiceTest, TestMultipleIncompleteSources) {
624 // Set Source 2 to have no AMP url, and Source 1 to have no publisher name 630 // Set Source 2 to have no AMP url, and Source 1 to have no publisher name
625 // Source 2 should win since we favor publisher name over amp url 631 // Source 2 should win since we favor publisher name over amp url
626 std::vector<std::string> source_urls, publishers, amp_urls; 632 std::vector<std::string> source_urls, publishers, amp_urls;
627 source_urls.push_back(std::string("http://source1.com")); 633 source_urls.push_back(std::string("http://source1.com"));
628 source_urls.push_back(std::string("http://source2.com")); 634 source_urls.push_back(std::string("http://source2.com"));
629 publishers.push_back(std::string()); 635 publishers.push_back(std::string());
630 publishers.push_back(std::string("Source 2")); 636 publishers.push_back(std::string("Source 2"));
631 amp_urls.push_back(std::string("http://source1.amp.com")); 637 amp_urls.push_back(std::string("http://source1.amp.com"));
632 amp_urls.push_back(std::string()); 638 amp_urls.push_back(std::string());
633 std::string json_str( 639 std::string json_str(
634 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); 640 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
635 641
636 LoadFromJSONString(json_str); 642 LoadFromJSONString(json_str);
637 ASSERT_THAT(service()->snippets(), SizeIs(1)); 643 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
638 { 644 {
639 const NTPSnippet& snippet = *service()->snippets().front(); 645 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front();
640 EXPECT_EQ(snippet.sources().size(), 2u); 646 EXPECT_EQ(snippet.sources().size(), 2u);
641 EXPECT_EQ(snippet.id(), kSnippetUrl); 647 EXPECT_EQ(snippet.id(), kSnippetUrl);
642 EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com")); 648 EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com"));
643 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2")); 649 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2"));
644 EXPECT_EQ(snippet.best_source().amp_url, GURL()); 650 EXPECT_EQ(snippet.best_source().amp_url, GURL());
645 } 651 }
646 652
647 service()->ClearCachedSuggestionsForDebugging(); 653 service()->ClearCachedSuggestionsForDebugging(articles_category());
648 // Set Source 1 to have no AMP url, and Source 2 to have no publisher name 654 // Set Source 1 to have no AMP url, and Source 2 to have no publisher name
649 // Source 1 should win in this case since we prefer publisher name to AMP url 655 // Source 1 should win in this case since we prefer publisher name to AMP url
650 source_urls.clear(); 656 source_urls.clear();
651 source_urls.push_back(std::string("http://source1.com")); 657 source_urls.push_back(std::string("http://source1.com"));
652 source_urls.push_back(std::string("http://source2.com")); 658 source_urls.push_back(std::string("http://source2.com"));
653 publishers.clear(); 659 publishers.clear();
654 publishers.push_back(std::string("Source 1")); 660 publishers.push_back(std::string("Source 1"));
655 publishers.push_back(std::string()); 661 publishers.push_back(std::string());
656 amp_urls.clear(); 662 amp_urls.clear();
657 amp_urls.push_back(std::string()); 663 amp_urls.push_back(std::string());
658 amp_urls.push_back(std::string("http://source2.amp.com")); 664 amp_urls.push_back(std::string("http://source2.amp.com"));
659 json_str = 665 json_str =
660 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); 666 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)});
661 667
662 LoadFromJSONString(json_str); 668 LoadFromJSONString(json_str);
663 ASSERT_THAT(service()->snippets(), SizeIs(1)); 669 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
664 { 670 {
665 const NTPSnippet& snippet = *service()->snippets().front(); 671 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front();
666 EXPECT_EQ(snippet.sources().size(), 2u); 672 EXPECT_EQ(snippet.sources().size(), 2u);
667 EXPECT_EQ(snippet.id(), kSnippetUrl); 673 EXPECT_EQ(snippet.id(), kSnippetUrl);
668 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); 674 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com"));
669 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1")); 675 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1"));
670 EXPECT_EQ(snippet.best_source().amp_url, GURL()); 676 EXPECT_EQ(snippet.best_source().amp_url, GURL());
671 } 677 }
672 678
673 service()->ClearCachedSuggestionsForDebugging(); 679 service()->ClearCachedSuggestionsForDebugging(articles_category());
674 // Set source 1 to have no AMP url and no source, and source 2 to only have 680 // Set source 1 to have no AMP url and no source, and source 2 to only have
675 // amp url. There should be no snippets since we only add sources we consider 681 // amp url. There should be no snippets since we only add sources we consider
676 // complete 682 // complete
677 source_urls.clear(); 683 source_urls.clear();
678 source_urls.push_back(std::string("http://source1.com")); 684 source_urls.push_back(std::string("http://source1.com"));
679 source_urls.push_back(std::string("http://source2.com")); 685 source_urls.push_back(std::string("http://source2.com"));
680 publishers.clear(); 686 publishers.clear();
681 publishers.push_back(std::string()); 687 publishers.push_back(std::string());
682 publishers.push_back(std::string()); 688 publishers.push_back(std::string());
683 amp_urls.clear(); 689 amp_urls.clear();
684 amp_urls.push_back(std::string()); 690 amp_urls.push_back(std::string());
685 amp_urls.push_back(std::string("http://source2.amp.com")); 691 amp_urls.push_back(std::string("http://source2.amp.com"));
686 json_str = 692 json_str =
687 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); 693 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)});
688 694
689 LoadFromJSONString(json_str); 695 LoadFromJSONString(json_str);
690 EXPECT_THAT(service()->snippets(), IsEmpty()); 696 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
691 } 697 }
692 698
693 TEST_F(NTPSnippetsServiceTest, TestMultipleCompleteSources) { 699 TEST_F(NTPSnippetsServiceTest, TestMultipleCompleteSources) {
694 // Test 2 complete sources, we should choose the first complete source 700 // Test 2 complete sources, we should choose the first complete source
695 std::vector<std::string> source_urls, publishers, amp_urls; 701 std::vector<std::string> source_urls, publishers, amp_urls;
696 source_urls.push_back(std::string("http://source1.com")); 702 source_urls.push_back(std::string("http://source1.com"));
697 source_urls.push_back(std::string("http://source2.com")); 703 source_urls.push_back(std::string("http://source2.com"));
698 source_urls.push_back(std::string("http://source3.com")); 704 source_urls.push_back(std::string("http://source3.com"));
699 publishers.push_back(std::string("Source 1")); 705 publishers.push_back(std::string("Source 1"));
700 publishers.push_back(std::string()); 706 publishers.push_back(std::string());
701 publishers.push_back(std::string("Source 3")); 707 publishers.push_back(std::string("Source 3"));
702 amp_urls.push_back(std::string("http://source1.amp.com")); 708 amp_urls.push_back(std::string("http://source1.amp.com"));
703 amp_urls.push_back(std::string("http://source2.amp.com")); 709 amp_urls.push_back(std::string("http://source2.amp.com"));
704 amp_urls.push_back(std::string("http://source3.amp.com")); 710 amp_urls.push_back(std::string("http://source3.amp.com"));
705 std::string json_str( 711 std::string json_str(
706 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)})); 712 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}));
707 713
708 LoadFromJSONString(json_str); 714 LoadFromJSONString(json_str);
709 ASSERT_THAT(service()->snippets(), SizeIs(1)); 715 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
710 { 716 {
711 const NTPSnippet& snippet = *service()->snippets().front(); 717 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front();
712 EXPECT_EQ(snippet.sources().size(), 3u); 718 EXPECT_EQ(snippet.sources().size(), 3u);
713 EXPECT_EQ(snippet.id(), kSnippetUrl); 719 EXPECT_EQ(snippet.id(), kSnippetUrl);
714 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com")); 720 EXPECT_EQ(snippet.best_source().url, GURL("http://source1.com"));
715 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1")); 721 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 1"));
716 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com")); 722 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source1.amp.com"));
717 } 723 }
718 724
719 // Test 2 complete sources, we should choose the first complete source 725 // Test 2 complete sources, we should choose the first complete source
720 service()->ClearCachedSuggestionsForDebugging(); 726 service()->ClearCachedSuggestionsForDebugging(articles_category());
721 source_urls.clear(); 727 source_urls.clear();
722 source_urls.push_back(std::string("http://source1.com")); 728 source_urls.push_back(std::string("http://source1.com"));
723 source_urls.push_back(std::string("http://source2.com")); 729 source_urls.push_back(std::string("http://source2.com"));
724 source_urls.push_back(std::string("http://source3.com")); 730 source_urls.push_back(std::string("http://source3.com"));
725 publishers.clear(); 731 publishers.clear();
726 publishers.push_back(std::string()); 732 publishers.push_back(std::string());
727 publishers.push_back(std::string("Source 2")); 733 publishers.push_back(std::string("Source 2"));
728 publishers.push_back(std::string("Source 3")); 734 publishers.push_back(std::string("Source 3"));
729 amp_urls.clear(); 735 amp_urls.clear();
730 amp_urls.push_back(std::string("http://source1.amp.com")); 736 amp_urls.push_back(std::string("http://source1.amp.com"));
731 amp_urls.push_back(std::string("http://source2.amp.com")); 737 amp_urls.push_back(std::string("http://source2.amp.com"));
732 amp_urls.push_back(std::string("http://source3.amp.com")); 738 amp_urls.push_back(std::string("http://source3.amp.com"));
733 json_str = 739 json_str =
734 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); 740 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)});
735 741
736 LoadFromJSONString(json_str); 742 LoadFromJSONString(json_str);
737 ASSERT_THAT(service()->snippets(), SizeIs(1)); 743 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
738 { 744 {
739 const NTPSnippet& snippet = *service()->snippets().front(); 745 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front();
740 EXPECT_EQ(snippet.sources().size(), 3u); 746 EXPECT_EQ(snippet.sources().size(), 3u);
741 EXPECT_EQ(snippet.id(), kSnippetUrl); 747 EXPECT_EQ(snippet.id(), kSnippetUrl);
742 EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com")); 748 EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com"));
743 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2")); 749 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2"));
744 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source2.amp.com")); 750 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source2.amp.com"));
745 } 751 }
746 752
747 // Test 3 complete sources, we should choose the first complete source 753 // Test 3 complete sources, we should choose the first complete source
748 service()->ClearCachedSuggestionsForDebugging(); 754 service()->ClearCachedSuggestionsForDebugging(articles_category());
749 source_urls.clear(); 755 source_urls.clear();
750 source_urls.push_back(std::string("http://source1.com")); 756 source_urls.push_back(std::string("http://source1.com"));
751 source_urls.push_back(std::string("http://source2.com")); 757 source_urls.push_back(std::string("http://source2.com"));
752 source_urls.push_back(std::string("http://source3.com")); 758 source_urls.push_back(std::string("http://source3.com"));
753 publishers.clear(); 759 publishers.clear();
754 publishers.push_back(std::string("Source 1")); 760 publishers.push_back(std::string("Source 1"));
755 publishers.push_back(std::string("Source 2")); 761 publishers.push_back(std::string("Source 2"));
756 publishers.push_back(std::string("Source 3")); 762 publishers.push_back(std::string("Source 3"));
757 amp_urls.clear(); 763 amp_urls.clear();
758 amp_urls.push_back(std::string()); 764 amp_urls.push_back(std::string());
759 amp_urls.push_back(std::string("http://source2.amp.com")); 765 amp_urls.push_back(std::string("http://source2.amp.com"));
760 amp_urls.push_back(std::string("http://source3.amp.com")); 766 amp_urls.push_back(std::string("http://source3.amp.com"));
761 json_str = 767 json_str =
762 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)}); 768 GetTestJson({GetSnippetWithSources(source_urls, publishers, amp_urls)});
763 769
764 LoadFromJSONString(json_str); 770 LoadFromJSONString(json_str);
765 ASSERT_THAT(service()->snippets(), SizeIs(1)); 771 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
766 { 772 {
767 const NTPSnippet& snippet = *service()->snippets().front(); 773 const NTPSnippet& snippet = *service()->GetSnippetsForTesting().front();
768 EXPECT_EQ(snippet.sources().size(), 3u); 774 EXPECT_EQ(snippet.sources().size(), 3u);
769 EXPECT_EQ(snippet.id(), kSnippetUrl); 775 EXPECT_EQ(snippet.id(), kSnippetUrl);
770 EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com")); 776 EXPECT_EQ(snippet.best_source().url, GURL("http://source2.com"));
771 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2")); 777 EXPECT_EQ(snippet.best_source().publisher_name, std::string("Source 2"));
772 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source2.amp.com")); 778 EXPECT_EQ(snippet.best_source().amp_url, GURL("http://source2.amp.com"));
773 } 779 }
774 } 780 }
775 781
776 TEST_F(NTPSnippetsServiceTest, LogNumArticlesHistogram) { 782 TEST_F(NTPSnippetsServiceTest, LogNumArticlesHistogram) {
777 base::HistogramTester tester; 783 base::HistogramTester tester;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
838 "http://mashable.com/2016/05/11/stolen?utm_cid=1"}; 844 "http://mashable.com/2016/05/11/stolen?utm_cid=1"};
839 const std::vector<std::string> publishers = {"Mashable", "AOL", "Mashable"}; 845 const std::vector<std::string> publishers = {"Mashable", "AOL", "Mashable"};
840 const std::vector<std::string> amp_urls = { 846 const std::vector<std::string> amp_urls = {
841 "http://mashable-amphtml.googleusercontent.com/1", 847 "http://mashable-amphtml.googleusercontent.com/1",
842 "http://t2.gstatic.com/images?q=tbn:3", 848 "http://t2.gstatic.com/images?q=tbn:3",
843 "http://t2.gstatic.com/images?q=tbn:3"}; 849 "http://t2.gstatic.com/images?q=tbn:3"};
844 850
845 // Add the snippet from the mashable domain. 851 // Add the snippet from the mashable domain.
846 LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources( 852 LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources(
847 source_urls[0], creation, expiry, source_urls, publishers, amp_urls)})); 853 source_urls[0], creation, expiry, source_urls, publishers, amp_urls)}));
848 ASSERT_THAT(service()->snippets(), SizeIs(1)); 854 ASSERT_THAT(service()->GetSnippetsForTesting(), SizeIs(1));
849 // Dismiss the snippet via the mashable source corpus ID. 855 // Dismiss the snippet via the mashable source corpus ID.
850 service()->DismissSuggestion(MakeUniqueID(source_urls[0])); 856 service()->DismissSuggestion(MakeUniqueID(source_urls[0]));
851 EXPECT_THAT(service()->snippets(), IsEmpty()); 857 EXPECT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
852 858
853 // The same article from the AOL domain should now be detected as dismissed. 859 // The same article from the AOL domain should now be detected as dismissed.
854 LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources( 860 LoadFromJSONString(GetTestJson({GetSnippetWithUrlAndTimesAndSources(
855 source_urls[1], creation, expiry, source_urls, publishers, amp_urls)})); 861 source_urls[1], creation, expiry, source_urls, publishers, amp_urls)}));
856 ASSERT_THAT(service()->snippets(), IsEmpty()); 862 ASSERT_THAT(service()->GetSnippetsForTesting(), IsEmpty());
857 } 863 }
858 864
859 TEST_F(NTPSnippetsServiceTest, StatusChanges) { 865 TEST_F(NTPSnippetsServiceTest, StatusChanges) {
860 // Simulate user signed out 866 // Simulate user signed out
861 SetUpFetchResponse(GetTestJson({GetSnippet()})); 867 SetUpFetchResponse(GetTestJson({GetSnippet()}));
862 EXPECT_CALL(observer(), 868 EXPECT_CALL(observer(),
863 OnCategoryStatusChanged(_, _, CategoryStatus::SIGNED_OUT)); 869 OnCategoryStatusChanged(_, _, CategoryStatus::SIGNED_OUT));
864 service()->OnDisabledReasonChanged(DisabledReason::SIGNED_OUT); 870 service()->OnDisabledReasonChanged(DisabledReason::SIGNED_OUT);
865 base::RunLoop().RunUntilIdle(); 871 base::RunLoop().RunUntilIdle();
866 EXPECT_EQ(NTPSnippetsService::State::DISABLED, service()->state_); 872 EXPECT_EQ(NTPSnippetsService::State::DISABLED, service()->state_);
867 EXPECT_THAT(service()->snippets(), IsEmpty()); // No fetch should be made. 873 EXPECT_THAT(service()->GetSnippetsForTesting(),
874 IsEmpty()); // No fetch should be made.
868 875
869 // Simulate user sign in. The service should be ready again and load snippets. 876 // Simulate user sign in. The service should be ready again and load snippets.
870 SetUpFetchResponse(GetTestJson({GetSnippet()})); 877 SetUpFetchResponse(GetTestJson({GetSnippet()}));
871 EXPECT_CALL(observer(), 878 EXPECT_CALL(observer(),
872 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE_LOADING)); 879 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE_LOADING));
873 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1); 880 EXPECT_CALL(mock_scheduler(), Schedule(_, _, _, _)).Times(1);
874 service()->OnDisabledReasonChanged(DisabledReason::NONE); 881 service()->OnDisabledReasonChanged(DisabledReason::NONE);
875 EXPECT_CALL(observer(), 882 EXPECT_CALL(observer(),
876 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE)); 883 OnCategoryStatusChanged(_, _, CategoryStatus::AVAILABLE));
877 base::RunLoop().RunUntilIdle(); 884 base::RunLoop().RunUntilIdle();
878 EXPECT_EQ(NTPSnippetsService::State::READY, service()->state_); 885 EXPECT_EQ(NTPSnippetsService::State::READY, service()->state_);
879 EXPECT_FALSE(service()->snippets().empty()); 886 EXPECT_FALSE(service()->GetSnippetsForTesting().empty());
880 } 887 }
881 888
882 } // namespace ntp_snippets 889 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698