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 "google_apis/gcm/base/mcs_util.h"
13 #include "google_apis/gcm/engine/fake_connection_handler.h"
14 #include "net/base/backoff_entry.h"
15 #include "net/http/http_network_session.h"
16 #include "testing/gtest/include/gtest/gtest.h"
23 const char kMCSEndpoint[] = "http://my.server";
24 const char kMCSEndpoint2[] = "http://my.alt.server";
26 const int kBackoffDelayMs = 1;
27 const int kBackoffMultiplier = 2;
29 // A backoff policy with small enough delays that tests aren't burdened.
30 const net::BackoffEntry::Policy kTestBackoffPolicy = {
31 // Number of initial errors (in sequence) to ignore before applying
32 // exponential back-off rules.
35 // Initial delay for exponential back-off in ms.
38 // Factor by which the waiting time will be multiplied.
41 // Fuzzing percentage. ex: 10% will spread requests randomly
42 // between 90%-100% of the calculated time.
45 // Maximum amount of time we are willing to delay our request in ms.
48 // Time to keep an entry from being discarded even when it
49 // has no significant state, -1 to never discard.
52 // Don't use initial delay unless the last request was an error.
56 std::vector<GURL> BuildEndpoints() {
57 std::vector<GURL> endpoints;
58 endpoints.push_back(GURL(kMCSEndpoint));
59 endpoints.push_back(GURL(kMCSEndpoint2));
63 // Helper for calculating total expected exponential backoff delay given an
64 // arbitrary number of failed attempts. See BackoffEntry::CalculateReleaseTime.
65 double CalculateBackoff(int num_attempts) {
66 double delay = kBackoffDelayMs;
67 for (int i = 1; i < num_attempts; ++i) {
68 delay += kBackoffDelayMs * pow(static_cast<double>(kBackoffMultiplier),
71 DVLOG(1) << "Expected backoff " << delay << " milliseconds.";
75 void ReadContinuation(
76 scoped_ptr<google::protobuf::MessageLite> message) {
79 void WriteContinuation() {
82 class TestBackoffEntry : public net::BackoffEntry {
84 explicit TestBackoffEntry(base::SimpleTestTickClock* tick_clock);
85 virtual ~TestBackoffEntry();
87 virtual base::TimeTicks ImplGetTimeNow() const OVERRIDE;
90 base::SimpleTestTickClock* tick_clock_;
93 TestBackoffEntry::TestBackoffEntry(base::SimpleTestTickClock* tick_clock)
94 : BackoffEntry(&kTestBackoffPolicy),
95 tick_clock_(tick_clock) {
98 TestBackoffEntry::~TestBackoffEntry() {}
100 base::TimeTicks TestBackoffEntry::ImplGetTimeNow() const {
101 return tick_clock_->NowTicks();
104 // A connection factory that stubs out network requests and overrides the
106 class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
108 TestConnectionFactoryImpl(const base::Closure& finished_callback);
109 virtual ~TestConnectionFactoryImpl();
111 void InitializeFactory();
114 virtual void ConnectImpl() OVERRIDE;
115 virtual void InitHandler() OVERRIDE;
116 virtual scoped_ptr<net::BackoffEntry> CreateBackoffEntry(
117 const net::BackoffEntry::Policy* const policy) OVERRIDE;
118 virtual scoped_ptr<ConnectionHandler> CreateConnectionHandler(
119 base::TimeDelta read_timeout,
120 const ConnectionHandler::ProtoReceivedCallback& read_callback,
121 const ConnectionHandler::ProtoSentCallback& write_callback,
122 const ConnectionHandler::ConnectionChangedCallback& connection_callback)
124 virtual base::TimeTicks NowTicks() OVERRIDE;
126 // Helpers for verifying connection attempts are made. Connection results
128 void SetConnectResult(int connect_result);
129 void SetMultipleConnectResults(int connect_result, int num_expected_attempts);
131 // Force a login handshake to be delayed.
132 void SetDelayLogin(bool delay_login);
134 base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
137 // Clock for controlling delay.
138 base::SimpleTestTickClock tick_clock_;
139 // The result to return on the next connect attempt.
141 // The number of expected connection attempts;
142 int num_expected_attempts_;
143 // Whether all expected connection attempts have been fulfilled since an
144 // expectation was last set.
145 bool connections_fulfilled_;
146 // Whether to delay a login handshake completion or not.
148 // Callback to invoke when all connection attempts have been made.
149 base::Closure finished_callback_;
150 // The current fake connection handler..
151 FakeConnectionHandler* fake_handler_;
154 TestConnectionFactoryImpl::TestConnectionFactoryImpl(
155 const base::Closure& finished_callback)
156 : ConnectionFactoryImpl(BuildEndpoints(),
157 net::BackoffEntry::Policy(),
160 connect_result_(net::ERR_UNEXPECTED),
161 num_expected_attempts_(0),
162 connections_fulfilled_(true),
164 finished_callback_(finished_callback),
165 fake_handler_(NULL) {
166 // Set a non-null time.
167 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
170 TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
171 EXPECT_EQ(0, num_expected_attempts_);
174 void TestConnectionFactoryImpl::ConnectImpl() {
175 ASSERT_GT(num_expected_attempts_, 0);
176 scoped_ptr<mcs_proto::LoginRequest> request(BuildLoginRequest(0, 0, ""));
177 GetConnectionHandler()->Init(*request, NULL);
178 OnConnectDone(connect_result_);
179 if (!NextRetryAttempt().is_null()) {
180 // Advance the time to the next retry time.
181 base::TimeDelta time_till_retry =
182 NextRetryAttempt() - tick_clock_.NowTicks();
183 tick_clock_.Advance(time_till_retry);
185 --num_expected_attempts_;
186 if (num_expected_attempts_ == 0) {
187 connect_result_ = net::ERR_UNEXPECTED;
188 connections_fulfilled_ = true;
189 finished_callback_.Run();
193 void TestConnectionFactoryImpl::InitHandler() {
194 EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
196 ConnectionHandlerCallback(net::OK);
199 scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
200 const net::BackoffEntry::Policy* const policy) {
201 return scoped_ptr<net::BackoffEntry>(new TestBackoffEntry(&tick_clock_));
204 scoped_ptr<ConnectionHandler>
205 TestConnectionFactoryImpl::CreateConnectionHandler(
206 base::TimeDelta read_timeout,
207 const ConnectionHandler::ProtoReceivedCallback& read_callback,
208 const ConnectionHandler::ProtoSentCallback& write_callback,
209 const ConnectionHandler::ConnectionChangedCallback& connection_callback) {
210 fake_handler_ = new FakeConnectionHandler(
211 base::Bind(&ReadContinuation),
212 base::Bind(&WriteContinuation));
213 return make_scoped_ptr<ConnectionHandler>(fake_handler_);
216 base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
217 return tick_clock_.NowTicks();
220 void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
221 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
222 ASSERT_EQ(0, num_expected_attempts_);
223 connections_fulfilled_ = false;
224 connect_result_ = connect_result;
225 num_expected_attempts_ = 1;
226 fake_handler_->ExpectOutgoingMessage(
227 MCSMessage(kLoginRequestTag,
228 BuildLoginRequest(0, 0, "").PassAs<
229 const google::protobuf::MessageLite>()));
232 void TestConnectionFactoryImpl::SetMultipleConnectResults(
234 int num_expected_attempts) {
235 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
236 DCHECK_GT(num_expected_attempts, 0);
237 ASSERT_EQ(0, num_expected_attempts_);
238 connections_fulfilled_ = false;
239 connect_result_ = connect_result;
240 num_expected_attempts_ = num_expected_attempts;
241 for (int i = 0 ; i < num_expected_attempts; ++i) {
242 fake_handler_->ExpectOutgoingMessage(
243 MCSMessage(kLoginRequestTag,
244 BuildLoginRequest(0, 0, "").PassAs<
245 const google::protobuf::MessageLite>()));
249 void TestConnectionFactoryImpl::SetDelayLogin(bool delay_login) {
250 delay_login_ = delay_login;
251 fake_handler_->set_fail_login(delay_login_);
254 class ConnectionFactoryImplTest : public testing::Test {
256 ConnectionFactoryImplTest();
257 virtual ~ConnectionFactoryImplTest();
259 TestConnectionFactoryImpl* factory() { return &factory_; }
261 void WaitForConnections();
264 void ConnectionsComplete();
266 TestConnectionFactoryImpl factory_;
267 base::MessageLoop message_loop_;
268 scoped_ptr<base::RunLoop> run_loop_;
271 ConnectionFactoryImplTest::ConnectionFactoryImplTest()
272 : factory_(base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
273 base::Unretained(this))),
274 run_loop_(new base::RunLoop()) {
275 factory()->Initialize(
276 ConnectionFactory::BuildLoginRequestCallback(),
277 ConnectionHandler::ProtoReceivedCallback(),
278 ConnectionHandler::ProtoSentCallback());
280 ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
282 void ConnectionFactoryImplTest::WaitForConnections() {
284 run_loop_.reset(new base::RunLoop());
287 void ConnectionFactoryImplTest::ConnectionsComplete() {
293 // Verify building a connection handler works.
294 TEST_F(ConnectionFactoryImplTest, Initialize) {
295 ConnectionHandler* handler = factory()->GetConnectionHandler();
296 ASSERT_TRUE(handler);
297 EXPECT_FALSE(factory()->IsEndpointReachable());
300 // An initial successful connection should not result in backoff.
301 TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
302 factory()->SetConnectResult(net::OK);
303 factory()->Connect();
304 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
305 EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[0]);
306 EXPECT_TRUE(factory()->IsEndpointReachable());
309 // A connection failure should result in backoff, and attempting the fallback
311 TEST_F(ConnectionFactoryImplTest, ConnectFail) {
312 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
313 factory()->Connect();
314 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
315 EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[1]);
316 EXPECT_FALSE(factory()->IsEndpointReachable());
319 // A connection success after a failure should reset backoff.
320 TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
321 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
322 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
323 factory()->Connect();
324 WaitForConnections();
325 EXPECT_FALSE(factory()->IsEndpointReachable());
326 base::TimeTicks retry_time = factory()->NextRetryAttempt();
327 EXPECT_FALSE(retry_time.is_null());
328 EXPECT_GE((retry_time - connect_time).InMilliseconds(), CalculateBackoff(1));
329 factory()->SetConnectResult(net::OK);
330 WaitForConnections();
331 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
332 EXPECT_TRUE(factory()->IsEndpointReachable());
335 // Multiple connection failures should retry with an exponentially increasing
336 // backoff, then reset on success.
337 TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
338 const int kNumAttempts = 5;
339 factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
342 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
343 factory()->Connect();
344 WaitForConnections();
345 EXPECT_FALSE(factory()->IsEndpointReachable());
346 base::TimeTicks retry_time = factory()->NextRetryAttempt();
347 EXPECT_FALSE(retry_time.is_null());
348 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
349 CalculateBackoff(kNumAttempts));
351 factory()->SetConnectResult(net::OK);
352 WaitForConnections();
353 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
354 EXPECT_TRUE(factory()->IsEndpointReachable());
357 // IP events should trigger canary connections.
358 TEST_F(ConnectionFactoryImplTest, FailThenIPEvent) {
359 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
360 factory()->Connect();
361 WaitForConnections();
362 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
363 EXPECT_FALSE(initial_backoff.is_null());
365 factory()->SetConnectResult(net::ERR_FAILED);
366 factory()->OnIPAddressChanged();
367 WaitForConnections();
369 // Backoff should increase.
370 base::TimeTicks next_backoff = factory()->NextRetryAttempt();
371 EXPECT_GT(next_backoff, initial_backoff);
372 EXPECT_FALSE(factory()->IsEndpointReachable());
375 // Connection type events should trigger canary connections.
376 TEST_F(ConnectionFactoryImplTest, FailThenConnectionTypeEvent) {
377 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
378 factory()->Connect();
379 WaitForConnections();
380 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
381 EXPECT_FALSE(initial_backoff.is_null());
383 factory()->SetConnectResult(net::ERR_FAILED);
384 factory()->OnConnectionTypeChanged(
385 net::NetworkChangeNotifier::CONNECTION_WIFI);
386 WaitForConnections();
388 // Backoff should increase.
389 base::TimeTicks next_backoff = factory()->NextRetryAttempt();
390 EXPECT_GT(next_backoff, initial_backoff);
391 EXPECT_FALSE(factory()->IsEndpointReachable());
394 // Verify that we reconnect even if a canary succeeded then disconnected while
395 // a backoff was pending.
396 TEST_F(ConnectionFactoryImplTest, CanarySucceedsThenDisconnects) {
397 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
398 factory()->Connect();
399 WaitForConnections();
400 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
401 EXPECT_FALSE(initial_backoff.is_null());
403 factory()->SetConnectResult(net::OK);
404 factory()->OnConnectionTypeChanged(
405 net::NetworkChangeNotifier::CONNECTION_WIFI);
406 WaitForConnections();
407 EXPECT_TRUE(factory()->IsEndpointReachable());
409 factory()->SetConnectResult(net::OK);
410 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
411 EXPECT_FALSE(factory()->IsEndpointReachable());
412 WaitForConnections();
413 EXPECT_TRUE(factory()->IsEndpointReachable());
416 // Verify that if a canary connects, but hasn't finished the handshake, a
417 // pending backoff attempt doesn't interrupt the connection.
418 TEST_F(ConnectionFactoryImplTest, CanarySucceedsRetryDuringLogin) {
419 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
420 factory()->Connect();
421 WaitForConnections();
422 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
423 EXPECT_FALSE(initial_backoff.is_null());
425 factory()->SetDelayLogin(true);
426 factory()->SetConnectResult(net::OK);
427 factory()->OnConnectionTypeChanged(
428 net::NetworkChangeNotifier::CONNECTION_WIFI);
429 WaitForConnections();
430 EXPECT_FALSE(factory()->IsEndpointReachable());
432 // Pump the loop, to ensure the pending backoff retry has no effect.
433 base::MessageLoop::current()->PostDelayedTask(
435 base::MessageLoop::QuitClosure(),
436 base::TimeDelta::FromMilliseconds(1));
437 WaitForConnections();
440 // Fail after successful connection via signal reset.
441 TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
442 factory()->SetConnectResult(net::OK);
443 factory()->Connect();
444 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
446 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
447 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
448 EXPECT_FALSE(factory()->IsEndpointReachable());
451 TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
452 factory()->SetConnectResult(net::OK);
453 factory()->Connect();
454 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
456 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
457 base::TimeTicks retry_time = factory()->NextRetryAttempt();
458 EXPECT_FALSE(retry_time.is_null());
459 EXPECT_FALSE(factory()->IsEndpointReachable());
461 const int kNumAttempts = 5;
462 for (int i = 0; i < kNumAttempts; ++i)
463 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
464 EXPECT_EQ(retry_time, factory()->NextRetryAttempt());
465 EXPECT_FALSE(factory()->IsEndpointReachable());
468 // Go into backoff due to connection failure. On successful connection, receive
469 // a signal reset. The original backoff should be restored and extended, rather
470 // than a new backoff starting from scratch.
471 TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
472 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
473 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
474 factory()->Connect();
475 WaitForConnections();
476 base::TimeTicks retry_time = factory()->NextRetryAttempt();
477 EXPECT_FALSE(retry_time.is_null());
479 factory()->SetConnectResult(net::OK);
480 connect_time = factory()->tick_clock()->NowTicks();
481 WaitForConnections();
482 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
484 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
485 EXPECT_FALSE(factory()->IsEndpointReachable());
486 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
487 retry_time = factory()->NextRetryAttempt();
488 EXPECT_FALSE(retry_time.is_null());
489 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
490 CalculateBackoff(2));
492 factory()->SetConnectResult(net::OK);
493 connect_time = factory()->tick_clock()->NowTicks();
494 factory()->tick_clock()->Advance(
495 factory()->NextRetryAttempt() - connect_time);
496 WaitForConnections();
497 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
498 EXPECT_TRUE(factory()->IsEndpointReachable());
500 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
501 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
502 retry_time = factory()->NextRetryAttempt();
503 EXPECT_FALSE(retry_time.is_null());
504 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
505 CalculateBackoff(3));
506 EXPECT_FALSE(factory()->IsEndpointReachable());