| Index: components/doodle/doodle_service_unittest.cc
|
| diff --git a/components/doodle/doodle_service_unittest.cc b/components/doodle/doodle_service_unittest.cc
|
| index 1fefbc10fca2f50071ab180006d1d76a568bab80..88ae97d2ee2f5e5aa87c31de10ee5721def8db56 100644
|
| --- a/components/doodle/doodle_service_unittest.cc
|
| +++ b/components/doodle/doodle_service_unittest.cc
|
| @@ -12,16 +12,26 @@
|
| #include "base/memory/ptr_util.h"
|
| #include "base/memory/ref_counted.h"
|
| #include "base/test/histogram_tester.h"
|
| +#include "base/test/mock_callback.h"
|
| #include "base/test/simple_test_tick_clock.h"
|
| #include "base/test/test_mock_time_task_runner.h"
|
| #include "base/threading/thread_task_runner_handle.h"
|
| #include "base/time/time.h"
|
| +#include "components/image_fetcher/core/image_fetcher.h"
|
| +#include "components/image_fetcher/core/request_metadata.h"
|
| #include "components/prefs/testing_pref_service.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| +#include "ui/gfx/geometry/size.h"
|
| +#include "ui/gfx/image/image.h"
|
| +#include "ui/gfx/image/image_unittest_util.h"
|
|
|
| +using image_fetcher::ImageFetcher;
|
| +using image_fetcher::RequestMetadata;
|
| +using testing::_;
|
| using testing::Eq;
|
| using testing::StrictMock;
|
| +using testing::Not;
|
|
|
| namespace doodle {
|
|
|
| @@ -60,10 +70,74 @@ class MockDoodleObserver : public DoodleService::Observer {
|
| MOCK_METHOD1(OnDoodleConfigRevalidated, void(bool));
|
| };
|
|
|
| +class FakeImageFetcher : public ImageFetcher {
|
| + public:
|
| + FakeImageFetcher() = default;
|
| + ~FakeImageFetcher() override = default;
|
| +
|
| + void SetImageFetcherDelegate(image_fetcher::ImageFetcherDelegate*) override {
|
| + NOTREACHED();
|
| + }
|
| +
|
| + void SetDataUseServiceName(DataUseServiceName) override {
|
| + // Ignored.
|
| + }
|
| +
|
| + void SetImageDownloadLimit(base::Optional<int64_t>) override {
|
| + // Ignored.
|
| + }
|
| +
|
| + void SetDesiredImageFrameSize(const gfx::Size&) override {
|
| + // Ignored.
|
| + }
|
| +
|
| + void StartOrQueueNetworkRequest(
|
| + const std::string& id,
|
| + const GURL& url,
|
| + const ImageFetcherCallback& callback) override {
|
| + // For simplicity, the fake doesn't support multiple concurrent requests.
|
| + DCHECK(!HasPendingRequest());
|
| +
|
| + pending_id_ = id;
|
| + pending_url_ = url;
|
| + pending_callback_ = callback;
|
| + }
|
| +
|
| + image_fetcher::ImageDecoder* GetImageDecoder() override {
|
| + NOTREACHED();
|
| + return nullptr;
|
| + }
|
| +
|
| + bool HasPendingRequest() const { return !pending_callback_.is_null(); }
|
| +
|
| + const GURL& pending_url() const { return pending_url_; }
|
| +
|
| + void RespondToPendingRequest(const gfx::Image& image) {
|
| + DCHECK(HasPendingRequest());
|
| +
|
| + RequestMetadata metadata;
|
| + metadata.http_response_code = 200;
|
| + pending_callback_.Run(pending_id_, image, metadata);
|
| +
|
| + pending_id_.clear();
|
| + pending_url_ = GURL();
|
| + pending_callback_.Reset();
|
| + }
|
| +
|
| + private:
|
| + std::string pending_id_;
|
| + GURL pending_url_;
|
| + ImageFetcherCallback pending_callback_;
|
| +};
|
| +
|
| DoodleConfig CreateConfig(DoodleType type) {
|
| return DoodleConfig(type, DoodleImage(GURL("https://doodle.com/image.jpg")));
|
| }
|
|
|
| +MATCHER(IsEmptyImage, "") {
|
| + return arg.IsEmpty();
|
| +}
|
| +
|
| } // namespace
|
|
|
| class DoodleServiceTest : public testing::Test {
|
| @@ -83,7 +157,20 @@ class DoodleServiceTest : public testing::Test {
|
| RecreateServiceWithZeroRefreshInterval();
|
| }
|
|
|
| - void DestroyService() { service_ = nullptr; }
|
| + void TearDown() override { DestroyService(); }
|
| +
|
| + void DestroyService() {
|
| + if (image_fetcher_) {
|
| + // Make sure we didn't receive an unexpected image request.
|
| + ASSERT_FALSE(image_fetcher_->HasPendingRequest());
|
| + }
|
| +
|
| + fetcher_ = nullptr;
|
| + expiry_timer_ = nullptr;
|
| + image_fetcher_ = nullptr;
|
| +
|
| + service_ = nullptr;
|
| + }
|
|
|
| void RecreateServiceWithZeroRefreshInterval() {
|
| RecreateService(/*min_refresh_interval=*/base::TimeDelta());
|
| @@ -97,14 +184,18 @@ class DoodleServiceTest : public testing::Test {
|
| auto fetcher = base::MakeUnique<FakeDoodleFetcher>();
|
| fetcher_ = fetcher.get();
|
|
|
| + auto image_fetcher = base::MakeUnique<FakeImageFetcher>();
|
| + image_fetcher_ = image_fetcher.get();
|
| +
|
| service_ = base::MakeUnique<DoodleService>(
|
| &pref_service_, std::move(fetcher), std::move(expiry_timer),
|
| task_runner_->GetMockClock(), task_runner_->GetMockTickClock(),
|
| - refresh_interval);
|
| + refresh_interval, std::move(image_fetcher));
|
| }
|
|
|
| DoodleService* service() { return service_.get(); }
|
| FakeDoodleFetcher* fetcher() { return fetcher_; }
|
| + FakeImageFetcher* image_fetcher() { return image_fetcher_; }
|
|
|
| base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); }
|
|
|
| @@ -120,6 +211,7 @@ class DoodleServiceTest : public testing::Test {
|
| // Weak, owned by the service.
|
| FakeDoodleFetcher* fetcher_;
|
| base::OneShotTimer* expiry_timer_;
|
| + FakeImageFetcher* image_fetcher_;
|
| };
|
|
|
| TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) {
|
| @@ -597,4 +689,55 @@ TEST_F(DoodleServiceTest, DoesNotRecordMetricsWhenConfigExpires) {
|
| histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0);
|
| }
|
|
|
| +TEST_F(DoodleServiceTest, GetImageWithEmptyConfigReturnsImmediately) {
|
| + ASSERT_THAT(service()->config(), Eq(base::nullopt));
|
| +
|
| + base::MockCallback<DoodleService::ImageCallback> callback;
|
| + EXPECT_CALL(callback, Run(IsEmptyImage()));
|
| +
|
| + service()->GetImage(callback.Get());
|
| +}
|
| +
|
| +TEST_F(DoodleServiceTest, GetImageFetchesLargeImage) {
|
| + service()->Refresh();
|
| + DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
|
| + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
|
| + base::TimeDelta::FromHours(1), config);
|
| + ASSERT_THAT(service()->config(), Eq(config));
|
| +
|
| + base::MockCallback<DoodleService::ImageCallback> callback;
|
| + service()->GetImage(callback.Get());
|
| +
|
| + EXPECT_EQ(config.large_image.url, image_fetcher()->pending_url());
|
| +
|
| + EXPECT_CALL(callback, Run(Not(IsEmptyImage())));
|
| + gfx::Image image = gfx::test::CreateImage(1, 1);
|
| + ASSERT_TRUE(image_fetcher()->HasPendingRequest());
|
| + image_fetcher()->RespondToPendingRequest(image);
|
| +}
|
| +
|
| +TEST_F(DoodleServiceTest, GetImageFetchesCTAImage) {
|
| + service()->Refresh();
|
| + DoodleConfig config = CreateConfig(DoodleType::SIMPLE);
|
| + // Set a CTA image, which should take precedence over the regular image.
|
| + config.large_image.is_animated_gif = true;
|
| + config.large_cta_image = DoodleImage(GURL("https://doodle.com/cta.jpg"));
|
| + config.large_cta_image->is_cta = true;
|
| + fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE,
|
| + base::TimeDelta::FromHours(1), config);
|
| + ASSERT_THAT(service()->config(), Eq(config));
|
| +
|
| + base::MockCallback<DoodleService::ImageCallback> callback;
|
| + service()->GetImage(callback.Get());
|
| +
|
| + // If the doodle has a CTA image, that should loaded instead of the regular
|
| + // large image.
|
| + EXPECT_EQ(config.large_cta_image->url, image_fetcher()->pending_url());
|
| +
|
| + EXPECT_CALL(callback, Run(Not(IsEmptyImage())));
|
| + gfx::Image image = gfx::test::CreateImage(1, 1);
|
| + ASSERT_TRUE(image_fetcher()->HasPendingRequest());
|
| + image_fetcher()->RespondToPendingRequest(image);
|
| +}
|
| +
|
| } // namespace doodle
|
|
|