Roll src/third_party/WebKit 3529d49:06e8485 (svn 202554:202555)
[chromium-blink-merge.git] / google_apis / gcm / engine / connection_factory_impl_unittest.cc
blob31d907d3fac30fd7c5b4a8fd111fa7fb1b680194
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"
7 #include <cmath>
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 "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
15 #include "net/base/backoff_entry.h"
16 #include "net/http/http_network_session.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 class Policy;
21 namespace gcm {
22 namespace {
24 const char kMCSEndpoint[] = "http://my.server";
25 const char kMCSEndpoint2[] = "http://my.alt.server";
27 const int kBackoffDelayMs = 1;
28 const int kBackoffMultiplier = 2;
30 // A backoff policy with small enough delays that tests aren't burdened.
31 const net::BackoffEntry::Policy kTestBackoffPolicy = {
32 // Number of initial errors (in sequence) to ignore before applying
33 // exponential back-off rules.
36 // Initial delay for exponential back-off in ms.
37 kBackoffDelayMs,
39 // Factor by which the waiting time will be multiplied.
40 kBackoffMultiplier,
42 // Fuzzing percentage. ex: 10% will spread requests randomly
43 // between 90%-100% of the calculated time.
46 // Maximum amount of time we are willing to delay our request in ms.
47 10,
49 // Time to keep an entry from being discarded even when it
50 // has no significant state, -1 to never discard.
51 -1,
53 // Don't use initial delay unless the last request was an error.
54 false,
57 std::vector<GURL> BuildEndpoints() {
58 std::vector<GURL> endpoints;
59 endpoints.push_back(GURL(kMCSEndpoint));
60 endpoints.push_back(GURL(kMCSEndpoint2));
61 return endpoints;
64 // Helper for calculating total expected exponential backoff delay given an
65 // arbitrary number of failed attempts. See BackoffEntry::CalculateReleaseTime.
66 double CalculateBackoff(int num_attempts) {
67 double delay = kBackoffDelayMs;
68 for (int i = 1; i < num_attempts; ++i) {
69 delay += kBackoffDelayMs * pow(static_cast<double>(kBackoffMultiplier),
70 i - 1);
72 DVLOG(1) << "Expected backoff " << delay << " milliseconds.";
73 return delay;
76 void ReadContinuation(
77 scoped_ptr<google::protobuf::MessageLite> message) {
80 void WriteContinuation() {
83 // A connection factory that stubs out network requests and overrides the
84 // backoff policy.
85 class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
86 public:
87 TestConnectionFactoryImpl(const base::Closure& finished_callback);
88 ~TestConnectionFactoryImpl() override;
90 void InitializeFactory();
92 // Overridden stubs.
93 void ConnectImpl() override;
94 void InitHandler() override;
95 scoped_ptr<net::BackoffEntry> CreateBackoffEntry(
96 const net::BackoffEntry::Policy* const policy) override;
97 scoped_ptr<ConnectionHandler> CreateConnectionHandler(
98 base::TimeDelta read_timeout,
99 const ConnectionHandler::ProtoReceivedCallback& read_callback,
100 const ConnectionHandler::ProtoSentCallback& write_callback,
101 const ConnectionHandler::ConnectionChangedCallback& connection_callback)
102 override;
103 base::TimeTicks NowTicks() override;
105 // Helpers for verifying connection attempts are made. Connection results
106 // must be consumed.
107 void SetConnectResult(int connect_result);
108 void SetMultipleConnectResults(int connect_result, int num_expected_attempts);
110 // Force a login handshake to be delayed.
111 void SetDelayLogin(bool delay_login);
113 // Simulate a socket error.
114 void SetSocketError();
116 base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
118 private:
119 // Clock for controlling delay.
120 base::SimpleTestTickClock tick_clock_;
121 // The result to return on the next connect attempt.
122 int connect_result_;
123 // The number of expected connection attempts;
124 int num_expected_attempts_;
125 // Whether all expected connection attempts have been fulfilled since an
126 // expectation was last set.
127 bool connections_fulfilled_;
128 // Whether to delay a login handshake completion or not.
129 bool delay_login_;
130 // Callback to invoke when all connection attempts have been made.
131 base::Closure finished_callback_;
132 // A temporary scoped pointer to make sure we don't leak the handler in the
133 // cases it's never consumed by the ConnectionFactory.
134 scoped_ptr<FakeConnectionHandler> scoped_handler_;
135 // The current fake connection handler..
136 FakeConnectionHandler* fake_handler_;
137 // Dummy GCM Stats recorder.
138 FakeGCMStatsRecorder dummy_recorder_;
141 TestConnectionFactoryImpl::TestConnectionFactoryImpl(
142 const base::Closure& finished_callback)
143 : ConnectionFactoryImpl(BuildEndpoints(),
144 net::BackoffEntry::Policy(),
145 NULL,
146 NULL,
147 NULL,
148 &dummy_recorder_),
149 connect_result_(net::ERR_UNEXPECTED),
150 num_expected_attempts_(0),
151 connections_fulfilled_(true),
152 delay_login_(false),
153 finished_callback_(finished_callback),
154 scoped_handler_(
155 new FakeConnectionHandler(base::Bind(&ReadContinuation),
156 base::Bind(&WriteContinuation))),
157 fake_handler_(scoped_handler_.get()) {
158 // Set a non-null time.
159 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
162 TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
163 EXPECT_EQ(0, num_expected_attempts_);
166 void TestConnectionFactoryImpl::ConnectImpl() {
167 ASSERT_GT(num_expected_attempts_, 0);
168 ASSERT_FALSE(GetConnectionHandler()->CanSendMessage());
169 scoped_ptr<mcs_proto::LoginRequest> request(BuildLoginRequest(0, 0, ""));
170 GetConnectionHandler()->Init(*request, NULL);
171 OnConnectDone(connect_result_);
172 if (!NextRetryAttempt().is_null()) {
173 // Advance the time to the next retry time.
174 base::TimeDelta time_till_retry =
175 NextRetryAttempt() - tick_clock_.NowTicks();
176 tick_clock_.Advance(time_till_retry);
178 --num_expected_attempts_;
179 if (num_expected_attempts_ == 0) {
180 connect_result_ = net::ERR_UNEXPECTED;
181 connections_fulfilled_ = true;
182 finished_callback_.Run();
186 void TestConnectionFactoryImpl::InitHandler() {
187 EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
188 if (!delay_login_)
189 ConnectionHandlerCallback(net::OK);
192 scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
193 const net::BackoffEntry::Policy* const policy) {
194 return make_scoped_ptr(new net::BackoffEntry(&kTestBackoffPolicy,
195 &tick_clock_));
198 scoped_ptr<ConnectionHandler>
199 TestConnectionFactoryImpl::CreateConnectionHandler(
200 base::TimeDelta read_timeout,
201 const ConnectionHandler::ProtoReceivedCallback& read_callback,
202 const ConnectionHandler::ProtoSentCallback& write_callback,
203 const ConnectionHandler::ConnectionChangedCallback& connection_callback) {
204 return scoped_handler_.Pass();
207 base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
208 return tick_clock_.NowTicks();
211 void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
212 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
213 ASSERT_EQ(0, num_expected_attempts_);
214 connections_fulfilled_ = false;
215 connect_result_ = connect_result;
216 num_expected_attempts_ = 1;
217 fake_handler_->ExpectOutgoingMessage(
218 MCSMessage(kLoginRequestTag, BuildLoginRequest(0, 0, "")));
221 void TestConnectionFactoryImpl::SetMultipleConnectResults(
222 int connect_result,
223 int num_expected_attempts) {
224 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
225 DCHECK_GT(num_expected_attempts, 0);
226 ASSERT_EQ(0, num_expected_attempts_);
227 connections_fulfilled_ = false;
228 connect_result_ = connect_result;
229 num_expected_attempts_ = num_expected_attempts;
230 for (int i = 0 ; i < num_expected_attempts; ++i) {
231 fake_handler_->ExpectOutgoingMessage(
232 MCSMessage(kLoginRequestTag, BuildLoginRequest(0, 0, "")));
236 void TestConnectionFactoryImpl::SetDelayLogin(bool delay_login) {
237 delay_login_ = delay_login;
238 fake_handler_->set_fail_login(delay_login_);
241 void TestConnectionFactoryImpl::SetSocketError() {
242 fake_handler_->set_had_error(true);
245 } // namespace
247 class ConnectionFactoryImplTest
248 : public testing::Test,
249 public ConnectionFactory::ConnectionListener {
250 public:
251 ConnectionFactoryImplTest();
252 ~ConnectionFactoryImplTest() override;
254 TestConnectionFactoryImpl* factory() { return &factory_; }
255 GURL& connected_server() { return connected_server_; }
257 void WaitForConnections();
259 // ConnectionFactory::ConnectionListener
260 void OnConnected(const GURL& current_server,
261 const net::IPEndPoint& ip_endpoint) override;
262 void OnDisconnected() override;
264 private:
265 void ConnectionsComplete();
267 TestConnectionFactoryImpl factory_;
268 base::MessageLoop message_loop_;
269 scoped_ptr<base::RunLoop> run_loop_;
271 GURL connected_server_;
274 ConnectionFactoryImplTest::ConnectionFactoryImplTest()
275 : factory_(base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
276 base::Unretained(this))),
277 run_loop_(new base::RunLoop()) {
278 factory()->SetConnectionListener(this);
279 factory()->Initialize(
280 ConnectionFactory::BuildLoginRequestCallback(),
281 ConnectionHandler::ProtoReceivedCallback(),
282 ConnectionHandler::ProtoSentCallback());
284 ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
286 void ConnectionFactoryImplTest::WaitForConnections() {
287 run_loop_->Run();
288 run_loop_.reset(new base::RunLoop());
291 void ConnectionFactoryImplTest::ConnectionsComplete() {
292 if (!run_loop_)
293 return;
294 run_loop_->Quit();
297 void ConnectionFactoryImplTest::OnConnected(
298 const GURL& current_server,
299 const net::IPEndPoint& ip_endpoint) {
300 connected_server_ = current_server;
303 void ConnectionFactoryImplTest::OnDisconnected() {
304 connected_server_ = GURL();
307 // Verify building a connection handler works.
308 TEST_F(ConnectionFactoryImplTest, Initialize) {
309 ASSERT_FALSE(factory()->GetConnectionHandler());
310 EXPECT_FALSE(factory()->IsEndpointReachable());
311 EXPECT_FALSE(connected_server().is_valid());
314 // An initial successful connection should not result in backoff.
315 TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
316 factory()->SetConnectResult(net::OK);
317 factory()->Connect();
318 ASSERT_TRUE(factory()->GetConnectionHandler());
319 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
320 EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[0]);
321 EXPECT_TRUE(factory()->IsEndpointReachable());
322 EXPECT_TRUE(connected_server().is_valid());
325 // A connection failure should result in backoff, and attempting the fallback
326 // endpoint next.
327 TEST_F(ConnectionFactoryImplTest, ConnectFail) {
328 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
329 factory()->Connect();
330 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
331 EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[1]);
332 EXPECT_FALSE(factory()->IsEndpointReachable());
333 EXPECT_FALSE(connected_server().is_valid());
336 // A connection success after a failure should reset backoff.
337 TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
338 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
339 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
340 factory()->Connect();
341 WaitForConnections();
342 EXPECT_FALSE(factory()->IsEndpointReachable());
343 EXPECT_FALSE(connected_server().is_valid());
344 base::TimeTicks retry_time = factory()->NextRetryAttempt();
345 EXPECT_FALSE(retry_time.is_null());
346 EXPECT_GE((retry_time - connect_time).InMilliseconds(), CalculateBackoff(1));
347 factory()->SetConnectResult(net::OK);
348 WaitForConnections();
349 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
350 EXPECT_TRUE(factory()->IsEndpointReachable());
351 EXPECT_TRUE(connected_server().is_valid());
354 // Multiple connection failures should retry with an exponentially increasing
355 // backoff, then reset on success.
356 TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
357 const int kNumAttempts = 5;
358 factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
359 kNumAttempts);
361 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
362 factory()->Connect();
363 WaitForConnections();
364 EXPECT_FALSE(factory()->IsEndpointReachable());
365 EXPECT_FALSE(connected_server().is_valid());
366 base::TimeTicks retry_time = factory()->NextRetryAttempt();
367 EXPECT_FALSE(retry_time.is_null());
368 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
369 CalculateBackoff(kNumAttempts));
371 factory()->SetConnectResult(net::OK);
372 WaitForConnections();
373 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
374 EXPECT_TRUE(factory()->IsEndpointReachable());
375 EXPECT_TRUE(connected_server().is_valid());
378 // Network change events should trigger canary connections.
379 TEST_F(ConnectionFactoryImplTest, FailThenNetworkChangeEvent) {
380 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
381 factory()->Connect();
382 WaitForConnections();
383 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
384 EXPECT_FALSE(initial_backoff.is_null());
386 factory()->SetConnectResult(net::ERR_FAILED);
387 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_WIFI);
388 WaitForConnections();
390 // Backoff should increase.
391 base::TimeTicks next_backoff = factory()->NextRetryAttempt();
392 EXPECT_GT(next_backoff, initial_backoff);
393 EXPECT_FALSE(factory()->IsEndpointReachable());
396 // Verify that we reconnect even if a canary succeeded then disconnected while
397 // a backoff was pending.
398 TEST_F(ConnectionFactoryImplTest, CanarySucceedsThenDisconnects) {
399 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
400 factory()->Connect();
401 WaitForConnections();
402 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
403 EXPECT_FALSE(initial_backoff.is_null());
405 factory()->SetConnectResult(net::OK);
406 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
407 WaitForConnections();
408 EXPECT_TRUE(factory()->IsEndpointReachable());
409 EXPECT_TRUE(connected_server().is_valid());
411 factory()->SetConnectResult(net::OK);
412 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
413 EXPECT_FALSE(factory()->IsEndpointReachable());
414 EXPECT_FALSE(connected_server().is_valid());
415 WaitForConnections();
416 EXPECT_TRUE(factory()->IsEndpointReachable());
417 EXPECT_TRUE(connected_server().is_valid());
420 // Verify that if a canary connects, but hasn't finished the handshake, a
421 // pending backoff attempt doesn't interrupt the connection.
422 TEST_F(ConnectionFactoryImplTest, CanarySucceedsRetryDuringLogin) {
423 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
424 factory()->Connect();
425 WaitForConnections();
426 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
427 EXPECT_FALSE(initial_backoff.is_null());
429 factory()->SetDelayLogin(true);
430 factory()->SetConnectResult(net::OK);
431 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_WIFI);
432 WaitForConnections();
433 EXPECT_FALSE(factory()->IsEndpointReachable());
435 // Pump the loop, to ensure the pending backoff retry has no effect.
436 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
437 FROM_HERE,
438 base::MessageLoop::QuitClosure(),
439 base::TimeDelta::FromMilliseconds(1));
440 WaitForConnections();
443 // Fail after successful connection via signal reset.
444 TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
445 factory()->SetConnectResult(net::OK);
446 factory()->Connect();
447 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
449 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
450 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
451 EXPECT_FALSE(factory()->IsEndpointReachable());
454 TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
455 factory()->SetConnectResult(net::OK);
456 factory()->Connect();
457 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
459 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
460 base::TimeTicks retry_time = factory()->NextRetryAttempt();
461 EXPECT_FALSE(retry_time.is_null());
462 EXPECT_FALSE(factory()->IsEndpointReachable());
464 const int kNumAttempts = 5;
465 for (int i = 0; i < kNumAttempts; ++i)
466 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
467 EXPECT_EQ(retry_time, factory()->NextRetryAttempt());
468 EXPECT_FALSE(factory()->IsEndpointReachable());
471 // Go into backoff due to connection failure. On successful connection, receive
472 // a signal reset. The original backoff should be restored and extended, rather
473 // than a new backoff starting from scratch.
474 TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
475 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
476 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
477 factory()->Connect();
478 WaitForConnections();
479 base::TimeTicks retry_time = factory()->NextRetryAttempt();
480 EXPECT_FALSE(retry_time.is_null());
482 factory()->SetConnectResult(net::OK);
483 connect_time = factory()->tick_clock()->NowTicks();
484 WaitForConnections();
485 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
487 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
488 EXPECT_FALSE(factory()->IsEndpointReachable());
489 EXPECT_FALSE(connected_server().is_valid());
490 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
491 retry_time = factory()->NextRetryAttempt();
492 EXPECT_FALSE(retry_time.is_null());
493 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
494 CalculateBackoff(2));
496 factory()->SetConnectResult(net::OK);
497 connect_time = factory()->tick_clock()->NowTicks();
498 factory()->tick_clock()->Advance(
499 factory()->NextRetryAttempt() - connect_time);
500 WaitForConnections();
501 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
502 EXPECT_TRUE(factory()->IsEndpointReachable());
503 EXPECT_TRUE(connected_server().is_valid());
505 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
506 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
507 retry_time = factory()->NextRetryAttempt();
508 EXPECT_FALSE(retry_time.is_null());
509 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
510 CalculateBackoff(3));
511 EXPECT_FALSE(factory()->IsEndpointReachable());
512 EXPECT_FALSE(connected_server().is_valid());
515 // When the network is disconnected, close the socket and suppress further
516 // connection attempts until the network returns.
517 // Disabled while crbug.com/396687 is being investigated.
518 TEST_F(ConnectionFactoryImplTest, DISABLED_SuppressConnectWhenNoNetwork) {
519 factory()->SetConnectResult(net::OK);
520 factory()->Connect();
521 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
522 EXPECT_TRUE(factory()->IsEndpointReachable());
524 // Advance clock so the login window reset isn't encountered.
525 factory()->tick_clock()->Advance(base::TimeDelta::FromSeconds(11));
527 // Will trigger reset, but will not attempt a new connection.
528 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE);
529 EXPECT_FALSE(factory()->IsEndpointReachable());
530 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
532 // When the network returns, attempt to connect.
533 factory()->SetConnectResult(net::OK);
534 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_4G);
535 WaitForConnections();
537 EXPECT_TRUE(factory()->IsEndpointReachable());
538 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
541 // Receiving a network change event before the initial connection should have
542 // no effect.
543 TEST_F(ConnectionFactoryImplTest, NetworkChangeBeforeFirstConnection) {
544 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_4G);
545 factory()->SetConnectResult(net::OK);
546 factory()->Connect();
547 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
548 EXPECT_TRUE(factory()->IsEndpointReachable());
551 // Test that if the client attempts to reconnect while a connection is already
552 // open, we don't crash.
553 TEST_F(ConnectionFactoryImplTest, ConnectionResetRace) {
554 // Initial successful connection.
555 factory()->SetConnectResult(net::OK);
556 factory()->Connect();
557 WaitForConnections();
558 EXPECT_TRUE(factory()->IsEndpointReachable());
560 // Trigger a connection error under the hood.
561 factory()->SetSocketError();
562 EXPECT_FALSE(factory()->IsEndpointReachable());
564 // Now trigger force a re-connection.
565 factory()->SetConnectResult(net::OK);
566 factory()->Connect();
567 WaitForConnections();
569 // Re-connection should succeed.
570 EXPECT_TRUE(factory()->IsEndpointReachable());
573 } // namespace gcm