| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/themes/ntp_background_service.h" |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/functional/callback.h" |
| #include "base/run_loop.h" |
| #include "base/test/bind.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/mock_callback.h" |
| #include "base/test/run_until.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/task_environment.h" |
| #include "components/application_locale_storage/application_locale_storage.h" |
| #include "components/search/ntp_features.h" |
| #include "components/themes/ntp_background_data.h" |
| #include "components/themes/ntp_background_service_observer.h" |
| #include "components/version_info/version_info.h" |
| #include "ntp_background_data.h" |
| #include "services/network/public/cpp/data_element.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/ui_base_features.h" |
| #include "url/gurl.h" |
| |
| using testing::Eq; |
| using testing::StartsWith; |
| |
| const char kTestImageUrl[] = "https://wallpapers.co/some_image"; |
| const char kTestActionUrl[] = "https://wallpapers.co/some_image/learn_more"; |
| |
| namespace { |
| |
| class MockNtpBackgroundServiceObserver : public NtpBackgroundServiceObserver { |
| public: |
| MOCK_METHOD0(OnCollectionInfoAvailable, void()); |
| MOCK_METHOD0(OnCollectionImagesAvailable, void()); |
| MOCK_METHOD0(OnNextCollectionImageAvailable, void()); |
| }; |
| |
| } // namespace |
| |
| class NtpBackgroundServiceTest : public testing::Test { |
| public: |
| NtpBackgroundServiceTest() |
| : test_shared_loader_factory_( |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| &test_url_loader_factory_)), |
| application_locale_storage_( |
| std::make_unique<ApplicationLocaleStorage>()) {} |
| |
| void TearDown() override { |
| if (service_) { |
| service_->RemoveObserver(&observer_); |
| } |
| } |
| |
| void SetUpResponseWithNetworkSuccess( |
| const GURL& load_url, |
| const std::string& response = std::string()) { |
| test_url_loader_factory_.AddResponse(load_url.spec(), response); |
| } |
| |
| void SetUpResponseWithData(const GURL& load_url, |
| const std::string& response) { |
| test_url_loader_factory_.SetInterceptor(base::BindLambdaForTesting( |
| [&](const network::ResourceRequest& request) {})); |
| SetUpResponseWithNetworkSuccess(load_url, response); |
| } |
| |
| void SetUpResponseWithNetworkError(const GURL& load_url) { |
| test_url_loader_factory_.AddResponse(load_url.spec(), std::string(), |
| net::HTTP_NOT_FOUND); |
| } |
| |
| NtpBackgroundService* service() { |
| if (!service_) { |
| service_ = std::make_unique<NtpBackgroundService>( |
| application_locale_storage_.get(), test_shared_loader_factory_); |
| service_->AddObserver(&observer_); |
| } |
| return service_.get(); |
| } |
| |
| network::TestURLLoaderFactory* test_url_loader_factory() { |
| return &test_url_loader_factory_; |
| } |
| |
| protected: |
| // Required to run tests from UI and threads. |
| base::test::TaskEnvironment task_environment_; |
| |
| network::TestURLLoaderFactory test_url_loader_factory_; |
| scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; |
| std::unique_ptr<ApplicationLocaleStorage> application_locale_storage_; |
| MockNtpBackgroundServiceObserver observer_; |
| base::test::ScopedFeatureList feature_list_; |
| base::HistogramTester histogram_tester_; |
| std::unique_ptr<NtpBackgroundService> service_; |
| }; |
| |
| TEST_F(NtpBackgroundServiceTest, CollectionRequest) { |
| application_locale_storage_->Set("foo"); |
| |
| service()->FetchCollectionInfo(); |
| EXPECT_TRUE(base::test::RunUntil([&]() { |
| return test_url_loader_factory()->pending_requests()->size() == 1u; |
| })); |
| |
| std::string request_body(test_url_loader_factory() |
| ->pending_requests() |
| ->at(0) |
| .request.request_body->elements() |
| ->at(0) |
| .As<network::DataElementBytes>() |
| .AsStringPiece()); |
| ntp::background::GetCollectionsRequest collection_request; |
| EXPECT_TRUE(collection_request.ParseFromString(request_body)); |
| EXPECT_EQ("foo", collection_request.language()); |
| EXPECT_EQ(4, collection_request.filtering_label_size()); |
| EXPECT_EQ(GetFilteringLabel(), collection_request.filtering_label(0)); |
| EXPECT_EQ(base::StrCat({GetFilteringLabel(), ".M"}) + |
| version_info::GetMajorVersionNumber(), |
| collection_request.filtering_label(1)); |
| EXPECT_EQ(base::StrCat({GetFilteringLabel(), ".panorama"}), |
| collection_request.filtering_label(2)); |
| EXPECT_EQ(base::StrCat({GetFilteringLabel(), ".gm3"}), |
| collection_request.filtering_label(3)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, CollectionRequestWithFilteringLabel) { |
| application_locale_storage_->Set("foo"); |
| |
| service()->FetchCollectionInfo("test"); |
| EXPECT_TRUE(base::test::RunUntil([&]() { |
| return test_url_loader_factory()->pending_requests()->size() == 1u; |
| })); |
| |
| std::string request_body(test_url_loader_factory() |
| ->pending_requests() |
| ->at(0) |
| .request.request_body->elements() |
| ->at(0) |
| .As<network::DataElementBytes>() |
| .AsStringPiece()); |
| ntp::background::GetCollectionsRequest collection_request; |
| EXPECT_TRUE(collection_request.ParseFromString(request_body)); |
| EXPECT_EQ("foo", collection_request.language()); |
| EXPECT_EQ(4, collection_request.filtering_label_size()); |
| EXPECT_EQ("test", collection_request.filtering_label(0)); |
| EXPECT_EQ( |
| base::StrCat({"test", ".M"}) + version_info::GetMajorVersionNumber(), |
| collection_request.filtering_label(1)); |
| EXPECT_EQ(base::StrCat({"test", ".panorama"}), |
| collection_request.filtering_label(2)); |
| EXPECT_EQ(base::StrCat({"test", ".gm3"}), |
| collection_request.filtering_label(3)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, |
| CollectionRequestWithImageErrorDetectionEnabled) { |
| base::test::ScopedFeatureList scoped_feature_list; |
| scoped_feature_list.InitAndEnableFeature( |
| ntp_features::kNtpBackgroundImageErrorDetection); |
| application_locale_storage_->Set("foo"); |
| |
| service()->FetchCollectionInfo(); |
| EXPECT_TRUE(base::test::RunUntil([&]() { |
| return test_url_loader_factory()->pending_requests()->size() == 1u; |
| })); |
| |
| std::string request_body(test_url_loader_factory() |
| ->pending_requests() |
| ->at(0) |
| .request.request_body->elements() |
| ->at(0) |
| .As<network::DataElementBytes>() |
| .AsStringPiece()); |
| ntp::background::GetCollectionsRequest collection_request; |
| EXPECT_TRUE(collection_request.ParseFromString(request_body)); |
| EXPECT_EQ("foo", collection_request.language()); |
| EXPECT_EQ(5, collection_request.filtering_label_size()); |
| EXPECT_EQ(base::StrCat({GetFilteringLabel(), ".error_detection"}), |
| collection_request.filtering_label(4)); |
| EXPECT_EQ(base::StrCat({GetFilteringLabel(), ".M"}) + |
| version_info::GetMajorVersionNumber(), |
| collection_request.filtering_label(1)); |
| EXPECT_EQ(base::StrCat({GetFilteringLabel(), ".panorama"}), |
| collection_request.filtering_label(2)); |
| EXPECT_EQ(base::StrCat({GetFilteringLabel(), ".gm3"}), |
| collection_request.filtering_label(3)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, CollectionInfoNetworkError) { |
| SetUpResponseWithNetworkError(service()->GetCollectionsLoadURLForTesting()); |
| |
| ASSERT_TRUE(service()->collection_info().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionInfoAvailable).Times(1); |
| service()->FetchCollectionInfo(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(service()->collection_info().empty()); |
| EXPECT_EQ(service()->collection_error_info().error_type, |
| ErrorType::NET_ERROR); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, BadCollectionsResponse) { |
| SetUpResponseWithData(service()->GetCollectionsLoadURLForTesting(), |
| "bad serialized GetCollectionsResponse"); |
| |
| ASSERT_TRUE(service()->collection_info().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionInfoAvailable).Times(1); |
| service()->FetchCollectionInfo(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(service()->collection_info().empty()); |
| EXPECT_EQ(service()->collection_error_info().error_type, |
| ErrorType::SERVICE_ERROR); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, GoodCollectionsResponse) { |
| ntp::background::Collection collection; |
| collection.set_collection_id("shapes"); |
| collection.set_collection_name("Shapes"); |
| collection.add_preview()->set_image_url(kTestImageUrl); |
| ntp::background::GetCollectionsResponse response; |
| *response.add_collections() = collection; |
| std::string response_string; |
| response.SerializeToString(&response_string); |
| |
| SetUpResponseWithData(service()->GetCollectionsLoadURLForTesting(), |
| response_string); |
| |
| ASSERT_TRUE(service()->collection_info().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionInfoAvailable).Times(1); |
| service()->FetchCollectionInfo(); |
| base::RunLoop().RunUntilIdle(); |
| |
| CollectionInfo collection_info; |
| collection_info.collection_id = collection.collection_id(); |
| collection_info.collection_name = collection.collection_name(); |
| collection_info.preview_image_url = |
| GURL(collection.preview(0).image_url() + GetThumbnailImageOptions()); |
| |
| EXPECT_FALSE(service()->collection_info().empty()); |
| EXPECT_THAT(service()->collection_info().at(0), Eq(collection_info)); |
| EXPECT_EQ(service()->collection_error_info().error_type, ErrorType::NONE); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, BrokenCollectionPreviewImageHasNoReplacement) { |
| ntp::background::Collection collection; |
| collection.set_collection_id("shapes"); |
| collection.set_collection_name("Shapes"); |
| |
| // Add fake image to collection that produces a network error when accessed. |
| ntp::background::Image image; |
| image.set_asset_id(12345); |
| image.set_image_url("https://wallpapers.co/some_other_image"); |
| image.add_attribution()->set_text("different attribution text"); |
| ntp::background::GetImagesInCollectionResponse image_response; |
| *image_response.add_images() = image; |
| std::string image_response_string; |
| image_response.SerializeToString(&image_response_string); |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), |
| image_response_string); |
| SetUpResponseWithNetworkError( |
| GURL(image.image_url() + GetThumbnailImageOptions())); |
| |
| base::RunLoop run_loop; |
| auto replacement_image_callback = base::BindLambdaForTesting( |
| [&](const std::optional<GURL>& replacement_image_url) { |
| EXPECT_FALSE(replacement_image_url.has_value()); |
| run_loop.Quit(); |
| }); |
| service()->FetchReplacementCollectionPreviewImage( |
| collection.collection_id(), std::move(replacement_image_callback)); |
| run_loop.Run(); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, BrokenCollectionPreviewImageHasReplacement) { |
| ntp::background::Collection collection; |
| collection.set_collection_id("shapes"); |
| collection.set_collection_name("Shapes"); |
| |
| // Add image to collection that produces a network success when accessed. |
| ntp::background::Image image_1; |
| image_1.set_asset_id(12345); |
| image_1.set_image_url("https://wallpapers.co/some_image"); |
| image_1.add_attribution()->set_text("attribution text"); |
| ntp::background::GetImagesInCollectionResponse image_response; |
| *image_response.add_images() = image_1; |
| ntp::background::Image image_2; |
| image_2.set_asset_id(23451); |
| image_2.set_image_url("https://wallpapers.co/some_other_image"); |
| image_2.add_attribution()->set_text("different attribution text"); |
| *image_response.add_images() = image_2; |
| std::string image_response_string; |
| image_response.SerializeToString(&image_response_string); |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), |
| image_response_string); |
| SetUpResponseWithNetworkError( |
| GURL(image_1.image_url() + GetThumbnailImageOptions())); |
| SetUpResponseWithNetworkSuccess( |
| GURL(image_2.image_url() + GetThumbnailImageOptions())); |
| |
| base::RunLoop run_loop; |
| auto replacement_image_callback = base::BindLambdaForTesting( |
| [&](const std::optional<GURL>& replacement_image_url) { |
| EXPECT_TRUE(replacement_image_url.has_value()); |
| EXPECT_EQ(replacement_image_url.value(), |
| GURL(image_2.image_url() + GetThumbnailImageOptions())); |
| run_loop.Quit(); |
| }); |
| service()->FetchReplacementCollectionPreviewImage( |
| collection.collection_id(), std::move(replacement_image_callback)); |
| run_loop.Run(); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, CollectionImagesNetworkError) { |
| SetUpResponseWithNetworkError(service()->GetImagesURLForTesting()); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(1); |
| service()->FetchCollectionImageInfo("shapes"); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(service()->collection_images().empty()); |
| EXPECT_EQ(service()->collection_images_error_info().error_type, |
| ErrorType::NET_ERROR); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, BadCollectionImagesResponse) { |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), |
| "bad serialized GetImagesInCollectionResponse"); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(1); |
| service()->FetchCollectionImageInfo("shapes"); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(service()->collection_images().empty()); |
| EXPECT_EQ(service()->collection_images_error_info().error_type, |
| ErrorType::SERVICE_ERROR); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, ImageInCollectionHasNetworkError) { |
| ntp::background::Image image; |
| image.set_asset_id(12345); |
| image.set_image_url(kTestImageUrl); |
| image.add_attribution()->set_text("attribution text"); |
| image.set_action_url(kTestActionUrl); |
| ntp::background::GetImagesInCollectionResponse response; |
| *response.add_images() = image; |
| std::string response_string; |
| response.SerializeToString(&response_string); |
| |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), response_string); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(1); |
| service()->FetchCollectionImageInfo("shapes"); |
| base::RunLoop().RunUntilIdle(); |
| |
| CollectionImage collection_image; |
| collection_image.collection_id = "shapes"; |
| collection_image.asset_id = image.asset_id(); |
| collection_image.thumbnail_image_url = |
| GURL(image.image_url() + GetThumbnailImageOptions()); |
| collection_image.image_url = GURL(image.image_url() + GetImageOptions()); |
| collection_image.attribution.push_back(image.attribution(0).text()); |
| collection_image.attribution_action_url = GURL(image.action_url()); |
| |
| EXPECT_FALSE(service()->collection_images().empty()); |
| EXPECT_THAT(service()->collection_images().at(0), Eq(collection_image)); |
| EXPECT_EQ(service()->collection_images_error_info().error_type, |
| ErrorType::NONE); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, GoodCollectionImagesResponse) { |
| ntp::background::Image image; |
| image.set_asset_id(12345); |
| image.set_image_url(kTestImageUrl); |
| image.add_attribution()->set_text("attribution text"); |
| image.set_action_url(kTestActionUrl); |
| ntp::background::GetImagesInCollectionResponse response; |
| *response.add_images() = image; |
| std::string response_string; |
| response.SerializeToString(&response_string); |
| |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), response_string); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(1); |
| service()->FetchCollectionImageInfo("shapes"); |
| base::RunLoop().RunUntilIdle(); |
| |
| CollectionImage collection_image; |
| collection_image.collection_id = "shapes"; |
| collection_image.asset_id = image.asset_id(); |
| collection_image.thumbnail_image_url = |
| GURL(image.image_url() + GetThumbnailImageOptions()); |
| collection_image.image_url = GURL(image.image_url() + GetImageOptions()); |
| collection_image.attribution.push_back(image.attribution(0).text()); |
| collection_image.attribution_action_url = GURL(image.action_url()); |
| |
| EXPECT_FALSE(service()->collection_images().empty()); |
| EXPECT_THAT(service()->collection_images().at(0), Eq(collection_image)); |
| EXPECT_EQ(service()->collection_images_error_info().error_type, |
| ErrorType::NONE); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, CollectionImagesNetworkErrorWithCallback) { |
| SetUpResponseWithNetworkError(service()->GetImagesURLForTesting()); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(0); |
| |
| std::vector<CollectionImage> collection_images; |
| ErrorType error_type; |
| base::MockCallback<NtpBackgroundService::FetchCollectionImageCallback> |
| callback; |
| EXPECT_CALL(callback, Run(testing::_, testing::_)) |
| .Times(1) |
| .WillOnce(testing::DoAll(testing::SaveArg<0>(&collection_images), |
| testing::SaveArg<1>(&error_type))); |
| |
| service()->FetchCollectionImageInfo("shapes", callback.Get()); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(collection_images.empty()); |
| EXPECT_EQ(collection_images.size(), 0u); |
| EXPECT_EQ(error_type, ErrorType::NET_ERROR); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, BadCollectionImagesWithCallback) { |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), |
| "bad serialized GetImagesInCollectionResponse"); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(0); |
| |
| std::vector<CollectionImage> collection_images; |
| ErrorType error_type; |
| base::MockCallback<NtpBackgroundService::FetchCollectionImageCallback> |
| callback; |
| EXPECT_CALL(callback, Run(testing::_, testing::_)) |
| .Times(1) |
| .WillOnce(testing::DoAll(testing::SaveArg<0>(&collection_images), |
| testing::SaveArg<1>(&error_type))); |
| |
| service()->FetchCollectionImageInfo("shapes", callback.Get()); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(collection_images.empty()); |
| EXPECT_EQ(collection_images.size(), 0u); |
| EXPECT_EQ(error_type, ErrorType::SERVICE_ERROR); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, GoodCollectionImagesResponseWithCallback) { |
| ntp::background::Image image; |
| image.set_asset_id(12345); |
| image.set_image_url(kTestImageUrl); |
| image.add_attribution()->set_text("attribution text"); |
| image.set_action_url(kTestActionUrl); |
| ntp::background::GetImagesInCollectionResponse response; |
| *response.add_images() = image; |
| std::string response_string; |
| response.SerializeToString(&response_string); |
| |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), response_string); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(0); |
| |
| std::vector<CollectionImage> collection_images; |
| ErrorType error_type; |
| base::MockCallback<NtpBackgroundService::FetchCollectionImageCallback> |
| callback; |
| EXPECT_CALL(callback, Run(testing::_, testing::_)) |
| .Times(1) |
| .WillOnce(testing::DoAll(testing::SaveArg<0>(&collection_images), |
| testing::SaveArg<1>(&error_type))); |
| |
| service()->FetchCollectionImageInfo("shapes", callback.Get()); |
| base::RunLoop().RunUntilIdle(); |
| |
| std::string expected_image_url = |
| std::string(kTestImageUrl) + GetImageOptions(); |
| std::string expected_thumbnail_image_url = |
| std::string(kTestImageUrl) + GetThumbnailImageOptions(); |
| EXPECT_EQ(collection_images[0].image_url, GURL(expected_image_url)); |
| EXPECT_EQ(collection_images[0].thumbnail_image_url, |
| GURL(expected_thumbnail_image_url)); |
| EXPECT_EQ(collection_images[0].collection_id, "shapes"); |
| EXPECT_EQ(collection_images.size(), 1u); |
| EXPECT_FALSE(collection_images.empty()); |
| EXPECT_EQ(error_type, ErrorType::NONE); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, |
| MultipleGoodCollectionImagesResponseWithCallback) { |
| ntp::background::Image image; |
| image.set_asset_id(12345); |
| image.set_image_url(kTestImageUrl); |
| image.add_attribution()->set_text("attribution text"); |
| image.set_action_url(kTestActionUrl); |
| ntp::background::GetImagesInCollectionResponse response; |
| *response.add_images() = image; |
| std::string response_string; |
| response.SerializeToString(&response_string); |
| |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), response_string); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(0); |
| |
| std::vector<CollectionImage> first_collection_images; |
| ErrorType first_error_type; |
| base::MockCallback<NtpBackgroundService::FetchCollectionImageCallback> |
| first_callback; |
| EXPECT_CALL(first_callback, Run(testing::_, testing::_)) |
| .Times(1) |
| .WillOnce(testing::DoAll(testing::SaveArg<0>(&first_collection_images), |
| testing::SaveArg<1>(&first_error_type))); |
| |
| std::vector<CollectionImage> second_collection_images; |
| ErrorType second_error_type; |
| base::MockCallback<NtpBackgroundService::FetchCollectionImageCallback> |
| second_callback; |
| EXPECT_CALL(second_callback, Run(testing::_, testing::_)) |
| .Times(1) |
| .WillOnce(testing::DoAll(testing::SaveArg<0>(&second_collection_images), |
| testing::SaveArg<1>(&second_error_type))); |
| |
| service()->FetchCollectionImageInfo("shapes", first_callback.Get()); |
| service()->FetchCollectionImageInfo("art", second_callback.Get()); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(first_collection_images[0].collection_id, "shapes"); |
| EXPECT_EQ(first_collection_images.size(), 1u); |
| EXPECT_FALSE(first_collection_images.empty()); |
| EXPECT_EQ(first_error_type, ErrorType::NONE); |
| |
| EXPECT_EQ(second_collection_images[0].collection_id, "art"); |
| EXPECT_EQ(second_collection_images.size(), 1u); |
| EXPECT_FALSE(second_collection_images.empty()); |
| EXPECT_EQ(second_error_type, ErrorType::NONE); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, |
| CollectionImageInfoRequestsAreIgnoredIfAnotherIsInProgress) { |
| ntp::background::Collection collection; |
| collection.set_collection_id("shapes"); |
| collection.set_collection_name("Shapes"); |
| collection.add_preview()->set_image_url(kTestImageUrl); |
| ntp::background::GetCollectionsResponse collection_response; |
| *collection_response.add_collections() = collection; |
| std::string collection_response_string; |
| collection_response.SerializeToString(&collection_response_string); |
| |
| ntp::background::Image image; |
| image.set_asset_id(12345); |
| image.set_image_url(kTestImageUrl); |
| image.add_attribution()->set_text("attribution text"); |
| ntp::background::GetImagesInCollectionResponse image_response; |
| *image_response.add_images() = image; |
| std::string image_response_string; |
| image_response.SerializeToString(&image_response_string); |
| |
| SetUpResponseWithData(service()->GetCollectionsLoadURLForTesting(), |
| collection_response_string); |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), |
| image_response_string); |
| |
| ASSERT_TRUE(service()->collection_info().empty()); |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionInfoAvailable).Times(1); |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(1); |
| service()->FetchCollectionInfo(); |
| service()->FetchCollectionImageInfo("shapes"); |
| // Subsequent requests are ignored while the loader is in use. |
| service()->FetchCollectionImageInfo("colors"); |
| base::RunLoop().RunUntilIdle(); |
| |
| CollectionInfo collection_info; |
| collection_info.collection_id = collection.collection_id(); |
| collection_info.collection_name = collection.collection_name(); |
| collection_info.preview_image_url = |
| GURL(collection.preview(0).image_url() + GetThumbnailImageOptions()); |
| |
| CollectionImage collection_image; |
| collection_image.collection_id = "shapes"; |
| collection_image.asset_id = image.asset_id(); |
| collection_image.thumbnail_image_url = |
| GURL(image.image_url() + GetThumbnailImageOptions()); |
| collection_image.image_url = GURL(image.image_url() + GetImageOptions()); |
| collection_image.attribution.push_back(image.attribution(0).text()); |
| |
| EXPECT_FALSE(service()->collection_info().empty()); |
| EXPECT_THAT(service()->collection_info().at(0), Eq(collection_info)); |
| EXPECT_FALSE(service()->collection_images().empty()); |
| EXPECT_THAT(service()->collection_images().at(0), Eq(collection_image)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, |
| CollectionImageInfoCanBeSuccessfullyFetchedMultipleTimes) { |
| ntp::background::Image image; |
| image.set_image_url(kTestImageUrl); |
| ntp::background::GetImagesInCollectionResponse response; |
| *response.add_images() = image; |
| std::string response_string; |
| response.SerializeToString(&response_string); |
| |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), response_string); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(2); |
| service()->FetchCollectionImageInfo("shapes"); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(service()->collection_images().empty()); |
| EXPECT_THAT(service()->collection_images().at(0).collection_id, "shapes"); |
| |
| service()->FetchCollectionImageInfo("colors"); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_THAT(service()->collection_images().at(0).collection_id, "colors"); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, NextImageNetworkError) { |
| SetUpResponseWithNetworkError(service()->GetNextImageURLForTesting()); |
| |
| service()->FetchNextCollectionImage("shapes", std::nullopt); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_THAT(service()->next_image_error_info().error_type, |
| Eq(ErrorType::NET_ERROR)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, BadNextImageResponse) { |
| SetUpResponseWithData(service()->GetNextImageURLForTesting(), |
| "bad serialized GetImageFromCollectionResponse"); |
| |
| service()->FetchNextCollectionImage("shapes", std::nullopt); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_THAT(service()->next_image_error_info().error_type, |
| Eq(ErrorType::SERVICE_ERROR)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, GoodNextImageResponse) { |
| ntp::background::Image image; |
| image.set_asset_id(12345); |
| image.set_image_url(kTestImageUrl); |
| image.add_attribution()->set_text("attribution text"); |
| image.set_action_url(kTestActionUrl); |
| ntp::background::GetImageFromCollectionResponse response; |
| *response.mutable_image() = image; |
| response.set_resume_token("resume1"); |
| std::string response_string; |
| response.SerializeToString(&response_string); |
| |
| SetUpResponseWithData(service()->GetNextImageURLForTesting(), |
| response_string); |
| |
| // NOTE: the effect of the resume token in the request (i.e. prevent images |
| // from being repeated) cannot be verified in a unit test. |
| service()->FetchNextCollectionImage("shapes", "resume0"); |
| base::RunLoop().RunUntilIdle(); |
| |
| CollectionImage collection_image; |
| collection_image.collection_id = "shapes"; |
| collection_image.asset_id = image.asset_id(); |
| collection_image.thumbnail_image_url = |
| GURL(image.image_url() + GetThumbnailImageOptions()); |
| collection_image.image_url = GURL(image.image_url() + GetImageOptions()); |
| collection_image.attribution.push_back(image.attribution(0).text()); |
| collection_image.attribution_action_url = GURL(image.action_url()); |
| |
| EXPECT_THAT(service()->next_image(), Eq(collection_image)); |
| EXPECT_THAT(service()->next_image_resume_token(), Eq("resume1")); |
| |
| EXPECT_THAT(service()->collection_images_error_info().error_type, |
| Eq(ErrorType::NONE)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, MultipleRequestsNextImage) { |
| ntp::background::Image image; |
| image.set_asset_id(12345); |
| image.set_image_url(kTestImageUrl); |
| image.add_attribution()->set_text("attribution text"); |
| image.set_action_url(kTestActionUrl); |
| ntp::background::GetImageFromCollectionResponse response; |
| *response.mutable_image() = image; |
| response.set_resume_token("resume1"); |
| std::string response_string; |
| response.SerializeToString(&response_string); |
| |
| SetUpResponseWithData(service()->GetNextImageURLForTesting(), |
| response_string); |
| |
| // NOTE: the effect of the resume token in the request (i.e. prevent images |
| // from being repeated) cannot be verified in a unit test. |
| EXPECT_CALL(observer_, OnNextCollectionImageAvailable).Times(1); |
| service()->FetchNextCollectionImage("shapes", std::nullopt); |
| // Subsequent requests are ignored while the loader is in use. |
| service()->FetchNextCollectionImage("shapes", "resume0"); |
| base::RunLoop().RunUntilIdle(); |
| |
| CollectionImage collection_image; |
| collection_image.collection_id = "shapes"; |
| collection_image.asset_id = image.asset_id(); |
| collection_image.thumbnail_image_url = |
| GURL(image.image_url() + GetThumbnailImageOptions()); |
| collection_image.image_url = GURL(image.image_url() + GetImageOptions()); |
| collection_image.attribution.push_back(image.attribution(0).text()); |
| collection_image.attribution_action_url = GURL(image.action_url()); |
| |
| EXPECT_THAT(service()->next_image(), Eq(collection_image)); |
| EXPECT_THAT(service()->next_image_resume_token(), Eq("resume1")); |
| |
| EXPECT_THAT(service()->collection_images_error_info().error_type, |
| Eq(ErrorType::NONE)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, CheckValidAndInvalidBackdropUrls) { |
| ntp::background::Image image; |
| image.set_asset_id(12345); |
| image.set_image_url(kTestImageUrl); |
| image.add_attribution()->set_text("attribution text"); |
| image.set_action_url(kTestActionUrl); |
| ntp::background::GetImagesInCollectionResponse response; |
| *response.add_images() = image; |
| std::string response_string; |
| response.SerializeToString(&response_string); |
| |
| SetUpResponseWithData(service()->GetImagesURLForTesting(), response_string); |
| |
| ASSERT_TRUE(service()->collection_images().empty()); |
| |
| EXPECT_CALL(observer_, OnCollectionImagesAvailable).Times(1); |
| service()->FetchCollectionImageInfo("shapes"); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(service()->IsValidBackdropUrl( |
| GURL(image.image_url() + GetImageOptions()))); |
| EXPECT_FALSE(service()->IsValidBackdropUrl( |
| GURL("http://wallpapers.co/some_image=imageOptions"))); |
| EXPECT_FALSE(service()->IsValidBackdropUrl( |
| GURL("https://wallpapers.co/another_image"))); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, GetThumbnailUrl) { |
| const GURL kInvalidUrl("foo"); |
| const GURL kValidUrl("https://www.foo.com"); |
| const GURL kValidThumbnailUrl("https://www.foo.com/thumbnail"); |
| service()->AddValidBackdropUrlWithThumbnailForTesting(kValidUrl, |
| kValidThumbnailUrl); |
| |
| EXPECT_EQ(kValidThumbnailUrl, service()->GetThumbnailUrl(kValidUrl)); |
| EXPECT_EQ(GURL(), service()->GetThumbnailUrl(kInvalidUrl)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, OverrideBaseUrl) { |
| base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| "collections-base-url", "https://foo.com"); |
| service()->FetchCollectionInfo(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(1u, test_url_loader_factory()->pending_requests()->size()); |
| EXPECT_EQ("https://foo.com/cast/chromecast/home/wallpaper/collections?rt=b", |
| test_url_loader_factory()->pending_requests()->at(0).request.url); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, VerifyURLMetricsWithNetworkSuccess) { |
| SetUpResponseWithNetworkSuccess(GURL(kTestImageUrl)); |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.RequestLatency", 0); |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.StatusCode", 0); |
| |
| base::OnceCallback<void(int)> image_url_headers_received_callback = |
| base::BindLambdaForTesting([&](int headers_response_code) { |
| EXPECT_EQ(headers_response_code, net::HTTP_OK); |
| }); |
| service()->VerifyImageURL(GURL(kTestImageUrl), |
| std::move(image_url_headers_received_callback)); |
| base::RunLoop().RunUntilIdle(); |
| |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.RequestLatency", 1); |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.RequestLatency.Ok", 1); |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.StatusCode", 1); |
| ASSERT_EQ(1, histogram_tester_.GetBucketCount( |
| "NewTabPage.BackgroundService.Images.Headers.StatusCode", |
| net::HTTP_OK)); |
| } |
| |
| TEST_F(NtpBackgroundServiceTest, VerifyURLMetricsWithNetworkError) { |
| SetUpResponseWithNetworkError(GURL(kTestImageUrl)); |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.RequestLatency", 0); |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.StatusCode", 0); |
| |
| base::OnceCallback<void(int)> image_url_headers_received_callback = |
| base::BindLambdaForTesting([&](int headers_response_code) { |
| EXPECT_EQ(headers_response_code, net::HTTP_NOT_FOUND); |
| }); |
| service()->VerifyImageURL(GURL(kTestImageUrl), |
| std::move(image_url_headers_received_callback)); |
| base::RunLoop().RunUntilIdle(); |
| |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.RequestLatency", 1); |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.RequestLatency.NotFound", 1); |
| histogram_tester_.ExpectTotalCount( |
| "NewTabPage.BackgroundService.Images.Headers.StatusCode", 1); |
| ASSERT_EQ(1, histogram_tester_.GetBucketCount( |
| "NewTabPage.BackgroundService.Images.Headers.StatusCode", |
| net::HTTP_NOT_FOUND)); |
| } |