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 <queue> |
| 6 |
| 7 #include "base/callback.h" |
| 8 #include "base/memory/ref_counted.h" |
| 9 #include "base/run_loop.h" |
| 10 #include "base/single_thread_task_runner.h" |
| 11 #include "base/test/test_mock_time_task_runner.h" |
| 12 #include "base/thread_task_runner_handle.h" |
| 13 #include "base/time/tick_clock.h" |
| 14 #include "base/time/time.h" |
| 15 #include "components/password_manager/core/browser/affiliation_fetch_throttler.h
" |
| 16 #include "testing/gmock/include/gmock/gmock.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 |
| 19 namespace password_manager { |
| 20 namespace { |
| 21 |
| 22 class MockAffiliationFetchThrottlerDelegate |
| 23 : public testing::StrictMock<AffiliationFetchThrottlerDelegate> { |
| 24 public: |
| 25 MockAffiliationFetchThrottlerDelegate() {} |
| 26 |
| 27 MOCK_METHOD0(OnCanSendNetworkRequest, bool()); |
| 28 |
| 29 private: |
| 30 DISALLOW_COPY_AND_ASSIGN(MockAffiliationFetchThrottlerDelegate); |
| 31 }; |
| 32 |
| 33 class MockNetworkChangeNotifier : public net::NetworkChangeNotifier { |
| 34 public: |
| 35 MockNetworkChangeNotifier() : connection_type_(CONNECTION_UNKNOWN) {} |
| 36 |
| 37 void set_connection_type(ConnectionType connection_type) { |
| 38 connection_type_ = connection_type; |
| 39 NotifyObserversOfConnectionTypeChangeForTests(connection_type_); |
| 40 } |
| 41 |
| 42 ConnectionType GetCurrentConnectionType() const override { |
| 43 return connection_type_; |
| 44 } |
| 45 |
| 46 private: |
| 47 ConnectionType connection_type_; |
| 48 }; |
| 49 |
| 50 } // namespace |
| 51 |
| 52 class AffiliationFetchThrottlerTest : public testing::Test { |
| 53 public: |
| 54 AffiliationFetchThrottlerTest() |
| 55 : network_change_notifier_(new MockNetworkChangeNotifier), |
| 56 task_runner_(new base::TestMockTimeTaskRunner) {} |
| 57 ~AffiliationFetchThrottlerTest() override {} |
| 58 |
| 59 void SetUp() override { |
| 60 policy_.reset(new AffiliationFetchThrottler( |
| 61 &mock_delegate_, task_runner_, task_runner_->GetMockTickClock())); |
| 62 } |
| 63 |
| 64 void SimulateHasNetworkConnectivity(bool has_connectivity) { |
| 65 network_change_notifier_->set_connection_type( |
| 66 has_connectivity ? net::NetworkChangeNotifier::CONNECTION_UNKNOWN |
| 67 : net::NetworkChangeNotifier::CONNECTION_NONE); |
| 68 base::RunLoop().RunUntilIdle(); |
| 69 } |
| 70 |
| 71 // Forwards time, and given that MockAffiliationFetchThrottlerDelegate is a |
| 72 // strict mock, also ensures OnCanSendNetworkRequest() is not called back |
| 73 // during this period. |
| 74 void FastForwardTimeBySecs(double secs) { |
| 75 task_runner_->FastForwardBy(base::TimeDelta::FromSecondsD(secs)); |
| 76 } |
| 77 |
| 78 void FastForwardUntilNoTasksRemain() { |
| 79 task_runner_->FastForwardUntilNoTasksRemain(); |
| 80 } |
| 81 |
| 82 size_t NumberOfEnqueuedTasks() { return task_runner_->GetPendingTaskCount(); } |
| 83 |
| 84 // Forwards time until the next OnCanSendNetworkRequest() callback, and |
| 85 // verifies that it occurs between |min_delay_sec| and |max_delay_sec| seconds |
| 86 // from now, inclusive. |
| 87 void AssertReleaseBetweenSecs(double min_delay_sec, double max_delay_sec) { |
| 88 base::TimeTicks ticks_at_start = task_runner_->GetCurrentTime(); |
| 89 base::TimeDelta min_delay = base::TimeDelta::FromSecondsD(min_delay_sec); |
| 90 if (min_delay.ToInternalValue() > 0) { |
| 91 task_runner_->FastForwardBy(min_delay - |
| 92 base::TimeDelta::FromInternalValue(1)); |
| 93 } |
| 94 EXPECT_CALL(mock_delegate_, OnCanSendNetworkRequest()) |
| 95 .Times(1) |
| 96 .WillRepeatedly(testing::Return(true)); |
| 97 task_runner_->FastForwardUntilNoTasksRemain(); |
| 98 ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate_)); |
| 99 ASSERT_GE(base::TimeDelta::FromSecondsD(max_delay_sec), |
| 100 task_runner_->GetCurrentTime() - ticks_at_start); |
| 101 } |
| 102 |
| 103 AffiliationFetchThrottler& policy() { return *policy_.get(); } |
| 104 |
| 105 private: |
| 106 // Needed because NetworkChangeNotifier uses ObserverList, which notifies |
| 107 // observers on the MessageLoop that belongs to the thread from which they |
| 108 // have registered. |
| 109 base::MessageLoop message_loop_; |
| 110 scoped_ptr<MockNetworkChangeNotifier> network_change_notifier_; |
| 111 scoped_refptr<base::TestMockTimeTaskRunner> task_runner_; |
| 112 MockAffiliationFetchThrottlerDelegate mock_delegate_; |
| 113 scoped_ptr<AffiliationFetchThrottler> policy_; |
| 114 |
| 115 DISALLOW_COPY_AND_ASSIGN(AffiliationFetchThrottlerTest); |
| 116 }; |
| 117 |
| 118 TEST_F(AffiliationFetchThrottlerTest, SuccessfulRequests) { |
| 119 SimulateHasNetworkConnectivity(true); |
| 120 |
| 121 policy().SignalNetworkRequestNeeded(); |
| 122 AssertReleaseBetweenSecs(0, 0); |
| 123 |
| 124 // Signal while request is in flight should be ignored. |
| 125 policy().SignalNetworkRequestNeeded(); |
| 126 FastForwardUntilNoTasksRemain(); |
| 127 policy().InformOfNetworkRequestComplete(true); |
| 128 FastForwardUntilNoTasksRemain(); |
| 129 |
| 130 // Duplicate the second signal 3 times: still only 1 callback should arrive. |
| 131 policy().SignalNetworkRequestNeeded(); |
| 132 policy().SignalNetworkRequestNeeded(); |
| 133 policy().SignalNetworkRequestNeeded(); |
| 134 AssertReleaseBetweenSecs(0, 0); |
| 135 } |
| 136 |
| 137 TEST_F(AffiliationFetchThrottlerTest, FailedRequests) { |
| 138 SimulateHasNetworkConnectivity(true); |
| 139 |
| 140 policy().SignalNetworkRequestNeeded(); |
| 141 ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(0, 0)); |
| 142 policy().InformOfNetworkRequestComplete(false); |
| 143 |
| 144 // Request after first failure should be delayed by 10 seconds % 50% fuzzing |
| 145 // factor. |
| 146 policy().SignalNetworkRequestNeeded(); |
| 147 ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10)); |
| 148 policy().InformOfNetworkRequestComplete(false); |
| 149 |
| 150 // Request after first failure should be delayed by 40 seconds % 50% fuzzing |
| 151 // factor, applied twice. |
| 152 policy().SignalNetworkRequestNeeded(); |
| 153 ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(10, 40)); |
| 154 policy().InformOfNetworkRequestComplete(false); |
| 155 } |
| 156 |
| 157 TEST_F(AffiliationFetchThrottlerTest, GracePeriodAfterConnectivityIsRestored) { |
| 158 SimulateHasNetworkConnectivity(false); |
| 159 |
| 160 // After connectivity is re-established, the first request should be delayed |
| 161 // by 10 seconds % 50% fuzzing factor. |
| 162 policy().SignalNetworkRequestNeeded(); |
| 163 SimulateHasNetworkConnectivity(true); |
| 164 ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10)); |
| 165 policy().InformOfNetworkRequestComplete(true); |
| 166 |
| 167 // The next request should not be delayed. |
| 168 policy().SignalNetworkRequestNeeded(); |
| 169 AssertReleaseBetweenSecs(0, 0); |
| 170 } |
| 171 |
| 172 // Same as GracePeriodAfterConnectivityIsRestored, but the network comes back |
| 173 // just before SignalNetworkRequestNeeded() is called. |
| 174 TEST_F(AffiliationFetchThrottlerTest, GracePeriodAfterConnectivityIsRestored2) { |
| 175 SimulateHasNetworkConnectivity(false); |
| 176 |
| 177 SimulateHasNetworkConnectivity(true); |
| 178 policy().SignalNetworkRequestNeeded(); |
| 179 ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10)); |
| 180 policy().InformOfNetworkRequestComplete(true); |
| 181 |
| 182 policy().SignalNetworkRequestNeeded(); |
| 183 AssertReleaseBetweenSecs(0, 0); |
| 184 } |
| 185 |
| 186 // TODO(engedy): This test is flaky. Investigate. |
| 187 TEST_F(AffiliationFetchThrottlerTest, ConnectivityLostDuringBackoff) { |
| 188 SimulateHasNetworkConnectivity(true); |
| 189 |
| 190 policy().SignalNetworkRequestNeeded(); |
| 191 ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(0, 0)); |
| 192 policy().InformOfNetworkRequestComplete(false); |
| 193 |
| 194 policy().SignalNetworkRequestNeeded(); |
| 195 SimulateHasNetworkConnectivity(false); |
| 196 |
| 197 // Let the exponential backoff delay expire, and verify nothing happens. |
| 198 FastForwardUntilNoTasksRemain(); |
| 199 |
| 200 // Verify that the request is, however, sent after 10 seconds % 50 fuzzing |
| 201 // factor. |
| 202 SimulateHasNetworkConnectivity(true); |
| 203 ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10)); |
| 204 } |
| 205 |
| 206 TEST_F(AffiliationFetchThrottlerTest, |
| 207 ConnectivityLostAndRestoredDuringBackoff) { |
| 208 SimulateHasNetworkConnectivity(true); |
| 209 |
| 210 policy().SignalNetworkRequestNeeded(); |
| 211 ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(0, 0)); |
| 212 policy().InformOfNetworkRequestComplete(false); |
| 213 |
| 214 policy().SignalNetworkRequestNeeded(); |
| 215 |
| 216 // Also verify that a flaky connection will not flood the task queue with lots |
| 217 // of tasks. |
| 218 for (size_t t = 1; t <= 5; ++t) { |
| 219 SimulateHasNetworkConnectivity(false); |
| 220 SimulateHasNetworkConnectivity(true); |
| 221 FastForwardTimeBySecs(1); |
| 222 } |
| 223 EXPECT_EQ(1u, NumberOfEnqueuedTasks()); |
| 224 |
| 225 ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10)); |
| 226 } |
| 227 |
| 228 } // namespace password_manager |
OLD | NEW |