| 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" |
| 14 #include "base/test/simple_test_tick_clock.h" |
| 15 #include "base/test/test_mock_time_task_runner.h" |
| 16 #include "base/threading/thread_task_runner_handle.h" |
| 13 #include "base/time/time.h" | 17 #include "base/time/time.h" |
| 14 #include "testing/gmock/include/gmock/gmock.h" | 18 #include "testing/gmock/include/gmock/gmock.h" |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 16 | 20 |
| 17 using testing::Eq; | 21 using testing::Eq; |
| 18 using testing::StrictMock; | 22 using testing::StrictMock; |
| 19 | 23 |
| 20 namespace doodle { | 24 namespace doodle { |
| 21 | 25 |
| 22 namespace { | 26 namespace { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 48 class MockDoodleObserver : public DoodleService::Observer { | 52 class MockDoodleObserver : public DoodleService::Observer { |
| 49 public: | 53 public: |
| 50 MOCK_METHOD1(OnDoodleConfigUpdated, | 54 MOCK_METHOD1(OnDoodleConfigUpdated, |
| 51 void(const base::Optional<DoodleConfig>&)); | 55 void(const base::Optional<DoodleConfig>&)); |
| 52 }; | 56 }; |
| 53 | 57 |
| 54 } // namespace | 58 } // namespace |
| 55 | 59 |
| 56 class DoodleServiceTest : public testing::Test { | 60 class DoodleServiceTest : public testing::Test { |
| 57 public: | 61 public: |
| 58 DoodleServiceTest() : fetcher_(nullptr) { | 62 DoodleServiceTest() |
| 63 : fetcher_(nullptr), |
| 64 task_runner_(new base::TestMockTimeTaskRunner()), |
| 65 task_runner_handle_(task_runner_), |
| 66 tick_clock_(task_runner_->GetMockTickClock()), |
| 67 expiry_timer_(nullptr) { |
| 68 task_runner_->FastForwardBy(base::TimeDelta::FromHours(12345)); |
| 69 |
| 70 auto expiry_timer = base::MakeUnique<base::OneShotTimer>(tick_clock_.get()); |
| 71 expiry_timer->SetTaskRunner(task_runner_); |
| 72 expiry_timer_ = expiry_timer.get(); |
| 73 |
| 59 auto fetcher = base::MakeUnique<FakeDoodleFetcher>(); | 74 auto fetcher = base::MakeUnique<FakeDoodleFetcher>(); |
| 60 fetcher_ = fetcher.get(); | 75 fetcher_ = fetcher.get(); |
| 61 service_ = base::MakeUnique<DoodleService>(std::move(fetcher)); | 76 |
| 77 service_ = base::MakeUnique<DoodleService>(std::move(fetcher), |
| 78 std::move(expiry_timer)); |
| 62 } | 79 } |
| 63 | 80 |
| 64 DoodleService* service() { return service_.get(); } | 81 DoodleService* service() { return service_.get(); } |
| 65 FakeDoodleFetcher* fetcher() { return fetcher_; } | 82 FakeDoodleFetcher* fetcher() { return fetcher_; } |
| 66 | 83 |
| 84 base::TestMockTimeTaskRunner* task_runner() { return task_runner_.get(); } |
| 85 |
| 67 private: | 86 private: |
| 87 // Weak, owned by the service. |
| 88 FakeDoodleFetcher* fetcher_; |
| 89 |
| 90 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
| 91 base::ThreadTaskRunnerHandle task_runner_handle_; |
| 92 std::unique_ptr<base::TickClock> tick_clock_; |
| 93 // Weak, owned by the service. |
| 94 base::OneShotTimer* expiry_timer_; |
| 95 |
| 68 std::unique_ptr<DoodleService> service_; | 96 std::unique_ptr<DoodleService> service_; |
| 69 FakeDoodleFetcher* fetcher_; | |
| 70 }; | 97 }; |
| 71 | 98 |
| 72 TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) { | 99 TEST_F(DoodleServiceTest, FetchesConfigOnRefresh) { |
| 73 ASSERT_THAT(service()->config(), Eq(base::nullopt)); | 100 ASSERT_THAT(service()->config(), Eq(base::nullopt)); |
| 74 | 101 |
| 75 // Request a refresh of the doodle config. | 102 // Request a refresh of the doodle config. |
| 76 service()->Refresh(); | 103 service()->Refresh(); |
| 77 // The request should have arrived at the fetcher. | 104 // The request should have arrived at the fetcher. |
| 78 EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); | 105 EXPECT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); |
| 79 | 106 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 other_config.doodle_type = DoodleType::SLIDESHOW; | 197 other_config.doodle_type = DoodleType::SLIDESHOW; |
| 171 DCHECK(config != other_config); | 198 DCHECK(config != other_config); |
| 172 EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(other_config))); | 199 EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(other_config))); |
| 173 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, | 200 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 174 base::TimeDelta::FromHours(1), other_config); | 201 base::TimeDelta::FromHours(1), other_config); |
| 175 | 202 |
| 176 // Remove the observer before the service gets destroyed. | 203 // Remove the observer before the service gets destroyed. |
| 177 service()->RemoveObserver(&observer); | 204 service()->RemoveObserver(&observer); |
| 178 } | 205 } |
| 179 | 206 |
| 180 TEST_F(DoodleServiceTest, DoesNotCallObserverWhenConfigEquivalent) { | 207 TEST_F(DoodleServiceTest, DoesNotCallObserverIfConfigEquivalent) { |
| 181 // Load some doodle config. | 208 // Load some doodle config. |
| 182 service()->Refresh(); | 209 service()->Refresh(); |
| 183 DoodleConfig config; | 210 DoodleConfig config; |
| 184 config.doodle_type = DoodleType::SIMPLE; | 211 config.doodle_type = DoodleType::SIMPLE; |
| 185 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, | 212 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 186 base::TimeDelta::FromHours(1), config); | 213 base::TimeDelta::FromHours(1), config); |
| 187 ASSERT_THAT(service()->config(), Eq(config)); | 214 ASSERT_THAT(service()->config(), Eq(config)); |
| 188 | 215 |
| 189 // Register an observer and request a refresh. | 216 // Register an observer and request a refresh. |
| 190 StrictMock<MockDoodleObserver> observer; | 217 StrictMock<MockDoodleObserver> observer; |
| 191 service()->AddObserver(&observer); | 218 service()->AddObserver(&observer); |
| 192 service()->Refresh(); | 219 service()->Refresh(); |
| 193 ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); | 220 ASSERT_THAT(fetcher()->num_pending_callbacks(), Eq(1u)); |
| 194 | 221 |
| 195 // Serve the request with an equivalent doodle config. The observer should | 222 // Serve the request with an equivalent doodle config. The observer should |
| 196 // *not* get notified. | 223 // *not* get notified. |
| 197 DoodleConfig equivalent_config; | 224 DoodleConfig equivalent_config; |
| 198 equivalent_config.doodle_type = DoodleType::SIMPLE; | 225 equivalent_config.doodle_type = DoodleType::SIMPLE; |
| 199 DCHECK(config == equivalent_config); | 226 DCHECK(config == equivalent_config); |
| 200 fetcher()->ServeAllCallbacks( | 227 fetcher()->ServeAllCallbacks( |
| 201 DoodleState::AVAILABLE, base::TimeDelta::FromHours(1), equivalent_config); | 228 DoodleState::AVAILABLE, base::TimeDelta::FromHours(1), equivalent_config); |
| 202 | 229 |
| 203 // Remove the observer before the service gets destroyed. | 230 // Remove the observer before the service gets destroyed. |
| 204 service()->RemoveObserver(&observer); | 231 service()->RemoveObserver(&observer); |
| 205 } | 232 } |
| 206 | 233 |
| 234 TEST_F(DoodleServiceTest, CallsObserverWhenConfigExpires) { |
| 235 // Load some doodle config. |
| 236 service()->Refresh(); |
| 237 DoodleConfig config; |
| 238 config.doodle_type = DoodleType::SIMPLE; |
| 239 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 240 base::TimeDelta::FromHours(1), config); |
| 241 ASSERT_THAT(service()->config(), Eq(config)); |
| 242 |
| 243 // Make sure the task arrived at the timer's task runner. |
| 244 ASSERT_THAT(task_runner()->GetPendingTaskCount(), Eq(1u)); |
| 245 EXPECT_THAT(task_runner()->NextPendingTaskDelay(), |
| 246 Eq(base::TimeDelta::FromHours(1))); |
| 247 |
| 248 // Register an observer. |
| 249 StrictMock<MockDoodleObserver> observer; |
| 250 service()->AddObserver(&observer); |
| 251 |
| 252 // Fast-forward time so that the expiry task will run. The observer should get |
| 253 // notified that there's no config anymore. |
| 254 EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt))); |
| 255 task_runner()->FastForwardBy(base::TimeDelta::FromHours(1)); |
| 256 |
| 257 // Remove the observer before the service gets destroyed. |
| 258 service()->RemoveObserver(&observer); |
| 259 } |
| 260 |
| 261 TEST_F(DoodleServiceTest, DisregardsAlreadyExpiredConfigs) { |
| 262 StrictMock<MockDoodleObserver> observer; |
| 263 service()->AddObserver(&observer); |
| 264 |
| 265 ASSERT_THAT(service()->config(), Eq(base::nullopt)); |
| 266 |
| 267 // Load an already-expired config. This should have no effect; in particular |
| 268 // no call to the observer. |
| 269 service()->Refresh(); |
| 270 DoodleConfig config; |
| 271 config.doodle_type = DoodleType::SIMPLE; |
| 272 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 273 base::TimeDelta::FromSeconds(0), config); |
| 274 EXPECT_THAT(service()->config(), Eq(base::nullopt)); |
| 275 |
| 276 // Load a doodle config as usual. Nothing to see here. |
| 277 service()->Refresh(); |
| 278 EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(config))); |
| 279 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 280 base::TimeDelta::FromHours(1), config); |
| 281 ASSERT_THAT(service()->config(), Eq(config)); |
| 282 |
| 283 // Now load an expired config again. The cached one should go away. |
| 284 service()->Refresh(); |
| 285 EXPECT_CALL(observer, OnDoodleConfigUpdated(Eq(base::nullopt))); |
| 286 fetcher()->ServeAllCallbacks(DoodleState::AVAILABLE, |
| 287 base::TimeDelta::FromSeconds(0), config); |
| 288 |
| 289 // Remove the observer before the service gets destroyed. |
| 290 service()->RemoveObserver(&observer); |
| 291 } |
| 292 |
| 207 } // namespace doodle | 293 } // namespace doodle |
| OLD | NEW |