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