1 // Copyright (c) 2013 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.
5 #include "google_apis/gcm/engine/connection_factory_impl.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/test/simple_test_tick_clock.h"
12 #include "net/base/backoff_entry.h"
13 #include "net/http/http_network_session.h"
14 #include "testing/gtest/include/gtest/gtest.h"
21 const char kMCSEndpoint[] = "http://my.server";
23 const int kBackoffDelayMs = 1;
24 const int kBackoffMultiplier = 2;
26 // A backoff policy with small enough delays that tests aren't burdened.
27 const net::BackoffEntry::Policy kTestBackoffPolicy = {
28 // Number of initial errors (in sequence) to ignore before applying
29 // exponential back-off rules.
32 // Initial delay for exponential back-off in ms.
35 // Factor by which the waiting time will be multiplied.
38 // Fuzzing percentage. ex: 10% will spread requests randomly
39 // between 90%-100% of the calculated time.
42 // Maximum amount of time we are willing to delay our request in ms.
45 // Time to keep an entry from being discarded even when it
46 // has no significant state, -1 to never discard.
49 // Don't use initial delay unless the last request was an error.
53 // Helper for calculating total expected exponential backoff delay given an
54 // arbitrary number of failed attempts. See BackoffEntry::CalculateReleaseTime.
55 double CalculateBackoff(int num_attempts) {
56 double delay = kBackoffDelayMs;
57 for (int i = 1; i < num_attempts; ++i) {
58 delay += kBackoffDelayMs * pow(static_cast<double>(kBackoffMultiplier),
61 DVLOG(1) << "Expected backoff " << delay << " milliseconds.";
65 // Helper methods that should never actually be called due to real connections
67 void ReadContinuation(
68 scoped_ptr<google::protobuf::MessageLite> message) {
72 void WriteContinuation() {
76 class TestBackoffEntry : public net::BackoffEntry {
78 explicit TestBackoffEntry(base::SimpleTestTickClock* tick_clock);
79 virtual ~TestBackoffEntry();
81 virtual base::TimeTicks ImplGetTimeNow() const OVERRIDE;
84 base::SimpleTestTickClock* tick_clock_;
87 TestBackoffEntry::TestBackoffEntry(base::SimpleTestTickClock* tick_clock)
88 : BackoffEntry(&kTestBackoffPolicy),
89 tick_clock_(tick_clock) {
92 TestBackoffEntry::~TestBackoffEntry() {}
94 base::TimeTicks TestBackoffEntry::ImplGetTimeNow() const {
95 return tick_clock_->NowTicks();
98 // A connection factory that stubs out network requests and overrides the
100 class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
102 TestConnectionFactoryImpl(const base::Closure& finished_callback);
103 virtual ~TestConnectionFactoryImpl();
106 virtual void ConnectImpl() OVERRIDE;
107 virtual void InitHandler() OVERRIDE;
108 virtual scoped_ptr<net::BackoffEntry> CreateBackoffEntry(
109 const net::BackoffEntry::Policy* const policy) OVERRIDE;
110 virtual base::TimeTicks NowTicks() OVERRIDE;
112 // Helpers for verifying connection attempts are made. Connection results
114 void SetConnectResult(int connect_result);
115 void SetMultipleConnectResults(int connect_result, int num_expected_attempts);
117 base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
120 // Clock for controlling delay.
121 base::SimpleTestTickClock tick_clock_;
122 // The result to return on the next connect attempt.
124 // The number of expected connection attempts;
125 int num_expected_attempts_;
126 // Whether all expected connection attempts have been fulfilled since an
127 // expectation was last set.
128 bool connections_fulfilled_;
129 // Callback to invoke when all connection attempts have been made.
130 base::Closure finished_callback_;
133 TestConnectionFactoryImpl::TestConnectionFactoryImpl(
134 const base::Closure& finished_callback)
135 : ConnectionFactoryImpl(GURL(kMCSEndpoint),
136 net::BackoffEntry::Policy(),
139 connect_result_(net::ERR_UNEXPECTED),
140 num_expected_attempts_(0),
141 connections_fulfilled_(true),
142 finished_callback_(finished_callback) {
143 // Set a non-null time.
144 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
147 TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
148 EXPECT_EQ(0, num_expected_attempts_);
151 void TestConnectionFactoryImpl::ConnectImpl() {
152 ASSERT_GT(num_expected_attempts_, 0);
154 OnConnectDone(connect_result_);
155 if (!NextRetryAttempt().is_null()) {
156 // Advance the time to the next retry time.
157 base::TimeDelta time_till_retry =
158 NextRetryAttempt() - tick_clock_.NowTicks();
159 tick_clock_.Advance(time_till_retry);
161 --num_expected_attempts_;
162 if (num_expected_attempts_ == 0) {
163 connect_result_ = net::ERR_UNEXPECTED;
164 connections_fulfilled_ = true;
165 finished_callback_.Run();
169 void TestConnectionFactoryImpl::InitHandler() {
170 EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
171 ConnectionHandlerCallback(net::OK);
174 scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
175 const net::BackoffEntry::Policy* const policy) {
176 return scoped_ptr<net::BackoffEntry>(new TestBackoffEntry(&tick_clock_));
179 base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
180 return tick_clock_.NowTicks();
183 void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
184 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
185 ASSERT_EQ(0, num_expected_attempts_);
186 connections_fulfilled_ = false;
187 connect_result_ = connect_result;
188 num_expected_attempts_ = 1;
191 void TestConnectionFactoryImpl::SetMultipleConnectResults(
193 int num_expected_attempts) {
194 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
195 DCHECK_GT(num_expected_attempts, 0);
196 ASSERT_EQ(0, num_expected_attempts_);
197 connections_fulfilled_ = false;
198 connect_result_ = connect_result;
199 num_expected_attempts_ = num_expected_attempts;
202 class ConnectionFactoryImplTest : public testing::Test {
204 ConnectionFactoryImplTest();
205 virtual ~ConnectionFactoryImplTest();
207 TestConnectionFactoryImpl* factory() { return &factory_; }
209 void WaitForConnections();
212 void ConnectionsComplete();
214 TestConnectionFactoryImpl factory_;
215 base::MessageLoop message_loop_;
216 scoped_ptr<base::RunLoop> run_loop_;
219 ConnectionFactoryImplTest::ConnectionFactoryImplTest()
220 : factory_(base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
221 base::Unretained(this))),
222 run_loop_(new base::RunLoop()) {}
223 ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
225 void ConnectionFactoryImplTest::WaitForConnections() {
227 run_loop_.reset(new base::RunLoop());
230 void ConnectionFactoryImplTest::ConnectionsComplete() {
236 // Verify building a connection handler works.
237 TEST_F(ConnectionFactoryImplTest, Initialize) {
238 EXPECT_FALSE(factory()->IsEndpointReachable());
239 factory()->Initialize(
240 ConnectionFactory::BuildLoginRequestCallback(),
241 base::Bind(&ReadContinuation),
242 base::Bind(&WriteContinuation));
243 ConnectionHandler* handler = factory()->GetConnectionHandler();
244 ASSERT_TRUE(handler);
245 EXPECT_FALSE(factory()->IsEndpointReachable());
248 // An initial successful connection should not result in backoff.
249 TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
250 factory()->Initialize(
251 ConnectionFactory::BuildLoginRequestCallback(),
252 ConnectionHandler::ProtoReceivedCallback(),
253 ConnectionHandler::ProtoSentCallback());
254 factory()->SetConnectResult(net::OK);
255 factory()->Connect();
256 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
259 // A connection failure should result in backoff.
260 TEST_F(ConnectionFactoryImplTest, ConnectFail) {
261 factory()->Initialize(
262 ConnectionFactory::BuildLoginRequestCallback(),
263 ConnectionHandler::ProtoReceivedCallback(),
264 ConnectionHandler::ProtoSentCallback());
265 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
266 factory()->Connect();
267 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
270 // A connection success after a failure should reset backoff.
271 TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
272 factory()->Initialize(
273 ConnectionFactory::BuildLoginRequestCallback(),
274 ConnectionHandler::ProtoReceivedCallback(),
275 ConnectionHandler::ProtoSentCallback());
276 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
277 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
278 factory()->Connect();
279 WaitForConnections();
280 base::TimeTicks retry_time = factory()->NextRetryAttempt();
281 EXPECT_FALSE(retry_time.is_null());
282 EXPECT_GE((retry_time - connect_time).InMilliseconds(), CalculateBackoff(1));
283 factory()->SetConnectResult(net::OK);
284 WaitForConnections();
285 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
288 // Multiple connection failures should retry with an exponentially increasing
289 // backoff, then reset on success.
290 TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
291 factory()->Initialize(
292 ConnectionFactory::BuildLoginRequestCallback(),
293 ConnectionHandler::ProtoReceivedCallback(),
294 ConnectionHandler::ProtoSentCallback());
296 const int kNumAttempts = 5;
297 factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
300 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
301 factory()->Connect();
302 WaitForConnections();
303 base::TimeTicks retry_time = factory()->NextRetryAttempt();
304 EXPECT_FALSE(retry_time.is_null());
305 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
306 CalculateBackoff(kNumAttempts));
308 factory()->SetConnectResult(net::OK);
309 WaitForConnections();
310 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
313 // IP events should reset backoff.
314 TEST_F(ConnectionFactoryImplTest, FailThenIPEvent) {
315 factory()->Initialize(
316 ConnectionFactory::BuildLoginRequestCallback(),
317 ConnectionHandler::ProtoReceivedCallback(),
318 ConnectionHandler::ProtoSentCallback());
319 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
320 factory()->Connect();
321 WaitForConnections();
322 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
324 factory()->OnIPAddressChanged();
325 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
328 // Connection type events should reset backoff.
329 TEST_F(ConnectionFactoryImplTest, FailThenConnectionTypeEvent) {
330 factory()->Initialize(
331 ConnectionFactory::BuildLoginRequestCallback(),
332 ConnectionHandler::ProtoReceivedCallback(),
333 ConnectionHandler::ProtoSentCallback());
334 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
335 factory()->Connect();
336 WaitForConnections();
337 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
339 factory()->OnConnectionTypeChanged(
340 net::NetworkChangeNotifier::CONNECTION_WIFI);
341 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
344 // Fail after successful connection via signal reset.
345 TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
346 factory()->Initialize(
347 ConnectionFactory::BuildLoginRequestCallback(),
348 ConnectionHandler::ProtoReceivedCallback(),
349 ConnectionHandler::ProtoSentCallback());
350 factory()->SetConnectResult(net::OK);
351 factory()->Connect();
352 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
354 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
355 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
356 EXPECT_FALSE(factory()->GetConnectionHandler()->CanSendMessage());
359 TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
360 factory()->Initialize(
361 ConnectionFactory::BuildLoginRequestCallback(),
362 ConnectionHandler::ProtoReceivedCallback(),
363 ConnectionHandler::ProtoSentCallback());
364 factory()->SetConnectResult(net::OK);
365 factory()->Connect();
366 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
368 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
369 base::TimeTicks retry_time = factory()->NextRetryAttempt();
370 EXPECT_FALSE(retry_time.is_null());
372 const int kNumAttempts = 5;
373 for (int i = 0; i < kNumAttempts; ++i)
374 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
375 EXPECT_EQ(retry_time, factory()->NextRetryAttempt());
378 // Go into backoff due to connection failure. On successful connection, receive
379 // a signal reset. The original backoff should be restored and extended, rather
380 // than a new backoff starting from scratch.
381 TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
382 factory()->Initialize(
383 ConnectionFactory::BuildLoginRequestCallback(),
384 ConnectionHandler::ProtoReceivedCallback(),
385 ConnectionHandler::ProtoSentCallback());
386 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
387 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
388 factory()->Connect();
389 WaitForConnections();
390 base::TimeTicks retry_time = factory()->NextRetryAttempt();
391 EXPECT_FALSE(retry_time.is_null());
393 factory()->SetConnectResult(net::OK);
394 connect_time = factory()->tick_clock()->NowTicks();
395 WaitForConnections();
396 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
398 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
399 EXPECT_FALSE(factory()->GetConnectionHandler()->CanSendMessage());
400 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
401 retry_time = factory()->NextRetryAttempt();
402 EXPECT_FALSE(retry_time.is_null());
403 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
404 CalculateBackoff(2));
406 factory()->SetConnectResult(net::OK);
407 connect_time = factory()->tick_clock()->NowTicks();
408 factory()->tick_clock()->Advance(
409 factory()->NextRetryAttempt() - connect_time);
410 WaitForConnections();
411 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
413 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
414 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
415 retry_time = factory()->NextRetryAttempt();
416 EXPECT_FALSE(retry_time.is_null());
417 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
418 CalculateBackoff(3));