OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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/doodle/doodle_service.h" | 5 #include "components/doodle/doodle_service.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
13 #include "base/memory/ref_counted.h" | 13 #include "base/memory/ref_counted.h" |
14 #include "base/test/histogram_tester.h" | 14 #include "base/test/histogram_tester.h" |
15 #include "base/test/mock_callback.h" | |
15 #include "base/test/simple_test_tick_clock.h" | 16 #include "base/test/simple_test_tick_clock.h" |
16 #include "base/test/test_mock_time_task_runner.h" | 17 #include "base/test/test_mock_time_task_runner.h" |
17 #include "base/threading/thread_task_runner_handle.h" | 18 #include "base/threading/thread_task_runner_handle.h" |
18 #include "base/time/time.h" | 19 #include "base/time/time.h" |
20 #include "components/image_fetcher/core/image_fetcher.h" | |
21 #include "components/image_fetcher/core/request_metadata.h" | |
19 #include "components/prefs/testing_pref_service.h" | 22 #include "components/prefs/testing_pref_service.h" |
20 #include "testing/gmock/include/gmock/gmock.h" | 23 #include "testing/gmock/include/gmock/gmock.h" |
21 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
25 #include "ui/gfx/geometry/size.h" | |
26 #include "ui/gfx/image/image.h" | |
27 #include "ui/gfx/image/image_unittest_util.h" | |
22 | 28 |
29 using image_fetcher::ImageFetcher; | |
30 using image_fetcher::RequestMetadata; | |
31 using testing::_; | |
23 using testing::Eq; | 32 using testing::Eq; |
24 using testing::StrictMock; | 33 using testing::StrictMock; |
34 using testing::Not; | |
25 | 35 |
26 namespace doodle { | 36 namespace doodle { |
27 | 37 |
28 namespace { | 38 namespace { |
29 | 39 |
30 class FakeDoodleFetcher : public DoodleFetcher { | 40 class FakeDoodleFetcher : public DoodleFetcher { |
31 public: | 41 public: |
32 FakeDoodleFetcher() = default; | 42 FakeDoodleFetcher() = default; |
33 ~FakeDoodleFetcher() override = default; | 43 ~FakeDoodleFetcher() override = default; |
34 | 44 |
(...skipping 18 matching lines...) Expand all Loading... | |
53 std::vector<FinishedCallback> callbacks_; | 63 std::vector<FinishedCallback> callbacks_; |
54 }; | 64 }; |
55 | 65 |
56 class MockDoodleObserver : public DoodleService::Observer { | 66 class MockDoodleObserver : public DoodleService::Observer { |
57 public: | 67 public: |
58 MOCK_METHOD1(OnDoodleConfigUpdated, | 68 MOCK_METHOD1(OnDoodleConfigUpdated, |
59 void(const base::Optional<DoodleConfig>&)); | 69 void(const base::Optional<DoodleConfig>&)); |
60 MOCK_METHOD1(OnDoodleConfigRevalidated, void(bool)); | 70 MOCK_METHOD1(OnDoodleConfigRevalidated, void(bool)); |
61 }; | 71 }; |
62 | 72 |
73 class FakeImageFetcher : public ImageFetcher { | |
74 public: | |
75 FakeImageFetcher() = default; | |
76 ~FakeImageFetcher() override { | |
77 // To make sure we didn't receive an unexpected image request. | |
78 CHECK(!HasPendingRequest()); | |
fhorschig
2017/05/15 13:54:35
s/CHECK/DCHECK?
Also: do we really want a crash he
Marc Treib
2017/05/15 14:25:22
CHECK or DCHECK doesn't really make a difference,
| |
79 } | |
80 | |
81 void SetImageFetcherDelegate(image_fetcher::ImageFetcherDelegate*) override { | |
fhorschig
2017/05/15 13:54:35
Why not "// Ignored"?
(I am not sure, a test shoul
Marc Treib
2017/05/15 14:25:22
Well, if someone calls this, then they expect some
| |
82 NOTREACHED(); | |
83 } | |
84 | |
85 void SetDataUseServiceName(DataUseServiceName) override { | |
86 // Ignored. | |
87 } | |
88 | |
89 void SetImageDownloadLimit(base::Optional<int64_t>) override { | |
90 // Ignored. | |
91 } | |
92 | |
93 void SetDesiredImageFrameSize(const gfx::Size&) override { NOTREACHED(); } | |
fhorschig
2017/05/15 13:54:35
Again, why not "// Ignored"?
Marc Treib
2017/05/15 14:25:22
Eh.. same argument as above, though I guess here i
| |
94 | |
95 void StartOrQueueNetworkRequest( | |
96 const std::string& id, | |
97 const GURL& url, | |
98 const ImageFetcherCallback& callback) override { | |
99 // For simplicity, the fake doesn't support multiple concurrent requests. | |
100 CHECK(!HasPendingRequest()); | |
fhorschig
2017/05/15 13:54:35
nit: s/CHECK/DCHECK?
Marc Treib
2017/05/15 14:25:22
Done.
| |
101 | |
102 pending_id_ = id; | |
103 pending_url_ = url; | |
104 pending_callback_ = callback; | |
105 } | |
106 | |
107 image_fetcher::ImageDecoder* GetImageDecoder() override { | |
108 NOTREACHED(); | |
109 return nullptr; | |
110 } | |
111 | |
112 bool HasPendingRequest() const { return !pending_callback_.is_null(); } | |
113 | |
114 const GURL& pending_url() const { return pending_url_; } | |
115 | |
116 void RespondToPendingRequest(const gfx::Image& image) { | |
117 CHECK(HasPendingRequest()); | |
fhorschig
2017/05/15 13:54:35
nit: s/CHECK/DCHECK?
Marc Treib
2017/05/15 14:25:22
Done.
| |
118 | |
119 RequestMetadata metadata; | |
120 metadata.http_response_code = 200; | |
121 pending_callback_.Run(pending_id_, image, metadata); | |
122 | |
123 pending_id_.clear(); | |
124 pending_url_ = GURL(); | |
125 pending_callback_.Reset(); | |
126 } | |
127 | |
128 private: | |
129 std::string pending_id_; | |
130 GURL pending_url_; | |
131 ImageFetcherCallback pending_callback_; | |
132 }; | |
133 | |
63 DoodleConfig CreateConfig(DoodleType type) { | 134 DoodleConfig CreateConfig(DoodleType type) { |
64 return DoodleConfig(type, DoodleImage(GURL("https://doodle.com/image.jpg"))); | 135 return DoodleConfig(type, DoodleImage(GURL("https://doodle.com/image.jpg"))); |
65 } | 136 } |
66 | 137 |
138 MATCHER(IsEmptyImage, "") { | |
139 return arg.IsEmpty(); | |
140 } | |
141 | |
67 } // namespace | 142 } // namespace |
68 | 143 |
69 class DoodleServiceTest : public testing::Test { | 144 class DoodleServiceTest : public testing::Test { |
70 public: | 145 public: |
71 DoodleServiceTest() | 146 DoodleServiceTest() |
72 : task_runner_(new base::TestMockTimeTaskRunner()), | 147 : task_runner_(new base::TestMockTimeTaskRunner()), |
73 task_runner_handle_(task_runner_), | 148 task_runner_handle_(task_runner_), |
74 tick_clock_(task_runner_->GetMockTickClock()), | 149 tick_clock_(task_runner_->GetMockTickClock()), |
75 fetcher_(nullptr), | 150 fetcher_(nullptr), |
76 expiry_timer_(nullptr) { | 151 expiry_timer_(nullptr) { |
77 DoodleService::RegisterProfilePrefs(pref_service_.registry()); | 152 DoodleService::RegisterProfilePrefs(pref_service_.registry()); |
78 | 153 |
79 task_runner_->FastForwardBy(base::TimeDelta::FromHours(12345)); | 154 task_runner_->FastForwardBy(base::TimeDelta::FromHours(12345)); |
80 | 155 |
81 // Set the minimum refresh interval to 0 by default, so tests don't have to | 156 // Set the minimum refresh interval to 0 by default, so tests don't have to |
82 // worry about it. The tests that care set it explicitly. | 157 // worry about it. The tests that care set it explicitly. |
83 RecreateServiceWithZeroRefreshInterval(); | 158 RecreateServiceWithZeroRefreshInterval(); |
84 } | 159 } |
85 | 160 |
86 void DestroyService() { service_ = nullptr; } | 161 void DestroyService() { |
162 fetcher_ = nullptr; | |
163 expiry_timer_ = nullptr; | |
164 image_fetcher_ = nullptr; | |
fhorschig
2017/05/15 13:54:35
This could be a good place to ASSERT HasPendingReq
Marc Treib
2017/05/15 14:25:22
Yup, moved the ASSERT here. IMO the name is fine t
| |
165 | |
166 service_ = nullptr; | |
167 } | |
87 | 168 |
88 void RecreateServiceWithZeroRefreshInterval() { | 169 void RecreateServiceWithZeroRefreshInterval() { |
89 RecreateService(/*min_refresh_interval=*/base::TimeDelta()); | 170 RecreateService(/*min_refresh_interval=*/base::TimeDelta()); |
90 } | 171 } |
91 | 172 |
92 void RecreateService(base::Optional<base::TimeDelta> refresh_interval) { | 173 void RecreateService(base::Optional<base::TimeDelta> refresh_interval) { |
93 auto expiry_timer = base::MakeUnique<base::OneShotTimer>(tick_clock_.get()); | 174 auto expiry_timer = base::MakeUnique<base::OneShotTimer>(tick_clock_.get()); |
94 expiry_timer->SetTaskRunner(task_runner_); | 175 expiry_timer->SetTaskRunner(task_runner_); |
95 expiry_timer_ = expiry_timer.get(); | 176 expiry_timer_ = expiry_timer.get(); |
96 | 177 |
97 auto fetcher = base::MakeUnique<FakeDoodleFetcher>(); | 178 auto fetcher = base::MakeUnique<FakeDoodleFetcher>(); |
98 fetcher_ = fetcher.get(); | 179 fetcher_ = fetcher.get(); |
99 | 180 |
181 auto image_fetcher = base::MakeUnique<FakeImageFetcher>(); | |
182 image_fetcher_ = image_fetcher.get(); | |
183 | |
100 service_ = base::MakeUnique<DoodleService>( | 184 service_ = base::MakeUnique<DoodleService>( |
101 &pref_service_, std::move(fetcher), std::move(expiry_timer), | 185 &pref_service_, std::move(fetcher), std::move(expiry_timer), |
102 task_runner_->GetMockClock(), task_runner_->GetMockTickClock(), | 186 task_runner_->GetMockClock(), task_runner_->GetMockTickClock(), |
103 refresh_interval); | 187 refresh_interval, std::move(image_fetcher)); |
104 } | 188 } |
105 | 189 |
106 DoodleService* service() { return service_.get(); } | 190 DoodleService* service() { return service_.get(); } |
107 FakeDoodleFetcher* fetcher() { return fetcher_; } | 191 FakeDoodleFetcher* fetcher() { return fetcher_; } |
192 FakeImageFetcher* image_fetcher() { return image_fetcher_; } | |
108 | 193 |
109 base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); } | 194 base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); } |
110 | 195 |
111 private: | 196 private: |
112 TestingPrefServiceSimple pref_service_; | 197 TestingPrefServiceSimple pref_service_; |
113 | 198 |
114 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; | 199 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
115 base::ThreadTaskRunnerHandle task_runner_handle_; | 200 base::ThreadTaskRunnerHandle task_runner_handle_; |
116 std::unique_ptr<base::TickClock> tick_clock_; | 201 std::unique_ptr<base::TickClock> tick_clock_; |
117 | 202 |
118 std::unique_ptr<DoodleService> service_; | 203 std::unique_ptr<DoodleService> service_; |
119 | 204 |
120 // Weak, owned by the service. | 205 // Weak, owned by the service. |
121 FakeDoodleFetcher* fetcher_; | 206 FakeDoodleFetcher* fetcher_; |
122 base::OneShotTimer* expiry_timer_; | 207 base::OneShotTimer* expiry_timer_; |
208 FakeImageFetcher* image_fetcher_; | |
123 }; | 209 }; |
124 | 210 |
125 TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) { | 211 TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) { |
126 ASSERT_THAT(service()->config(), Eq(base::nullopt)); | 212 ASSERT_THAT(service()->config(), Eq(base::nullopt)); |
127 | 213 |
128 // Request a refresh of the doodle config. | 214 // Request a refresh of the doodle config. |
129 service()->Refresh(); | 215 service()->Refresh(); |
130 // The request should have arrived at the fetcher. | 216 // The request should have arrived at the fetcher. |
131 EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); | 217 EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); |
132 | 218 |
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
590 | 676 |
591 // Fast-forward time so that the config expires. | 677 // Fast-forward time so that the config expires. |
592 task_runner()->FastForwardBy(base::TimeDelta::FromHours(1)); | 678 task_runner()->FastForwardBy(base::TimeDelta::FromHours(1)); |
593 ASSERT_THAT(service()->config(), Eq(base::nullopt)); | 679 ASSERT_THAT(service()->config(), Eq(base::nullopt)); |
594 | 680 |
595 // This should not have resulted in any metrics being emitted. | 681 // This should not have resulted in any metrics being emitted. |
596 histograms.ExpectTotalCount("Doodle.ConfigDownloadOutcome", 0); | 682 histograms.ExpectTotalCount("Doodle.ConfigDownloadOutcome", 0); |
597 histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0); | 683 histograms.ExpectTotalCount("Doodle.ConfigDownloadTime", 0); |
598 } | 684 } |
599 | 685 |
686 TEST_F(DoodleServiceTest, GetImageWithEmptyConfigReturnsImmediately) { | |
687 ASSERT_THAT(service()->config(), Eq(base::nullopt)); | |
688 | |
689 base::MockCallback<DoodleService::ImageCallback> callback; | |
690 EXPECT_CALL(callback, Run(IsEmptyImage())); | |
691 | |
692 service()->GetImage(callback.Get()); | |
fhorschig
2017/05/15 13:54:35
ASSERT_FALSE(HasPendingRequest) might ensure this
Marc Treib
2017/05/15 14:25:22
Er.. what?
Anyway, that assert happens during Tea
| |
693 } | |
694 | |
695 TEST_F(DoodleServiceTest, GetImageFetchesLargeImage) { | |
696 service()->Refresh(); | |
697 DoodleConfig config = CreateConfig(DoodleType::SIMPLE); | |
698 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, | |
699 base::TimeDelta::FromHours(1), config); | |
700 ASSERT_THAT(service()->config(), Eq(config)); | |
701 | |
702 base::MockCallback<DoodleService::ImageCallback> callback; | |
703 service()->GetImage(callback.Get()); | |
704 | |
705 EXPECT_EQ(config.large_image.url, image_fetcher()->pending_url()); | |
706 | |
707 EXPECT_CALL(callback, Run(Not(IsEmptyImage()))); | |
708 gfx::Image image = gfx::test::CreateImage(1, 1); | |
709 image_fetcher()->RespondToPendingRequest(image); | |
fhorschig
2017/05/15 13:54:35
ASSERT_TRUE(HasPendingRequest) before that would h
Marc Treib
2017/05/15 14:25:22
Done.
| |
710 } | |
711 | |
712 TEST_F(DoodleServiceTest, GetImageFetchesCTAImage) { | |
713 service()->Refresh(); | |
714 DoodleConfig config = CreateConfig(DoodleType::SIMPLE); | |
715 // Set a CTA image, which should take precedence over the regular image. | |
716 config.large_image.is_animated_gif = true; | |
717 config.large_cta_image = DoodleImage(GURL("https://doodle.com/cta.jpg")); | |
718 config.large_cta_image->is_cta = true; | |
719 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, | |
720 base::TimeDelta::FromHours(1), config); | |
721 ASSERT_THAT(service()->config(), Eq(config)); | |
722 | |
723 base::MockCallback<DoodleService::ImageCallback> callback; | |
724 service()->GetImage(callback.Get()); | |
725 | |
726 // If the doodle has a CTA image, that should loaded instead of the regular | |
727 // large image. | |
728 EXPECT_EQ(config.large_cta_image->url, image_fetcher()->pending_url()); | |
729 | |
730 EXPECT_CALL(callback, Run(Not(IsEmptyImage()))); | |
731 gfx::Image image = gfx::test::CreateImage(1, 1); | |
732 image_fetcher()->RespondToPendingRequest(image); | |
fhorschig
2017/05/15 13:54:35
again ASSERT_FALSE(HasPendingRequest)?
Marc Treib
2017/05/15 14:25:22
ASSERT_TRUE :) but done.
| |
733 } | |
734 | |
600 } // namespace doodle | 735 } // namespace doodle |
OLD | NEW |