| OLD | NEW |
| 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/remote_suggestions_provider_impl.h" | 5 #include "components/ntp_snippets/remote/remote_suggestions_provider_impl.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 #include "components/ntp_snippets/remote/remote_suggestion.h" | 41 #include "components/ntp_snippets/remote/remote_suggestion.h" |
| 42 #include "components/ntp_snippets/remote/remote_suggestions_database.h" | 42 #include "components/ntp_snippets/remote/remote_suggestions_database.h" |
| 43 #include "components/ntp_snippets/remote/remote_suggestions_fetcher.h" | 43 #include "components/ntp_snippets/remote/remote_suggestions_fetcher.h" |
| 44 #include "components/ntp_snippets/remote/remote_suggestions_scheduler.h" | 44 #include "components/ntp_snippets/remote/remote_suggestions_scheduler.h" |
| 45 #include "components/ntp_snippets/remote/test_utils.h" | 45 #include "components/ntp_snippets/remote/test_utils.h" |
| 46 #include "components/ntp_snippets/user_classifier.h" | 46 #include "components/ntp_snippets/user_classifier.h" |
| 47 #include "components/prefs/testing_pref_service.h" | 47 #include "components/prefs/testing_pref_service.h" |
| 48 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" | 48 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h" |
| 49 #include "components/signin/core/browser/fake_signin_manager.h" | 49 #include "components/signin/core/browser/fake_signin_manager.h" |
| 50 #include "components/variations/variations_params_manager.h" | 50 #include "components/variations/variations_params_manager.h" |
| 51 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| 52 |
| 51 #include "net/url_request/test_url_fetcher_factory.h" | 53 #include "net/url_request/test_url_fetcher_factory.h" |
| 52 #include "net/url_request/url_request_test_util.h" | 54 #include "net/url_request/url_request_test_util.h" |
| 53 #include "testing/gmock/include/gmock/gmock.h" | 55 #include "testing/gmock/include/gmock/gmock.h" |
| 54 #include "testing/gmock_mutant.h" | 56 #include "testing/gmock_mutant.h" |
| 55 #include "testing/gtest/include/gtest/gtest.h" | 57 #include "testing/gtest/include/gtest/gtest.h" |
| 56 #include "ui/gfx/geometry/size.h" | 58 #include "ui/gfx/geometry/size.h" |
| 57 #include "ui/gfx/image/image.h" | 59 #include "ui/gfx/image/image.h" |
| 58 #include "ui/gfx/image/image_unittest_util.h" | 60 #include "ui/gfx/image/image_unittest_util.h" |
| 59 | 61 |
| 60 using image_fetcher::ImageFetcher; | 62 using image_fetcher::ImageFetcher; |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 } | 345 } |
| 344 }; | 346 }; |
| 345 | 347 |
| 346 class MockImageFetcher : public ImageFetcher { | 348 class MockImageFetcher : public ImageFetcher { |
| 347 public: | 349 public: |
| 348 MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*)); | 350 MOCK_METHOD1(SetImageFetcherDelegate, void(ImageFetcherDelegate*)); |
| 349 MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName)); | 351 MOCK_METHOD1(SetDataUseServiceName, void(DataUseServiceName)); |
| 350 MOCK_METHOD1(SetImageDownloadLimit, | 352 MOCK_METHOD1(SetImageDownloadLimit, |
| 351 void(base::Optional<int64_t> max_download_bytes)); | 353 void(base::Optional<int64_t> max_download_bytes)); |
| 352 MOCK_METHOD1(SetDesiredImageFrameSize, void(const gfx::Size&)); | 354 MOCK_METHOD1(SetDesiredImageFrameSize, void(const gfx::Size&)); |
| 353 MOCK_METHOD3(StartOrQueueNetworkRequest, | 355 MOCK_METHOD4(StartOrQueueNetworkRequest, |
| 354 void(const std::string&, | 356 void(const std::string&, |
| 355 const GURL&, | 357 const GURL&, |
| 356 const ImageFetcherCallback&)); | 358 const ImageFetcherCallback&, |
| 359 const net::NetworkTrafficAnnotationTag&)); |
| 357 MOCK_METHOD0(GetImageDecoder, image_fetcher::ImageDecoder*()); | 360 MOCK_METHOD0(GetImageDecoder, image_fetcher::ImageDecoder*()); |
| 358 }; | 361 }; |
| 359 | 362 |
| 360 class FakeImageDecoder : public image_fetcher::ImageDecoder { | 363 class FakeImageDecoder : public image_fetcher::ImageDecoder { |
| 361 public: | 364 public: |
| 362 FakeImageDecoder() {} | 365 FakeImageDecoder() {} |
| 363 ~FakeImageDecoder() override = default; | 366 ~FakeImageDecoder() override = default; |
| 364 void DecodeImage( | 367 void DecodeImage( |
| 365 const std::string& image_data, | 368 const std::string& image_data, |
| 366 const gfx::Size& desired_image_frame_size, | 369 const gfx::Size& desired_image_frame_size, |
| (...skipping 627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 Eq("http://second")); | 997 Eq("http://second")); |
| 995 }); | 998 }); |
| 996 LoadMoreFromJSONString(service.get(), articles_category(), | 999 LoadMoreFromJSONString(service.get(), articles_category(), |
| 997 GetTestJson({GetSuggestionWithUrl("http://second")}), | 1000 GetTestJson({GetSuggestionWithUrl("http://second")}), |
| 998 /*known_ids=*/std::set<std::string>(), | 1001 /*known_ids=*/std::set<std::string>(), |
| 999 expect_only_second_suggestion_received); | 1002 expect_only_second_suggestion_received); |
| 1000 | 1003 |
| 1001 // Verify we can resolve the image of the new suggestions. | 1004 // Verify we can resolve the image of the new suggestions. |
| 1002 ServeImageCallback cb = | 1005 ServeImageCallback cb = |
| 1003 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); | 1006 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); |
| 1004 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) | 1007 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _)) |
| 1005 .Times(2) | 1008 .Times(2) |
| 1006 .WillRepeatedly(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); | 1009 .WillRepeatedly(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); |
| 1007 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); | 1010 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); |
| 1008 gfx::Image image = FetchImage(service.get(), MakeArticleID("http://first")); | 1011 gfx::Image image = FetchImage(service.get(), MakeArticleID("http://first")); |
| 1009 EXPECT_FALSE(image.IsEmpty()); | 1012 EXPECT_FALSE(image.IsEmpty()); |
| 1010 EXPECT_EQ(1, image.Width()); | 1013 EXPECT_EQ(1, image.Width()); |
| 1011 | 1014 |
| 1012 image = FetchImage(service.get(), MakeArticleID("http://second")); | 1015 image = FetchImage(service.get(), MakeArticleID("http://second")); |
| 1013 EXPECT_FALSE(image.IsEmpty()); | 1016 EXPECT_FALSE(image.IsEmpty()); |
| 1014 EXPECT_EQ(1, image.Width()); | 1017 EXPECT_EQ(1, image.Width()); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1098 LoadFromJSONString(service.get(), | 1101 LoadFromJSONString(service.get(), |
| 1099 GetTestJson({GetSuggestionWithUrl("http://id-1"), | 1102 GetTestJson({GetSuggestionWithUrl("http://id-1"), |
| 1100 GetSuggestionWithUrl("http://id-2")})); | 1103 GetSuggestionWithUrl("http://id-2")})); |
| 1101 LoadFromJSONString(service.get(), | 1104 LoadFromJSONString(service.get(), |
| 1102 GetTestJson({GetSuggestionWithUrl("http://new-id-1"), | 1105 GetTestJson({GetSuggestionWithUrl("http://new-id-1"), |
| 1103 GetSuggestionWithUrl("http://new-id-2")})); | 1106 GetSuggestionWithUrl("http://new-id-2")})); |
| 1104 // Make sure images of both batches are available. This is to sanity check our | 1107 // Make sure images of both batches are available. This is to sanity check our |
| 1105 // assumptions for the test are right. | 1108 // assumptions for the test are right. |
| 1106 ServeImageCallback cb = | 1109 ServeImageCallback cb = |
| 1107 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); | 1110 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); |
| 1108 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) | 1111 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _)) |
| 1109 .Times(2) | 1112 .Times(2) |
| 1110 .WillRepeatedly(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); | 1113 .WillRepeatedly(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); |
| 1111 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); | 1114 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); |
| 1112 gfx::Image image = FetchImage(service.get(), MakeArticleID("http://id-1")); | 1115 gfx::Image image = FetchImage(service.get(), MakeArticleID("http://id-1")); |
| 1113 ASSERT_FALSE(image.IsEmpty()); | 1116 ASSERT_FALSE(image.IsEmpty()); |
| 1114 ASSERT_EQ(1, image.Width()); | 1117 ASSERT_EQ(1, image.Width()); |
| 1115 image = FetchImage(service.get(), MakeArticleID("http://new-id-1")); | 1118 image = FetchImage(service.get(), MakeArticleID("http://new-id-1")); |
| 1116 ASSERT_FALSE(image.IsEmpty()); | 1119 ASSERT_FALSE(image.IsEmpty()); |
| 1117 ASSERT_EQ(1, image.Width()); | 1120 ASSERT_EQ(1, image.Width()); |
| 1118 | 1121 |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1338 std::string json_str(GetTestJson( | 1341 std::string json_str(GetTestJson( |
| 1339 {GetSuggestionWithSources("http://site.com", "Source 1", "")})); | 1342 {GetSuggestionWithSources("http://site.com", "Source 1", "")})); |
| 1340 | 1343 |
| 1341 LoadFromJSONString(service.get(), json_str); | 1344 LoadFromJSONString(service.get(), json_str); |
| 1342 | 1345 |
| 1343 ASSERT_THAT(service->GetSuggestionsForTesting(articles_category()), | 1346 ASSERT_THAT(service->GetSuggestionsForTesting(articles_category()), |
| 1344 SizeIs(1)); | 1347 SizeIs(1)); |
| 1345 // Load the image to store it in the database. | 1348 // Load the image to store it in the database. |
| 1346 ServeImageCallback cb = | 1349 ServeImageCallback cb = |
| 1347 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); | 1350 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); |
| 1348 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) | 1351 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _)) |
| 1349 .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); | 1352 .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); |
| 1350 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); | 1353 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); |
| 1351 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl)); | 1354 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl)); |
| 1352 EXPECT_FALSE(image.IsEmpty()); | 1355 EXPECT_FALSE(image.IsEmpty()); |
| 1353 EXPECT_EQ(1, image.Width()); | 1356 EXPECT_EQ(1, image.Width()); |
| 1354 | 1357 |
| 1355 // Dismissing a non-existent suggestion shouldn't do anything. | 1358 // Dismissing a non-existent suggestion shouldn't do anything. |
| 1356 service->DismissSuggestion(MakeArticleID("http://othersite.com")); | 1359 service->DismissSuggestion(MakeArticleID("http://othersite.com")); |
| 1357 EXPECT_THAT(service->GetSuggestionsForTesting(articles_category()), | 1360 EXPECT_THAT(service->GetSuggestionsForTesting(articles_category()), |
| 1358 SizeIs(1)); | 1361 SizeIs(1)); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1443 auto service = MakeSuggestionsProvider(); | 1446 auto service = MakeSuggestionsProvider(); |
| 1444 | 1447 |
| 1445 std::string json_str1(GetTestJson({GetExpiredSuggestion()})); | 1448 std::string json_str1(GetTestJson({GetExpiredSuggestion()})); |
| 1446 // Load it. | 1449 // Load it. |
| 1447 LoadFromJSONString(service.get(), json_str1); | 1450 LoadFromJSONString(service.get(), json_str1); |
| 1448 // Load the image to store it in the database. | 1451 // Load the image to store it in the database. |
| 1449 // TODO(tschumann): Introduce some abstraction to nicely work with image | 1452 // TODO(tschumann): Introduce some abstraction to nicely work with image |
| 1450 // fetching expectations. | 1453 // fetching expectations. |
| 1451 ServeImageCallback cb = | 1454 ServeImageCallback cb = |
| 1452 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); | 1455 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); |
| 1453 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) | 1456 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _)) |
| 1454 .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); | 1457 .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); |
| 1455 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); | 1458 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); |
| 1456 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl)); | 1459 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl)); |
| 1457 EXPECT_FALSE(image.IsEmpty()); | 1460 EXPECT_FALSE(image.IsEmpty()); |
| 1458 EXPECT_EQ(1, image.Width()); | 1461 EXPECT_EQ(1, image.Width()); |
| 1459 | 1462 |
| 1460 // Dismiss the suggestion | 1463 // Dismiss the suggestion |
| 1461 service->DismissSuggestion( | 1464 service->DismissSuggestion( |
| 1462 ContentSuggestion::ID(articles_category(), kSuggestionUrl)); | 1465 ContentSuggestion::ID(articles_category(), kSuggestionUrl)); |
| 1463 | 1466 |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1617 auto service = MakeSuggestionsProvider(); | 1620 auto service = MakeSuggestionsProvider(); |
| 1618 | 1621 |
| 1619 LoadFromJSONString(service.get(), GetTestJson({GetSuggestion()})); | 1622 LoadFromJSONString(service.get(), GetTestJson({GetSuggestion()})); |
| 1620 | 1623 |
| 1621 gfx::Image image; | 1624 gfx::Image image; |
| 1622 MockFunction<void(const gfx::Image&)> image_fetched; | 1625 MockFunction<void(const gfx::Image&)> image_fetched; |
| 1623 ServeImageCallback cb = | 1626 ServeImageCallback cb = |
| 1624 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); | 1627 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); |
| 1625 { | 1628 { |
| 1626 InSequence s; | 1629 InSequence s; |
| 1627 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) | 1630 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _)) |
| 1628 .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); | 1631 .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); |
| 1629 EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image)); | 1632 EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image)); |
| 1630 } | 1633 } |
| 1631 | 1634 |
| 1632 service->FetchSuggestionImage( | 1635 service->FetchSuggestionImage( |
| 1633 MakeArticleID(kSuggestionUrl), | 1636 MakeArticleID(kSuggestionUrl), |
| 1634 base::Bind(&MockFunction<void(const gfx::Image&)>::Call, | 1637 base::Bind(&MockFunction<void(const gfx::Image&)>::Call, |
| 1635 base::Unretained(&image_fetched))); | 1638 base::Unretained(&image_fetched))); |
| 1636 base::RunLoop().RunUntilIdle(); | 1639 base::RunLoop().RunUntilIdle(); |
| 1637 // Check that the image by ServeOneByOneImage is really served. | 1640 // Check that the image by ServeOneByOneImage is really served. |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1724 Eq(CategoryStatus::AVAILABLE)); | 1727 Eq(CategoryStatus::AVAILABLE)); |
| 1725 } | 1728 } |
| 1726 | 1729 |
| 1727 TEST_F(RemoteSuggestionsProviderImplTest, ShouldClearOrphanedImagesOnRestart) { | 1730 TEST_F(RemoteSuggestionsProviderImplTest, ShouldClearOrphanedImagesOnRestart) { |
| 1728 auto service = MakeSuggestionsProvider(); | 1731 auto service = MakeSuggestionsProvider(); |
| 1729 | 1732 |
| 1730 LoadFromJSONString(service.get(), GetTestJson({GetSuggestion()})); | 1733 LoadFromJSONString(service.get(), GetTestJson({GetSuggestion()})); |
| 1731 ServeImageCallback cb = | 1734 ServeImageCallback cb = |
| 1732 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); | 1735 base::Bind(&ServeOneByOneImage, &service->GetImageFetcherForTesting()); |
| 1733 | 1736 |
| 1734 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _)) | 1737 EXPECT_CALL(*image_fetcher(), StartOrQueueNetworkRequest(_, _, _, _)) |
| 1735 .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); | 1738 .WillOnce(WithArgs<0, 2>(Invoke(CreateFunctor(cb)))); |
| 1736 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); | 1739 image_decoder()->SetDecodedImage(gfx::test::CreateImage(1, 1)); |
| 1737 | 1740 |
| 1738 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl)); | 1741 gfx::Image image = FetchImage(service.get(), MakeArticleID(kSuggestionUrl)); |
| 1739 EXPECT_EQ(1, image.Width()); | 1742 EXPECT_EQ(1, image.Width()); |
| 1740 EXPECT_FALSE(image.IsEmpty()); | 1743 EXPECT_FALSE(image.IsEmpty()); |
| 1741 | 1744 |
| 1742 // Send new suggestion which don't include the suggestion referencing the | 1745 // Send new suggestion which don't include the suggestion referencing the |
| 1743 // image. | 1746 // image. |
| 1744 LoadFromJSONString(service.get(), | 1747 LoadFromJSONString(service.get(), |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1875 WaitForSuggestionsProviderInitialization(service.get(), | 1878 WaitForSuggestionsProviderInitialization(service.get(), |
| 1876 /*set_empty_response=*/true); | 1879 /*set_empty_response=*/true); |
| 1877 | 1880 |
| 1878 // The scheduler should be notified of clearing the history. | 1881 // The scheduler should be notified of clearing the history. |
| 1879 EXPECT_CALL(*scheduler(), OnSuggestionsCleared()); | 1882 EXPECT_CALL(*scheduler(), OnSuggestionsCleared()); |
| 1880 service->OnStatusChanged(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT, | 1883 service->OnStatusChanged(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT, |
| 1881 RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN); | 1884 RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN); |
| 1882 } | 1885 } |
| 1883 | 1886 |
| 1884 } // namespace ntp_snippets | 1887 } // namespace ntp_snippets |
| OLD | NEW |