Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/password_manager/core/browser/affiliation_fetch_throttler.h " | |
| 6 | |
| 7 #include <cmath> | |
| 8 | |
| 9 #include "base/callback.h" | |
| 10 #include "base/macros.h" | |
| 11 #include "base/memory/ref_counted.h" | |
| 12 #include "base/memory/scoped_ptr.h" | |
| 13 #include "base/message_loop/message_loop.h" | |
| 14 #include "base/numerics/safe_math.h" | |
| 15 #include "base/run_loop.h" | |
| 16 #include "base/test/test_mock_time_task_runner.h" | |
| 17 #include "base/thread_task_runner_handle.h" | |
| 18 #include "base/time/tick_clock.h" | |
| 19 #include "base/time/time.h" | |
| 20 #include "components/password_manager/core/browser/affiliation_fetch_throttler_d elegate.h" | |
| 21 #include "net/base/network_change_notifier.h" | |
| 22 #include "testing/gtest/include/gtest/gtest.h" | |
| 23 | |
| 24 namespace password_manager { | |
| 25 namespace { | |
| 26 | |
| 27 class MockAffiliationFetchThrottlerDelegate | |
| 28 : public AffiliationFetchThrottlerDelegate { | |
| 29 public: | |
| 30 MockAffiliationFetchThrottlerDelegate(scoped_ptr<base::TickClock> tick_clock) | |
|
mmenke
2015/01/30 19:50:41
nit: explicit
engedy
2015/01/30 20:23:13
Done.
| |
| 31 : tick_clock_(tick_clock.Pass()), | |
| 32 emulated_return_value_(true), | |
| 33 release_count_(0u) {} | |
| 34 ~MockAffiliationFetchThrottlerDelegate() { EXPECT_EQ(0u, release_count_); } | |
| 35 | |
| 36 void set_emulated_return_value(bool value) { emulated_return_value_ = value; } | |
| 37 void reset_release_count() { release_count_ = 0u; } | |
|
mmenke
2015/01/30 19:50:41
optional: Think this variable name is a little un
engedy
2015/01/30 20:23:13
Done.
| |
| 38 size_t release_count() const { return release_count_; } | |
| 39 base::TimeTicks last_release_time() const { return last_release_time_; } | |
| 40 | |
| 41 // AffiliationFetchThrottlerDelegate: | |
| 42 bool OnCanSendNetworkRequest() override { | |
| 43 ++release_count_; | |
| 44 last_release_time_ = tick_clock_->NowTicks(); | |
| 45 return emulated_return_value_; | |
| 46 } | |
| 47 | |
| 48 private: | |
| 49 scoped_ptr<base::TickClock> tick_clock_; | |
| 50 bool emulated_return_value_; | |
| 51 size_t release_count_; | |
| 52 base::TimeTicks last_release_time_; | |
| 53 | |
| 54 DISALLOW_COPY_AND_ASSIGN(MockAffiliationFetchThrottlerDelegate); | |
| 55 }; | |
| 56 | |
| 57 } // namespace | |
| 58 | |
| 59 class AffiliationFetchThrottlerTest : public testing::Test { | |
| 60 public: | |
| 61 AffiliationFetchThrottlerTest() | |
| 62 : network_change_notifier_(net::NetworkChangeNotifier::CreateMock()), | |
| 63 task_runner_(new base::TestMockTimeTaskRunner), | |
| 64 mock_delegate_(task_runner_->GetMockTickClock()) {} | |
| 65 ~AffiliationFetchThrottlerTest() override {} | |
| 66 | |
| 67 scoped_ptr<AffiliationFetchThrottler> CreateThrottler() { | |
| 68 return make_scoped_ptr(new AffiliationFetchThrottler( | |
| 69 &mock_delegate_, task_runner_, task_runner_->GetMockTickClock())); | |
| 70 } | |
| 71 | |
| 72 void SimulateHasNetworkConnectivity(bool has_connectivity) { | |
| 73 net::NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests( | |
| 74 has_connectivity ? net::NetworkChangeNotifier::CONNECTION_UNKNOWN | |
| 75 : net::NetworkChangeNotifier::CONNECTION_NONE); | |
| 76 base::RunLoop().RunUntilIdle(); | |
| 77 } | |
| 78 | |
| 79 // Runs the task runner until no tasks remain, and asserts that by this time, | |
| 80 // OnCanSendNetworkRequest() will have been called exactly once, with a delay | |
| 81 // between |min_delay_ms| and |max_delay_ms|, modulo 0.5 ms to allow for | |
| 82 // floating point errors. When OnCanSendNetworkRequest() is called, the mock | |
| 83 // will return |emulated_return_value|. This value normally indicates whether | |
| 84 // or not a request was actually issued in response to the call. | |
| 85 void AssertReleaseInBetween(bool emulated_return_value, | |
| 86 double min_delay_ms, | |
| 87 double max_delay_ms) { | |
| 88 ASSERT_EQ(0u, mock_delegate_.release_count()); | |
| 89 base::TimeTicks ticks_at_start = task_runner_->GetCurrentMockTime(); | |
| 90 mock_delegate_.set_emulated_return_value(emulated_return_value); | |
| 91 task_runner_->FastForwardUntilNoTasksRemain(); | |
| 92 ASSERT_EQ(1u, mock_delegate_.release_count()); | |
| 93 base::TimeDelta delay = mock_delegate_.last_release_time() - ticks_at_start; | |
| 94 EXPECT_LE(min_delay_ms - 1, delay.InMillisecondsF()); | |
| 95 EXPECT_GE(max_delay_ms + 1, delay.InMillisecondsF()); | |
| 96 mock_delegate_.reset_release_count(); | |
| 97 } | |
| 98 | |
| 99 // Runs the task runner for |secs| and asserts that OnCanSendNetworkRequest() | |
| 100 // will not have been called by the end of this period. | |
| 101 void AssertNoReleaseForSecs(int64_t secs) { | |
| 102 task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(secs)); | |
| 103 ASSERT_EQ(0u, mock_delegate_.release_count()); | |
| 104 } | |
| 105 | |
| 106 // Runs the task runner until no tasks remain, and asserts that | |
| 107 // OnCanSendNetworkRequest() will not have been called. | |
| 108 void AssertNoReleaseUntilNoTasksRemain() { | |
| 109 task_runner_->FastForwardUntilNoTasksRemain(); | |
| 110 ASSERT_EQ(0u, mock_delegate_.release_count()); | |
| 111 } | |
| 112 | |
| 113 size_t GetPendingTaskCount() const { | |
| 114 return task_runner_->GetPendingTaskCount(); | |
| 115 } | |
| 116 | |
| 117 private: | |
| 118 // Needed because NetworkChangeNotifier uses ObserverList, which notifies | |
| 119 // observers on the MessageLoop that belongs to the thread from which they | |
| 120 // have registered. | |
| 121 base::MessageLoop message_loop_; | |
| 122 scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_; | |
| 123 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; | |
| 124 MockAffiliationFetchThrottlerDelegate mock_delegate_; | |
| 125 | |
| 126 DISALLOW_COPY_AND_ASSIGN(AffiliationFetchThrottlerTest); | |
| 127 }; | |
| 128 | |
| 129 TEST_F(AffiliationFetchThrottlerTest, SuccessfulRequests) { | |
| 130 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 131 | |
| 132 throttler->SignalNetworkRequestNeeded(); | |
| 133 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 134 | |
| 135 // Signal while request is in flight should be ignored. | |
| 136 throttler->SignalNetworkRequestNeeded(); | |
| 137 AssertNoReleaseUntilNoTasksRemain(); | |
| 138 throttler->InformOfNetworkRequestComplete(true); | |
| 139 AssertNoReleaseUntilNoTasksRemain(); | |
| 140 | |
| 141 // Duplicate the second signal 3 times: still only 1 callback should arrive. | |
| 142 throttler->SignalNetworkRequestNeeded(); | |
| 143 throttler->SignalNetworkRequestNeeded(); | |
| 144 throttler->SignalNetworkRequestNeeded(); | |
| 145 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 146 } | |
| 147 | |
| 148 TEST_F(AffiliationFetchThrottlerTest, FailedRequests) { | |
| 149 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 150 | |
| 151 throttler->SignalNetworkRequestNeeded(); | |
| 152 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 153 throttler->InformOfNetworkRequestComplete(false); | |
| 154 | |
| 155 // The request after the first failure should be delayed by |initial_delay_ms| | |
| 156 // spread out over Uniform(1 - |jitter_factor|, 1). | |
| 157 throttler->SignalNetworkRequestNeeded(); | |
| 158 const auto& kPolicy = AffiliationFetchThrottler::kBackoffPolicy; | |
| 159 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween( | |
| 160 true, kPolicy.initial_delay_ms * (1 - kPolicy.jitter_factor), | |
| 161 kPolicy.initial_delay_ms)); | |
| 162 throttler->InformOfNetworkRequestComplete(true); | |
| 163 | |
| 164 // After a successful request, the next one should be released immediately. | |
| 165 throttler->SignalNetworkRequestNeeded(); | |
| 166 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 167 throttler->InformOfNetworkRequestComplete(false); | |
| 168 | |
| 169 // In general, the request after the n-th failure should be delayed by | |
| 170 // |multiply_factor| ^ (n-1) * |initial_delay_ms|, | |
| 171 // spread out over Uniform(1 - |jitter_factor|, 1), up until | |
| 172 // |maximum_backoff_ms| | |
| 173 // is reached. | |
| 174 for (size_t num_failures = 1; num_failures < 100; ++num_failures) { | |
| 175 throttler->SignalNetworkRequestNeeded(); | |
| 176 double max_delay_ms = kPolicy.initial_delay_ms * | |
| 177 pow(kPolicy.multiply_factor, num_failures - 1); | |
| 178 double min_delay_ms = max_delay_ms * (1 - kPolicy.jitter_factor); | |
| 179 if (max_delay_ms > kPolicy.maximum_backoff_ms) | |
| 180 max_delay_ms = kPolicy.maximum_backoff_ms; | |
| 181 if (min_delay_ms > kPolicy.maximum_backoff_ms) | |
| 182 min_delay_ms = kPolicy.maximum_backoff_ms; | |
| 183 ASSERT_NO_FATAL_FAILURE( | |
| 184 AssertReleaseInBetween(true, min_delay_ms, max_delay_ms)); | |
| 185 throttler->InformOfNetworkRequestComplete(false); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 TEST_F(AffiliationFetchThrottlerTest, OnCanSendNetworkRequestReturnsFalse) { | |
| 190 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 191 | |
| 192 // A need for a network request is signaled, but as OnCanSendNetworkRequest() | |
| 193 // is called, the implementation returns false to indicate that the request | |
| 194 // will not be needed after all. InformOfNetworkRequestComplete() must not be | |
| 195 // called in this case. | |
| 196 throttler->SignalNetworkRequestNeeded(); | |
| 197 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(false, 0, 0)); | |
| 198 | |
| 199 // A subsequent signaling, however, should result in OnCanSendNetworkRequest() | |
| 200 // being called immediately. | |
| 201 throttler->SignalNetworkRequestNeeded(); | |
| 202 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 203 } | |
| 204 | |
| 205 TEST_F(AffiliationFetchThrottlerTest, GracePeriodAfterConnectivityIsRestored) { | |
| 206 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 207 SimulateHasNetworkConnectivity(false); | |
| 208 | |
| 209 // After connectivity is restored, the first request should be delayed by the | |
| 210 // grace period, spread out over Uniform(1 - |jitter_factor|, 1). | |
| 211 throttler->SignalNetworkRequestNeeded(); | |
| 212 AssertNoReleaseUntilNoTasksRemain(); | |
| 213 | |
| 214 SimulateHasNetworkConnectivity(true); | |
| 215 const auto& kPolicy = AffiliationFetchThrottler::kBackoffPolicy; | |
| 216 const int64_t& kGraceMs = | |
| 217 AffiliationFetchThrottler::kGracePeriodAfterReconnectMs; | |
| 218 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween( | |
| 219 true, kGraceMs * (1 - kPolicy.jitter_factor), kGraceMs)); | |
| 220 throttler->InformOfNetworkRequestComplete(true); | |
| 221 | |
| 222 // The next request should not be delayed. | |
| 223 throttler->SignalNetworkRequestNeeded(); | |
| 224 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 225 } | |
| 226 | |
| 227 // Same as GracePeriodAfterConnectivityIsRestored, but the network comes back | |
| 228 // just before SignalNetworkRequestNeeded() is called. | |
| 229 TEST_F(AffiliationFetchThrottlerTest, GracePeriodAfterConnectivityIsRestored2) { | |
| 230 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 231 SimulateHasNetworkConnectivity(false); | |
| 232 | |
| 233 SimulateHasNetworkConnectivity(true); | |
| 234 throttler->SignalNetworkRequestNeeded(); | |
| 235 const auto& kPolicy = AffiliationFetchThrottler::kBackoffPolicy; | |
| 236 const int64_t& kGraceMs = | |
| 237 AffiliationFetchThrottler::kGracePeriodAfterReconnectMs; | |
| 238 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween( | |
| 239 true, kGraceMs * (1 - kPolicy.jitter_factor), kGraceMs)); | |
| 240 throttler->InformOfNetworkRequestComplete(true); | |
| 241 | |
| 242 throttler->SignalNetworkRequestNeeded(); | |
| 243 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 244 } | |
| 245 | |
| 246 TEST_F(AffiliationFetchThrottlerTest, ConnectivityLostDuringBackoff) { | |
| 247 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 248 | |
| 249 throttler->SignalNetworkRequestNeeded(); | |
| 250 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 251 throttler->InformOfNetworkRequestComplete(false); | |
| 252 | |
| 253 throttler->SignalNetworkRequestNeeded(); | |
| 254 SimulateHasNetworkConnectivity(false); | |
| 255 | |
| 256 // Let the exponential backoff delay expire, and verify nothing happens. | |
| 257 AssertNoReleaseUntilNoTasksRemain(); | |
| 258 | |
| 259 // Verify that the request is, however, sent after the normal grace period | |
| 260 // once connectivity is restored. | |
| 261 SimulateHasNetworkConnectivity(true); | |
| 262 const auto& kPolicy = AffiliationFetchThrottler::kBackoffPolicy; | |
| 263 const int64_t& kGraceMs = | |
| 264 AffiliationFetchThrottler::kGracePeriodAfterReconnectMs; | |
| 265 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween( | |
| 266 true, kGraceMs * (1 - kPolicy.jitter_factor), kGraceMs)); | |
| 267 throttler->InformOfNetworkRequestComplete(true); | |
| 268 } | |
| 269 | |
| 270 TEST_F(AffiliationFetchThrottlerTest, | |
| 271 ConnectivityLostAndRestoredDuringBackoff) { | |
| 272 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 273 | |
| 274 throttler->SignalNetworkRequestNeeded(); | |
| 275 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 276 throttler->InformOfNetworkRequestComplete(false); | |
| 277 | |
| 278 throttler->SignalNetworkRequestNeeded(); | |
| 279 const auto& kPolicy = AffiliationFetchThrottler::kBackoffPolicy; | |
| 280 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween( | |
| 281 true, kPolicy.initial_delay_ms * (1 - kPolicy.jitter_factor), | |
| 282 kPolicy.initial_delay_ms)); | |
| 283 throttler->InformOfNetworkRequestComplete(false); | |
| 284 | |
| 285 SimulateHasNetworkConnectivity(false); | |
| 286 SimulateHasNetworkConnectivity(true); | |
| 287 | |
| 288 // This test expects that the exponential backoff interval after the 2nd error | |
| 289 // is larger than the normal grace period after connectivity is restored. | |
| 290 const int64_t& kGraceMs = | |
| 291 AffiliationFetchThrottler::kGracePeriodAfterReconnectMs; | |
| 292 EXPECT_PRED_FORMAT2(testing::DoubleLE, kGraceMs, | |
| 293 kPolicy.initial_delay_ms * kPolicy.multiply_factor); | |
| 294 | |
| 295 // The release should come after the longest of the two intervals expire. | |
| 296 throttler->SignalNetworkRequestNeeded(); | |
| 297 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween( | |
| 298 true, kPolicy.initial_delay_ms * kPolicy.multiply_factor * | |
| 299 (1 - kPolicy.jitter_factor), | |
| 300 kPolicy.initial_delay_ms * kPolicy.multiply_factor)); | |
| 301 throttler->InformOfNetworkRequestComplete(false); | |
| 302 } | |
| 303 | |
| 304 TEST_F(AffiliationFetchThrottlerTest, FlakyConnectivity) { | |
| 305 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 306 | |
| 307 throttler->SignalNetworkRequestNeeded(); | |
| 308 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 309 throttler->InformOfNetworkRequestComplete(false); | |
| 310 | |
| 311 // Run for a total of 5 grace periods and simulate connectivity being lost and | |
| 312 // restored every second. This verifies that a flaky connection will not flood | |
| 313 // the task queue with lots of of tasks and also that release will not happen | |
| 314 // while the connection is flaky even once the first grace period has expired. | |
| 315 throttler->SignalNetworkRequestNeeded(); | |
| 316 const auto& kPolicy = AffiliationFetchThrottler::kBackoffPolicy; | |
| 317 const int64_t& kGraceMs = | |
| 318 AffiliationFetchThrottler::kGracePeriodAfterReconnectMs; | |
| 319 int64_t five_grace_periods_secs = | |
| 320 kGraceMs * 5 / base::Time::kMillisecondsPerSecond; | |
| 321 for (int64_t t = 0; t < five_grace_periods_secs; ++t) { | |
| 322 SimulateHasNetworkConnectivity(false); | |
| 323 AssertNoReleaseForSecs(1); | |
| 324 SimulateHasNetworkConnectivity(true); | |
| 325 EXPECT_EQ(1u, GetPendingTaskCount()); | |
| 326 } | |
| 327 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween( | |
| 328 true, kGraceMs * (1 - kPolicy.jitter_factor), kGraceMs)); | |
| 329 } | |
| 330 | |
| 331 TEST_F(AffiliationFetchThrottlerTest, ConnectivityLostDuringRequest) { | |
| 332 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 333 | |
| 334 throttler->SignalNetworkRequestNeeded(); | |
| 335 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 336 | |
| 337 SimulateHasNetworkConnectivity(false); | |
| 338 AssertNoReleaseUntilNoTasksRemain(); | |
| 339 throttler->InformOfNetworkRequestComplete(false); | |
| 340 AssertNoReleaseUntilNoTasksRemain(); | |
| 341 throttler->SignalNetworkRequestNeeded(); | |
| 342 AssertNoReleaseUntilNoTasksRemain(); | |
| 343 | |
| 344 SimulateHasNetworkConnectivity(true); | |
| 345 | |
| 346 // Verify that the next request is released after the normal grace period. | |
| 347 const auto& kPolicy = AffiliationFetchThrottler::kBackoffPolicy; | |
| 348 const int64_t& kGraceMs = | |
| 349 AffiliationFetchThrottler::kGracePeriodAfterReconnectMs; | |
| 350 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween( | |
| 351 true, kGraceMs * (1 - kPolicy.jitter_factor), kGraceMs)); | |
| 352 throttler->InformOfNetworkRequestComplete(true); | |
| 353 } | |
| 354 | |
| 355 TEST_F(AffiliationFetchThrottlerTest, | |
| 356 ConnectivityLostAndRestoredDuringRequest) { | |
| 357 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 358 | |
| 359 throttler->SignalNetworkRequestNeeded(); | |
| 360 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 361 | |
| 362 SimulateHasNetworkConnectivity(false); | |
| 363 AssertNoReleaseUntilNoTasksRemain(); | |
| 364 SimulateHasNetworkConnectivity(true); | |
| 365 AssertNoReleaseUntilNoTasksRemain(); | |
| 366 throttler->InformOfNetworkRequestComplete(true); | |
| 367 | |
| 368 // Even though the previous request succeeded, the next request should still | |
| 369 // be held back for the normal grace period after connection is restored. | |
| 370 throttler->SignalNetworkRequestNeeded(); | |
| 371 const auto& kPolicy = AffiliationFetchThrottler::kBackoffPolicy; | |
| 372 const int64_t& kGraceMs = | |
| 373 AffiliationFetchThrottler::kGracePeriodAfterReconnectMs; | |
| 374 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween( | |
| 375 true, kGraceMs * (1 - kPolicy.jitter_factor), kGraceMs)); | |
| 376 throttler->InformOfNetworkRequestComplete(true); | |
| 377 } | |
| 378 | |
| 379 TEST_F(AffiliationFetchThrottlerTest, | |
| 380 ConnectivityLostAndRestoredDuringRequest2) { | |
| 381 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 382 | |
| 383 throttler->SignalNetworkRequestNeeded(); | |
| 384 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 385 | |
| 386 SimulateHasNetworkConnectivity(false); | |
| 387 AssertNoReleaseUntilNoTasksRemain(); | |
| 388 SimulateHasNetworkConnectivity(true); | |
| 389 | |
| 390 const int64_t& kGraceMs = | |
| 391 AffiliationFetchThrottler::kGracePeriodAfterReconnectMs; | |
| 392 AssertNoReleaseForSecs(kGraceMs / base::Time::kMillisecondsPerSecond); | |
| 393 throttler->InformOfNetworkRequestComplete(true); | |
| 394 | |
| 395 // The next request should not be held back. | |
| 396 throttler->SignalNetworkRequestNeeded(); | |
| 397 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 398 } | |
| 399 | |
| 400 TEST_F(AffiliationFetchThrottlerTest, InstanceDestroyedWhileInBackoff) { | |
| 401 scoped_ptr<AffiliationFetchThrottler> throttler(CreateThrottler()); | |
| 402 | |
| 403 throttler->SignalNetworkRequestNeeded(); | |
| 404 ASSERT_NO_FATAL_FAILURE(AssertReleaseInBetween(true, 0, 0)); | |
| 405 throttler->InformOfNetworkRequestComplete(false); | |
| 406 | |
| 407 throttler->SignalNetworkRequestNeeded(); | |
| 408 throttler.reset(); | |
| 409 EXPECT_EQ(1u, GetPendingTaskCount()); | |
| 410 AssertNoReleaseUntilNoTasksRemain(); | |
| 411 } | |
| 412 | |
| 413 } // namespace password_manager | |
| OLD | NEW |