| 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/simple_test_tick_clock.h" | 14 #include "base/test/simple_test_tick_clock.h" |
| 15 #include "base/test/test_mock_time_task_runner.h" | 15 #include "base/test/test_mock_time_task_runner.h" |
| 16 #include "base/threading/thread_task_runner_handle.h" | 16 #include "base/threading/thread_task_runner_handle.h" |
| 17 #include "base/time/time.h" | 17 #include "base/time/time.h" |
| 18 #include "components/prefs/testing_pref_service.h" |
| 18 #include "testing/gmock/include/gmock/gmock.h" | 19 #include "testing/gmock/include/gmock/gmock.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 21 |
| 21 using testing::Eq; | 22 using testing::Eq; |
| 22 using testing::StrictMock; | 23 using testing::StrictMock; |
| 23 | 24 |
| 24 namespace doodle { | 25 namespace doodle { |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 57 | 58 |
| 58 DoodleConfig CreateConfig(DoodleType type) { | 59 DoodleConfig CreateConfig(DoodleType type) { |
| 59 return DoodleConfig(type, DoodleImage(GURL("https://doodle.com/image.jpg"))); | 60 return DoodleConfig(type, DoodleImage(GURL("https://doodle.com/image.jpg"))); |
| 60 } | 61 } |
| 61 | 62 |
| 62 } // namespace | 63 } // namespace |
| 63 | 64 |
| 64 class DoodleServiceTest : public testing::Test { | 65 class DoodleServiceTest : public testing::Test { |
| 65 public: | 66 public: |
| 66 DoodleServiceTest() | 67 DoodleServiceTest() |
| 67 : fetcher_(nullptr), | 68 : task_runner_(new base::TestMockTimeTaskRunner()), |
| 68 task_runner_(new base::TestMockTimeTaskRunner()), | |
| 69 task_runner_handle_(task_runner_), | 69 task_runner_handle_(task_runner_), |
| 70 clock_(task_runner_->GetMockClock()), |
| 70 tick_clock_(task_runner_->GetMockTickClock()), | 71 tick_clock_(task_runner_->GetMockTickClock()), |
| 72 fetcher_(nullptr), |
| 71 expiry_timer_(nullptr) { | 73 expiry_timer_(nullptr) { |
| 74 DoodleService::RegisterProfilePrefs(pref_service_.registry()); |
| 75 |
| 72 task_runner_->FastForwardBy(base::TimeDelta::FromHours(12345)); | 76 task_runner_->FastForwardBy(base::TimeDelta::FromHours(12345)); |
| 73 | 77 |
| 78 RecreateService(); |
| 79 } |
| 80 |
| 81 void DestroyService() { service_ = nullptr; } |
| 82 |
| 83 void RecreateService() { |
| 74 auto expiry_timer = base::MakeUnique<base::OneShotTimer>(tick_clock_.get()); | 84 auto expiry_timer = base::MakeUnique<base::OneShotTimer>(tick_clock_.get()); |
| 75 expiry_timer->SetTaskRunner(task_runner_); | 85 expiry_timer->SetTaskRunner(task_runner_); |
| 76 expiry_timer_ = expiry_timer.get(); | 86 expiry_timer_ = expiry_timer.get(); |
| 77 | 87 |
| 78 auto fetcher = base::MakeUnique<FakeDoodleFetcher>(); | 88 auto fetcher = base::MakeUnique<FakeDoodleFetcher>(); |
| 79 fetcher_ = fetcher.get(); | 89 fetcher_ = fetcher.get(); |
| 80 | 90 |
| 81 service_ = base::MakeUnique<DoodleService>(std::move(fetcher), | 91 service_ = |
| 82 std::move(expiry_timer)); | 92 base::MakeUnique<DoodleService>(&pref_service_, std::move(fetcher), |
| 93 std::move(expiry_timer), clock_.get()); |
| 83 } | 94 } |
| 84 | 95 |
| 85 DoodleService* service() { return service_.get(); } | 96 DoodleService* service() { return service_.get(); } |
| 86 FakeDoodleFetcher* fetcher() { return fetcher_; } | 97 FakeDoodleFetcher* fetcher() { return fetcher_; } |
| 87 | 98 |
| 88 base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); } | 99 base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); } |
| 89 | 100 |
| 90 private: | 101 private: |
| 91 // Weak, owned by the service. | 102 TestingPrefServiceSimple pref_service_; |
| 92 FakeDoodleFetcher* fetcher_; | |
| 93 | 103 |
| 94 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; | 104 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
| 95 base::ThreadTaskRunnerHandle task_runner_handle_; | 105 base::ThreadTaskRunnerHandle task_runner_handle_; |
| 106 std::unique_ptr<base::Clock> clock_; |
| 96 std::unique_ptr<base::TickClock> tick_clock_; | 107 std::unique_ptr<base::TickClock> tick_clock_; |
| 97 // Weak, owned by the service. | |
| 98 base::OneShotTimer* expiry_timer_; | |
| 99 | 108 |
| 100 std::unique_ptr<DoodleService> service_; | 109 std::unique_ptr<DoodleService> service_; |
| 110 |
| 111 // Weak, owned by the service. |
| 112 FakeDoodleFetcher* fetcher_; |
| 113 base::OneShotTimer* expiry_timer_; |
| 101 }; | 114 }; |
| 102 | 115 |
| 103 TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) { | 116 TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) { |
| 104 ASSERT_THAT(service()->config(), Eq(base::nullopt)); | 117 ASSERT_THAT(service()->config(), Eq(base::nullopt)); |
| 105 | 118 |
| 106 // Request a refresh of the doodle config. | 119 // Request a refresh of the doodle config. |
| 107 service()->Refresh(); | 120 service()->Refresh(); |
| 108 // The request should have arrived at the fetcher. | 121 // The request should have arrived at the fetcher. |
| 109 EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); | 122 EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); |
| 110 | 123 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 124 // Serve it with a different config. | 137 // Serve it with a different config. |
| 125 DoodleConfig other_config = CreateConfig(DoodleType::SLIDESHOW); | 138 DoodleConfig other_config = CreateConfig(DoodleType::SLIDESHOW); |
| 126 DCHECK(config != other_config); | 139 DCHECK(config != other_config); |
| 127 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, | 140 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 128 base::TimeDelta::FromHours(1), other_config); | 141 base::TimeDelta::FromHours(1), other_config); |
| 129 | 142 |
| 130 // The config should have been updated. | 143 // The config should have been updated. |
| 131 EXPECT_THAT(service()->config(), Eq(other_config)); | 144 EXPECT_THAT(service()->config(), Eq(other_config)); |
| 132 } | 145 } |
| 133 | 146 |
| 147 TEST_F(DoodleServiceTest, PersistsConfig) { |
| 148 // Load some doodle config. |
| 149 service()->Refresh(); |
| 150 DoodleConfig config = CreateConfig(DoodleType::SIMPLE); |
| 151 config.large_image.url = GURL("https://doodle.com/doodle.jpg"); |
| 152 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 153 base::TimeDelta::FromHours(1), config); |
| 154 ASSERT_THAT(service()->config(), Eq(config)); |
| 155 |
| 156 // Re-create the service. It should have persisted the config, and load it |
| 157 // again automatically. |
| 158 RecreateService(); |
| 159 EXPECT_THAT(service()->config(), Eq(config)); |
| 160 } |
| 161 |
| 162 TEST_F(DoodleServiceTest, PersistsExpiryDate) { |
| 163 // Load some doodle config. |
| 164 service()->Refresh(); |
| 165 DoodleConfig config = CreateConfig(DoodleType::SIMPLE); |
| 166 config.large_image.url = GURL("https://doodle.com/doodle.jpg"); |
| 167 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 168 base::TimeDelta::FromHours(1), config); |
| 169 ASSERT_THAT(service()->config(), Eq(config)); |
| 170 |
| 171 // Destroy the service, and let some time pass. |
| 172 DestroyService(); |
| 173 task_runner()->FastForwardBy(base::TimeDelta::FromMinutes(15)); |
| 174 |
| 175 // Remove the abandoned expiry task from the task runner. |
| 176 ASSERT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u)); |
| 177 task_runner()->ClearPendingTasks(); |
| 178 |
| 179 // Re-create the service. The persisted config should have been loaded again. |
| 180 RecreateService(); |
| 181 EXPECT_THAT(service()->config(), Eq(config)); |
| 182 |
| 183 // Its time-to-live should have been updated. |
| 184 EXPECT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u)); |
| 185 EXPECT_THAT(task_runner()->NextPendingTaskDelay(), |
| 186 Eq(base::TimeDelta::FromMinutes(45))); |
| 187 } |
| 188 |
| 189 TEST_F(DoodleServiceTest, PersistedConfigExpires) { |
| 190 // Load some doodle config. |
| 191 service()->Refresh(); |
| 192 DoodleConfig config = CreateConfig(DoodleType::SIMPLE); |
| 193 config.large_image.url = GURL("https://doodle.com/doodle.jpg"); |
| 194 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 195 base::TimeDelta::FromHours(1), config); |
| 196 ASSERT_THAT(service()->config(), Eq(config)); |
| 197 |
| 198 // Destroy the service, and let enough time pass so that the config expires. |
| 199 DestroyService(); |
| 200 task_runner()->FastForwardBy(base::TimeDelta::FromHours(1)); |
| 201 |
| 202 // Re-create the service. The persisted config should have been discarded |
| 203 // because it is expired. |
| 204 RecreateService(); |
| 205 EXPECT_THAT(service()->config(), Eq(base::nullopt)); |
| 206 } |
| 207 |
| 134 TEST_F(DoodleServiceTest, CallsObserverOnConfigReceived) { | 208 TEST_F(DoodleServiceTest, CallsObserverOnConfigReceived) { |
| 135 StrictMock<MockDoodleObserver> observer; | 209 StrictMock<MockDoodleObserver> observer; |
| 136 service()->AddObserver(&observer); | 210 service()->AddObserver(&observer); |
| 137 | 211 |
| 138 ASSERT_THAT(service()->config(), Eq(base::nullopt)); | 212 ASSERT_THAT(service()->config(), Eq(base::nullopt)); |
| 139 | 213 |
| 140 // Request a refresh of the doodle config. | 214 // Request a refresh of the doodle config. |
| 141 service()->Refresh(); | 215 service()->Refresh(); |
| 142 // The request should have arrived at the fetcher. | 216 // The request should have arrived at the fetcher. |
| 143 ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); | 217 ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 | 303 |
| 230 TEST_F(DoodleServiceTest, CallsObserverWhenConfigExpires) { | 304 TEST_F(DoodleServiceTest, CallsObserverWhenConfigExpires) { |
| 231 // Load some doodle config. | 305 // Load some doodle config. |
| 232 service()->Refresh(); | 306 service()->Refresh(); |
| 233 DoodleConfig config = CreateConfig(DoodleType::SIMPLE); | 307 DoodleConfig config = CreateConfig(DoodleType::SIMPLE); |
| 234 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, | 308 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 235 base::TimeDelta::FromHours(1), config); | 309 base::TimeDelta::FromHours(1), config); |
| 236 ASSERT_THAT(service()->config(), Eq(config)); | 310 ASSERT_THAT(service()->config(), Eq(config)); |
| 237 | 311 |
| 238 // Make sure the task arrived at the timer's task runner. | 312 // Make sure the task arrived at the timer's task runner. |
| 239 ASSERT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u)); | 313 EXPECT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u)); |
| 240 EXPECT_THAT(task_runner()->NextPendingTaskDelay(), | 314 EXPECT_THAT(task_runner()->NextPendingTaskDelay(), |
| 241 Eq(base::TimeDelta::FromHours(1))); | 315 Eq(base::TimeDelta::FromHours(1))); |
| 242 | 316 |
| 243 // Register an observer. | 317 // Register an observer. |
| 244 StrictMock<MockDoodleObserver> observer; | 318 StrictMock<MockDoodleObserver> observer; |
| 245 service()->AddObserver(&observer); | 319 service()->AddObserver(&observer); |
| 246 | 320 |
| 247 // Fast-forward time so that the expiry task will run. The observer should get | 321 // Fast-forward time so that the expiry task will run. The observer should get |
| 248 // notified that there's no config anymore. | 322 // notified that there's no config anymore. |
| 249 EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt))); | 323 EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt))); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 278 service()->Refresh(); | 352 service()->Refresh(); |
| 279 EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt))); | 353 EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt))); |
| 280 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, | 354 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 281 base::TimeDelta::FromSeconds(0), config); | 355 base::TimeDelta::FromSeconds(0), config); |
| 282 | 356 |
| 283 // Remove the observer before the service gets destroyed. | 357 // Remove the observer before the service gets destroyed. |
| 284 service()->RemoveObserver(&observer); | 358 service()->RemoveObserver(&observer); |
| 285 } | 359 } |
| 286 | 360 |
| 287 } // namespace doodle | 361 } // namespace doodle |
| OLD | NEW |