26f456a7e17604fb9df53594798f3478819df1c2
[platform/framework/web/crosswalk.git] / src / google_apis / gcm / engine / connection_factory_impl_unittest.cc
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.
4
5 #include "google_apis/gcm/engine/connection_factory_impl.h"
6
7 #include <cmath>
8
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"
17
18 class Policy;
19
20 namespace gcm {
21 namespace {
22
23 const char kMCSEndpoint[] = "http://my.server";
24 const char kMCSEndpoint2[] = "http://my.alt.server";
25
26 const int kBackoffDelayMs = 1;
27 const int kBackoffMultiplier = 2;
28
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.
33   0,
34
35   // Initial delay for exponential back-off in ms.
36   kBackoffDelayMs,
37
38   // Factor by which the waiting time will be multiplied.
39   kBackoffMultiplier,
40
41   // Fuzzing percentage. ex: 10% will spread requests randomly
42   // between 90%-100% of the calculated time.
43   0,
44
45   // Maximum amount of time we are willing to delay our request in ms.
46   10,
47
48   // Time to keep an entry from being discarded even when it
49   // has no significant state, -1 to never discard.
50   -1,
51
52   // Don't use initial delay unless the last request was an error.
53   false,
54 };
55
56 std::vector<GURL> BuildEndpoints() {
57   std::vector<GURL> endpoints;
58   endpoints.push_back(GURL(kMCSEndpoint));
59   endpoints.push_back(GURL(kMCSEndpoint2));
60   return endpoints;
61 }
62
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),
69                                    i - 1);
70   }
71   DVLOG(1) << "Expected backoff " << delay << " milliseconds.";
72   return delay;
73 }
74
75 void ReadContinuation(
76     scoped_ptr<google::protobuf::MessageLite> message) {
77 }
78
79 void WriteContinuation() {
80 }
81
82 class TestBackoffEntry : public net::BackoffEntry {
83  public:
84   explicit TestBackoffEntry(base::SimpleTestTickClock* tick_clock);
85   virtual ~TestBackoffEntry();
86
87   virtual base::TimeTicks ImplGetTimeNow() const OVERRIDE;
88
89  private:
90   base::SimpleTestTickClock* tick_clock_;
91 };
92
93 TestBackoffEntry::TestBackoffEntry(base::SimpleTestTickClock* tick_clock)
94     : BackoffEntry(&kTestBackoffPolicy),
95       tick_clock_(tick_clock) {
96 }
97
98 TestBackoffEntry::~TestBackoffEntry() {}
99
100 base::TimeTicks TestBackoffEntry::ImplGetTimeNow() const {
101   return tick_clock_->NowTicks();
102 }
103
104 // A connection factory that stubs out network requests and overrides the
105 // backoff policy.
106 class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
107  public:
108   TestConnectionFactoryImpl(const base::Closure& finished_callback);
109   virtual ~TestConnectionFactoryImpl();
110
111   void InitializeFactory();
112
113   // Overridden stubs.
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)
123           OVERRIDE;
124   virtual base::TimeTicks NowTicks() OVERRIDE;
125
126   // Helpers for verifying connection attempts are made. Connection results
127   // must be consumed.
128   void SetConnectResult(int connect_result);
129   void SetMultipleConnectResults(int connect_result, int num_expected_attempts);
130
131   // Force a login handshake to be delayed.
132   void SetDelayLogin(bool delay_login);
133
134   base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
135
136  private:
137   // Clock for controlling delay.
138   base::SimpleTestTickClock tick_clock_;
139   // The result to return on the next connect attempt.
140   int connect_result_;
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.
147   bool delay_login_;
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_;
152 };
153
154 TestConnectionFactoryImpl::TestConnectionFactoryImpl(
155     const base::Closure& finished_callback)
156     : ConnectionFactoryImpl(BuildEndpoints(),
157                             net::BackoffEntry::Policy(),
158                             NULL,
159                             NULL),
160       connect_result_(net::ERR_UNEXPECTED),
161       num_expected_attempts_(0),
162       connections_fulfilled_(true),
163       delay_login_(false),
164       finished_callback_(finished_callback),
165       fake_handler_(NULL) {
166   // Set a non-null time.
167   tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
168 }
169
170 TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
171   EXPECT_EQ(0, num_expected_attempts_);
172 }
173
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);
184   }
185   --num_expected_attempts_;
186   if (num_expected_attempts_ == 0) {
187     connect_result_ = net::ERR_UNEXPECTED;
188     connections_fulfilled_ = true;
189     finished_callback_.Run();
190   }
191 }
192
193 void TestConnectionFactoryImpl::InitHandler() {
194   EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
195   if (!delay_login_)
196     ConnectionHandlerCallback(net::OK);
197 }
198
199 scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
200     const net::BackoffEntry::Policy* const policy) {
201   return scoped_ptr<net::BackoffEntry>(new TestBackoffEntry(&tick_clock_));
202 }
203
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_);
214 }
215
216 base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
217   return tick_clock_.NowTicks();
218 }
219
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>()));
230 }
231
232 void TestConnectionFactoryImpl::SetMultipleConnectResults(
233     int connect_result,
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>()));
246   }
247 }
248
249 void TestConnectionFactoryImpl::SetDelayLogin(bool delay_login) {
250   delay_login_ = delay_login;
251   fake_handler_->set_fail_login(delay_login_);
252 }
253
254 class ConnectionFactoryImplTest : public testing::Test {
255  public:
256   ConnectionFactoryImplTest();
257   virtual ~ConnectionFactoryImplTest();
258
259   TestConnectionFactoryImpl* factory() { return &factory_; }
260
261   void WaitForConnections();
262
263  private:
264   void ConnectionsComplete();
265
266   TestConnectionFactoryImpl factory_;
267   base::MessageLoop message_loop_;
268   scoped_ptr<base::RunLoop> run_loop_;
269 };
270
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());
279 }
280 ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
281
282 void ConnectionFactoryImplTest::WaitForConnections() {
283   run_loop_->Run();
284   run_loop_.reset(new base::RunLoop());
285 }
286
287 void ConnectionFactoryImplTest::ConnectionsComplete() {
288   if (!run_loop_)
289     return;
290   run_loop_->Quit();
291 }
292
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());
298 }
299
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());
307 }
308
309 // A connection failure should result in backoff, and attempting the fallback
310 // endpoint next.
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());
317 }
318
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());
333 }
334
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,
340                                        kNumAttempts);
341
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));
350
351   factory()->SetConnectResult(net::OK);
352   WaitForConnections();
353   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
354   EXPECT_TRUE(factory()->IsEndpointReachable());
355 }
356
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());
364
365   factory()->SetConnectResult(net::ERR_FAILED);
366   factory()->OnIPAddressChanged();
367   WaitForConnections();
368
369   // Backoff should increase.
370   base::TimeTicks next_backoff = factory()->NextRetryAttempt();
371   EXPECT_GT(next_backoff, initial_backoff);
372   EXPECT_FALSE(factory()->IsEndpointReachable());
373 }
374
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());
382
383   factory()->SetConnectResult(net::ERR_FAILED);
384   factory()->OnConnectionTypeChanged(
385       net::NetworkChangeNotifier::CONNECTION_WIFI);
386   WaitForConnections();
387
388   // Backoff should increase.
389   base::TimeTicks next_backoff = factory()->NextRetryAttempt();
390   EXPECT_GT(next_backoff, initial_backoff);
391   EXPECT_FALSE(factory()->IsEndpointReachable());
392 }
393
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());
402
403   factory()->SetConnectResult(net::OK);
404   factory()->OnConnectionTypeChanged(
405       net::NetworkChangeNotifier::CONNECTION_WIFI);
406   WaitForConnections();
407   EXPECT_TRUE(factory()->IsEndpointReachable());
408
409   factory()->SetConnectResult(net::OK);
410   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
411   EXPECT_FALSE(factory()->IsEndpointReachable());
412   WaitForConnections();
413   EXPECT_TRUE(factory()->IsEndpointReachable());
414 }
415
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());
424
425   factory()->SetDelayLogin(true);
426   factory()->SetConnectResult(net::OK);
427   factory()->OnConnectionTypeChanged(
428       net::NetworkChangeNotifier::CONNECTION_WIFI);
429   WaitForConnections();
430   EXPECT_FALSE(factory()->IsEndpointReachable());
431
432   // Pump the loop, to ensure the pending backoff retry has no effect.
433   base::MessageLoop::current()->PostDelayedTask(
434       FROM_HERE,
435       base::MessageLoop::QuitClosure(),
436       base::TimeDelta::FromMilliseconds(1));
437   WaitForConnections();
438 }
439
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());
445
446   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
447   EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
448   EXPECT_FALSE(factory()->IsEndpointReachable());
449 }
450
451 TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
452   factory()->SetConnectResult(net::OK);
453   factory()->Connect();
454   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
455
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());
460
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());
466 }
467
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());
478
479   factory()->SetConnectResult(net::OK);
480   connect_time = factory()->tick_clock()->NowTicks();
481   WaitForConnections();
482   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
483
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));
491
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());
499
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());
507 }
508
509 }  // namespace
510 }  // namespace gcm