Rename isSystemLocationEnabled to isLocationEnabled, as per internal review (185995).
[chromium-blink-merge.git] / google_apis / gcm / engine / connection_factory_impl_unittest.cc
blobaf04fb7473c8b05b53b4bcecde41fe77591e1ae3
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 class TestBackoffEntry : public net::BackoffEntry {
84 public:
85 explicit TestBackoffEntry(base::SimpleTestTickClock* tick_clock);
86 ~TestBackoffEntry() override;
88 base::TimeTicks ImplGetTimeNow() const override;
90 private:
91 base::SimpleTestTickClock* tick_clock_;
94 TestBackoffEntry::TestBackoffEntry(base::SimpleTestTickClock* tick_clock)
95 : BackoffEntry(&kTestBackoffPolicy),
96 tick_clock_(tick_clock) {
99 TestBackoffEntry::~TestBackoffEntry() {}
101 base::TimeTicks TestBackoffEntry::ImplGetTimeNow() const {
102 return tick_clock_->NowTicks();
105 // A connection factory that stubs out network requests and overrides the
106 // backoff policy.
107 class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
108 public:
109 TestConnectionFactoryImpl(const base::Closure& finished_callback);
110 ~TestConnectionFactoryImpl() override;
112 void InitializeFactory();
114 // Overridden stubs.
115 void ConnectImpl() override;
116 void InitHandler() override;
117 scoped_ptr<net::BackoffEntry> CreateBackoffEntry(
118 const net::BackoffEntry::Policy* const policy) override;
119 scoped_ptr<ConnectionHandler> CreateConnectionHandler(
120 base::TimeDelta read_timeout,
121 const ConnectionHandler::ProtoReceivedCallback& read_callback,
122 const ConnectionHandler::ProtoSentCallback& write_callback,
123 const ConnectionHandler::ConnectionChangedCallback& connection_callback)
124 override;
125 base::TimeTicks NowTicks() override;
127 // Helpers for verifying connection attempts are made. Connection results
128 // must be consumed.
129 void SetConnectResult(int connect_result);
130 void SetMultipleConnectResults(int connect_result, int num_expected_attempts);
132 // Force a login handshake to be delayed.
133 void SetDelayLogin(bool delay_login);
135 base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
137 private:
138 // Clock for controlling delay.
139 base::SimpleTestTickClock tick_clock_;
140 // The result to return on the next connect attempt.
141 int connect_result_;
142 // The number of expected connection attempts;
143 int num_expected_attempts_;
144 // Whether all expected connection attempts have been fulfilled since an
145 // expectation was last set.
146 bool connections_fulfilled_;
147 // Whether to delay a login handshake completion or not.
148 bool delay_login_;
149 // Callback to invoke when all connection attempts have been made.
150 base::Closure finished_callback_;
151 // The current fake connection handler..
152 FakeConnectionHandler* fake_handler_;
153 FakeGCMStatsRecorder dummy_recorder_;
156 TestConnectionFactoryImpl::TestConnectionFactoryImpl(
157 const base::Closure& finished_callback)
158 : ConnectionFactoryImpl(BuildEndpoints(),
159 net::BackoffEntry::Policy(),
160 NULL,
161 NULL,
162 NULL,
163 &dummy_recorder_),
164 connect_result_(net::ERR_UNEXPECTED),
165 num_expected_attempts_(0),
166 connections_fulfilled_(true),
167 delay_login_(false),
168 finished_callback_(finished_callback),
169 fake_handler_(NULL) {
170 // Set a non-null time.
171 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
174 TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
175 EXPECT_EQ(0, num_expected_attempts_);
178 void TestConnectionFactoryImpl::ConnectImpl() {
179 ASSERT_GT(num_expected_attempts_, 0);
180 scoped_ptr<mcs_proto::LoginRequest> request(BuildLoginRequest(0, 0, ""));
181 GetConnectionHandler()->Init(*request, NULL);
182 OnConnectDone(connect_result_);
183 if (!NextRetryAttempt().is_null()) {
184 // Advance the time to the next retry time.
185 base::TimeDelta time_till_retry =
186 NextRetryAttempt() - tick_clock_.NowTicks();
187 tick_clock_.Advance(time_till_retry);
189 --num_expected_attempts_;
190 if (num_expected_attempts_ == 0) {
191 connect_result_ = net::ERR_UNEXPECTED;
192 connections_fulfilled_ = true;
193 finished_callback_.Run();
197 void TestConnectionFactoryImpl::InitHandler() {
198 EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
199 if (!delay_login_)
200 ConnectionHandlerCallback(net::OK);
203 scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
204 const net::BackoffEntry::Policy* const policy) {
205 return scoped_ptr<net::BackoffEntry>(new TestBackoffEntry(&tick_clock_));
208 scoped_ptr<ConnectionHandler>
209 TestConnectionFactoryImpl::CreateConnectionHandler(
210 base::TimeDelta read_timeout,
211 const ConnectionHandler::ProtoReceivedCallback& read_callback,
212 const ConnectionHandler::ProtoSentCallback& write_callback,
213 const ConnectionHandler::ConnectionChangedCallback& connection_callback) {
214 fake_handler_ = new FakeConnectionHandler(
215 base::Bind(&ReadContinuation),
216 base::Bind(&WriteContinuation));
217 return make_scoped_ptr<ConnectionHandler>(fake_handler_);
220 base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
221 return tick_clock_.NowTicks();
224 void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
225 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
226 ASSERT_EQ(0, num_expected_attempts_);
227 connections_fulfilled_ = false;
228 connect_result_ = connect_result;
229 num_expected_attempts_ = 1;
230 fake_handler_->ExpectOutgoingMessage(
231 MCSMessage(kLoginRequestTag, BuildLoginRequest(0, 0, "")));
234 void TestConnectionFactoryImpl::SetMultipleConnectResults(
235 int connect_result,
236 int num_expected_attempts) {
237 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
238 DCHECK_GT(num_expected_attempts, 0);
239 ASSERT_EQ(0, num_expected_attempts_);
240 connections_fulfilled_ = false;
241 connect_result_ = connect_result;
242 num_expected_attempts_ = num_expected_attempts;
243 for (int i = 0 ; i < num_expected_attempts; ++i) {
244 fake_handler_->ExpectOutgoingMessage(
245 MCSMessage(kLoginRequestTag, BuildLoginRequest(0, 0, "")));
249 void TestConnectionFactoryImpl::SetDelayLogin(bool delay_login) {
250 delay_login_ = delay_login;
251 fake_handler_->set_fail_login(delay_login_);
254 } // namespace
256 class ConnectionFactoryImplTest
257 : public testing::Test,
258 public ConnectionFactory::ConnectionListener {
259 public:
260 ConnectionFactoryImplTest();
261 virtual ~ConnectionFactoryImplTest();
263 TestConnectionFactoryImpl* factory() { return &factory_; }
264 GURL& connected_server() { return connected_server_; }
266 void WaitForConnections();
268 // ConnectionFactory::ConnectionListener
269 void OnConnected(const GURL& current_server,
270 const net::IPEndPoint& ip_endpoint) override;
271 void OnDisconnected() override;
273 private:
274 void ConnectionsComplete();
276 TestConnectionFactoryImpl factory_;
277 base::MessageLoop message_loop_;
278 scoped_ptr<base::RunLoop> run_loop_;
280 GURL connected_server_;
283 ConnectionFactoryImplTest::ConnectionFactoryImplTest()
284 : factory_(base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
285 base::Unretained(this))),
286 run_loop_(new base::RunLoop()) {
287 factory()->SetConnectionListener(this);
288 factory()->Initialize(
289 ConnectionFactory::BuildLoginRequestCallback(),
290 ConnectionHandler::ProtoReceivedCallback(),
291 ConnectionHandler::ProtoSentCallback());
293 ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
295 void ConnectionFactoryImplTest::WaitForConnections() {
296 run_loop_->Run();
297 run_loop_.reset(new base::RunLoop());
300 void ConnectionFactoryImplTest::ConnectionsComplete() {
301 if (!run_loop_)
302 return;
303 run_loop_->Quit();
306 void ConnectionFactoryImplTest::OnConnected(
307 const GURL& current_server,
308 const net::IPEndPoint& ip_endpoint) {
309 connected_server_ = current_server;
312 void ConnectionFactoryImplTest::OnDisconnected() {
313 connected_server_ = GURL();
316 // Verify building a connection handler works.
317 TEST_F(ConnectionFactoryImplTest, Initialize) {
318 ConnectionHandler* handler = factory()->GetConnectionHandler();
319 ASSERT_TRUE(handler);
320 EXPECT_FALSE(factory()->IsEndpointReachable());
321 EXPECT_FALSE(connected_server().is_valid());
324 // An initial successful connection should not result in backoff.
325 TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
326 factory()->SetConnectResult(net::OK);
327 factory()->Connect();
328 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
329 EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[0]);
330 EXPECT_TRUE(factory()->IsEndpointReachable());
331 EXPECT_TRUE(connected_server().is_valid());
334 // A connection failure should result in backoff, and attempting the fallback
335 // endpoint next.
336 TEST_F(ConnectionFactoryImplTest, ConnectFail) {
337 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
338 factory()->Connect();
339 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
340 EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[1]);
341 EXPECT_FALSE(factory()->IsEndpointReachable());
342 EXPECT_FALSE(connected_server().is_valid());
345 // A connection success after a failure should reset backoff.
346 TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
347 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
348 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
349 factory()->Connect();
350 WaitForConnections();
351 EXPECT_FALSE(factory()->IsEndpointReachable());
352 EXPECT_FALSE(connected_server().is_valid());
353 base::TimeTicks retry_time = factory()->NextRetryAttempt();
354 EXPECT_FALSE(retry_time.is_null());
355 EXPECT_GE((retry_time - connect_time).InMilliseconds(), CalculateBackoff(1));
356 factory()->SetConnectResult(net::OK);
357 WaitForConnections();
358 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
359 EXPECT_TRUE(factory()->IsEndpointReachable());
360 EXPECT_TRUE(connected_server().is_valid());
363 // Multiple connection failures should retry with an exponentially increasing
364 // backoff, then reset on success.
365 TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
366 const int kNumAttempts = 5;
367 factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
368 kNumAttempts);
370 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
371 factory()->Connect();
372 WaitForConnections();
373 EXPECT_FALSE(factory()->IsEndpointReachable());
374 EXPECT_FALSE(connected_server().is_valid());
375 base::TimeTicks retry_time = factory()->NextRetryAttempt();
376 EXPECT_FALSE(retry_time.is_null());
377 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
378 CalculateBackoff(kNumAttempts));
380 factory()->SetConnectResult(net::OK);
381 WaitForConnections();
382 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
383 EXPECT_TRUE(factory()->IsEndpointReachable());
384 EXPECT_TRUE(connected_server().is_valid());
387 // Network change events should trigger canary connections.
388 TEST_F(ConnectionFactoryImplTest, FailThenNetworkChangeEvent) {
389 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
390 factory()->Connect();
391 WaitForConnections();
392 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
393 EXPECT_FALSE(initial_backoff.is_null());
395 factory()->SetConnectResult(net::ERR_FAILED);
396 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_WIFI);
397 WaitForConnections();
399 // Backoff should increase.
400 base::TimeTicks next_backoff = factory()->NextRetryAttempt();
401 EXPECT_GT(next_backoff, initial_backoff);
402 EXPECT_FALSE(factory()->IsEndpointReachable());
405 // Verify that we reconnect even if a canary succeeded then disconnected while
406 // a backoff was pending.
407 TEST_F(ConnectionFactoryImplTest, CanarySucceedsThenDisconnects) {
408 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
409 factory()->Connect();
410 WaitForConnections();
411 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
412 EXPECT_FALSE(initial_backoff.is_null());
414 factory()->SetConnectResult(net::OK);
415 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
416 WaitForConnections();
417 EXPECT_TRUE(factory()->IsEndpointReachable());
418 EXPECT_TRUE(connected_server().is_valid());
420 factory()->SetConnectResult(net::OK);
421 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
422 EXPECT_FALSE(factory()->IsEndpointReachable());
423 EXPECT_FALSE(connected_server().is_valid());
424 WaitForConnections();
425 EXPECT_TRUE(factory()->IsEndpointReachable());
426 EXPECT_TRUE(connected_server().is_valid());
429 // Verify that if a canary connects, but hasn't finished the handshake, a
430 // pending backoff attempt doesn't interrupt the connection.
431 TEST_F(ConnectionFactoryImplTest, CanarySucceedsRetryDuringLogin) {
432 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
433 factory()->Connect();
434 WaitForConnections();
435 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
436 EXPECT_FALSE(initial_backoff.is_null());
438 factory()->SetDelayLogin(true);
439 factory()->SetConnectResult(net::OK);
440 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_WIFI);
441 WaitForConnections();
442 EXPECT_FALSE(factory()->IsEndpointReachable());
444 // Pump the loop, to ensure the pending backoff retry has no effect.
445 base::MessageLoop::current()->PostDelayedTask(
446 FROM_HERE,
447 base::MessageLoop::QuitClosure(),
448 base::TimeDelta::FromMilliseconds(1));
449 WaitForConnections();
452 // Fail after successful connection via signal reset.
453 TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
454 factory()->SetConnectResult(net::OK);
455 factory()->Connect();
456 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
458 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
459 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
460 EXPECT_FALSE(factory()->IsEndpointReachable());
463 TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
464 factory()->SetConnectResult(net::OK);
465 factory()->Connect();
466 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
468 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
469 base::TimeTicks retry_time = factory()->NextRetryAttempt();
470 EXPECT_FALSE(retry_time.is_null());
471 EXPECT_FALSE(factory()->IsEndpointReachable());
473 const int kNumAttempts = 5;
474 for (int i = 0; i < kNumAttempts; ++i)
475 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
476 EXPECT_EQ(retry_time, factory()->NextRetryAttempt());
477 EXPECT_FALSE(factory()->IsEndpointReachable());
480 // Go into backoff due to connection failure. On successful connection, receive
481 // a signal reset. The original backoff should be restored and extended, rather
482 // than a new backoff starting from scratch.
483 TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
484 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
485 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
486 factory()->Connect();
487 WaitForConnections();
488 base::TimeTicks retry_time = factory()->NextRetryAttempt();
489 EXPECT_FALSE(retry_time.is_null());
491 factory()->SetConnectResult(net::OK);
492 connect_time = factory()->tick_clock()->NowTicks();
493 WaitForConnections();
494 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
496 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
497 EXPECT_FALSE(factory()->IsEndpointReachable());
498 EXPECT_FALSE(connected_server().is_valid());
499 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
500 retry_time = factory()->NextRetryAttempt();
501 EXPECT_FALSE(retry_time.is_null());
502 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
503 CalculateBackoff(2));
505 factory()->SetConnectResult(net::OK);
506 connect_time = factory()->tick_clock()->NowTicks();
507 factory()->tick_clock()->Advance(
508 factory()->NextRetryAttempt() - connect_time);
509 WaitForConnections();
510 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
511 EXPECT_TRUE(factory()->IsEndpointReachable());
512 EXPECT_TRUE(connected_server().is_valid());
514 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
515 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
516 retry_time = factory()->NextRetryAttempt();
517 EXPECT_FALSE(retry_time.is_null());
518 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
519 CalculateBackoff(3));
520 EXPECT_FALSE(factory()->IsEndpointReachable());
521 EXPECT_FALSE(connected_server().is_valid());
524 // When the network is disconnected, close the socket and suppress further
525 // connection attempts until the network returns.
526 // Disabled while crbug.com/396687 is being investigated.
527 TEST_F(ConnectionFactoryImplTest, DISABLED_SuppressConnectWhenNoNetwork) {
528 factory()->SetConnectResult(net::OK);
529 factory()->Connect();
530 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
531 EXPECT_TRUE(factory()->IsEndpointReachable());
533 // Advance clock so the login window reset isn't encountered.
534 factory()->tick_clock()->Advance(base::TimeDelta::FromSeconds(11));
536 // Will trigger reset, but will not attempt a new connection.
537 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE);
538 EXPECT_FALSE(factory()->IsEndpointReachable());
539 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
541 // When the network returns, attempt to connect.
542 factory()->SetConnectResult(net::OK);
543 factory()->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_4G);
544 WaitForConnections();
546 EXPECT_TRUE(factory()->IsEndpointReachable());
547 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
550 } // namespace gcm