Upstream version 6.35.121.0
[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   base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
132
133  private:
134   // Clock for controlling delay.
135   base::SimpleTestTickClock tick_clock_;
136   // The result to return on the next connect attempt.
137   int connect_result_;
138   // The number of expected connection attempts;
139   int num_expected_attempts_;
140   // Whether all expected connection attempts have been fulfilled since an
141   // expectation was last set.
142   bool connections_fulfilled_;
143   // Callback to invoke when all connection attempts have been made.
144   base::Closure finished_callback_;
145   // The current fake connection handler..
146   FakeConnectionHandler* fake_handler_;
147 };
148
149 TestConnectionFactoryImpl::TestConnectionFactoryImpl(
150     const base::Closure& finished_callback)
151     : ConnectionFactoryImpl(BuildEndpoints(),
152                             net::BackoffEntry::Policy(),
153                             NULL,
154                             NULL),
155       connect_result_(net::ERR_UNEXPECTED),
156       num_expected_attempts_(0),
157       connections_fulfilled_(true),
158       finished_callback_(finished_callback),
159       fake_handler_(NULL) {
160   // Set a non-null time.
161   tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
162 }
163
164 TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
165   EXPECT_EQ(0, num_expected_attempts_);
166 }
167
168 void TestConnectionFactoryImpl::ConnectImpl() {
169   ASSERT_GT(num_expected_attempts_, 0);
170   scoped_ptr<mcs_proto::LoginRequest> request(BuildLoginRequest(0, 0, ""));
171   GetConnectionHandler()->Init(*request, NULL);
172   OnConnectDone(connect_result_);
173   if (!NextRetryAttempt().is_null()) {
174     // Advance the time to the next retry time.
175     base::TimeDelta time_till_retry =
176         NextRetryAttempt() - tick_clock_.NowTicks();
177     tick_clock_.Advance(time_till_retry);
178   }
179   --num_expected_attempts_;
180   if (num_expected_attempts_ == 0) {
181     connect_result_ = net::ERR_UNEXPECTED;
182     connections_fulfilled_ = true;
183     finished_callback_.Run();
184   }
185 }
186
187 void TestConnectionFactoryImpl::InitHandler() {
188   EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
189   ConnectionHandlerCallback(net::OK);
190 }
191
192 scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
193     const net::BackoffEntry::Policy* const policy) {
194   return scoped_ptr<net::BackoffEntry>(new TestBackoffEntry(&tick_clock_));
195 }
196
197 scoped_ptr<ConnectionHandler>
198 TestConnectionFactoryImpl::CreateConnectionHandler(
199     base::TimeDelta read_timeout,
200     const ConnectionHandler::ProtoReceivedCallback& read_callback,
201     const ConnectionHandler::ProtoSentCallback& write_callback,
202     const ConnectionHandler::ConnectionChangedCallback& connection_callback) {
203   fake_handler_ = new FakeConnectionHandler(
204       base::Bind(&ReadContinuation),
205       base::Bind(&WriteContinuation));
206   return make_scoped_ptr<ConnectionHandler>(fake_handler_);
207 }
208
209 base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
210   return tick_clock_.NowTicks();
211 }
212
213 void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
214   DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
215   ASSERT_EQ(0, num_expected_attempts_);
216   connections_fulfilled_ = false;
217   connect_result_ = connect_result;
218   num_expected_attempts_ = 1;
219   fake_handler_->ExpectOutgoingMessage(
220       MCSMessage(kLoginRequestTag,
221                  BuildLoginRequest(0, 0, "").PassAs<
222                      const google::protobuf::MessageLite>()));
223 }
224
225 void TestConnectionFactoryImpl::SetMultipleConnectResults(
226     int connect_result,
227     int num_expected_attempts) {
228   DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
229   DCHECK_GT(num_expected_attempts, 0);
230   ASSERT_EQ(0, num_expected_attempts_);
231   connections_fulfilled_ = false;
232   connect_result_ = connect_result;
233   num_expected_attempts_ = num_expected_attempts;
234   for (int i = 0 ; i < num_expected_attempts; ++i) {
235     fake_handler_->ExpectOutgoingMessage(
236         MCSMessage(kLoginRequestTag,
237                    BuildLoginRequest(0, 0, "").PassAs<
238                        const google::protobuf::MessageLite>()));
239   }
240 }
241
242 class ConnectionFactoryImplTest : public testing::Test {
243  public:
244   ConnectionFactoryImplTest();
245   virtual ~ConnectionFactoryImplTest();
246
247   TestConnectionFactoryImpl* factory() { return &factory_; }
248
249   void WaitForConnections();
250
251  private:
252   void ConnectionsComplete();
253
254   TestConnectionFactoryImpl factory_;
255   base::MessageLoop message_loop_;
256   scoped_ptr<base::RunLoop> run_loop_;
257 };
258
259 ConnectionFactoryImplTest::ConnectionFactoryImplTest()
260    : factory_(base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
261                          base::Unretained(this))),
262      run_loop_(new base::RunLoop()) {
263   factory()->Initialize(
264       ConnectionFactory::BuildLoginRequestCallback(),
265       ConnectionHandler::ProtoReceivedCallback(),
266       ConnectionHandler::ProtoSentCallback());
267 }
268 ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
269
270 void ConnectionFactoryImplTest::WaitForConnections() {
271   run_loop_->Run();
272   run_loop_.reset(new base::RunLoop());
273 }
274
275 void ConnectionFactoryImplTest::ConnectionsComplete() {
276   if (!run_loop_)
277     return;
278   run_loop_->Quit();
279 }
280
281 // Verify building a connection handler works.
282 TEST_F(ConnectionFactoryImplTest, Initialize) {
283   ConnectionHandler* handler = factory()->GetConnectionHandler();
284   ASSERT_TRUE(handler);
285   EXPECT_FALSE(factory()->IsEndpointReachable());
286 }
287
288 // An initial successful connection should not result in backoff.
289 TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
290   factory()->SetConnectResult(net::OK);
291   factory()->Connect();
292   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
293   EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[0]);
294   EXPECT_TRUE(factory()->IsEndpointReachable());
295 }
296
297 // A connection failure should result in backoff, and attempting the fallback
298 // endpoint next.
299 TEST_F(ConnectionFactoryImplTest, ConnectFail) {
300   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
301   factory()->Connect();
302   EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
303   EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[1]);
304   EXPECT_FALSE(factory()->IsEndpointReachable());
305 }
306
307 // A connection success after a failure should reset backoff.
308 TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
309   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
310   base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
311   factory()->Connect();
312   WaitForConnections();
313   EXPECT_FALSE(factory()->IsEndpointReachable());
314   base::TimeTicks retry_time = factory()->NextRetryAttempt();
315   EXPECT_FALSE(retry_time.is_null());
316   EXPECT_GE((retry_time - connect_time).InMilliseconds(), CalculateBackoff(1));
317   factory()->SetConnectResult(net::OK);
318   WaitForConnections();
319   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
320   EXPECT_TRUE(factory()->IsEndpointReachable());
321 }
322
323 // Multiple connection failures should retry with an exponentially increasing
324 // backoff, then reset on success.
325 TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
326
327   const int kNumAttempts = 5;
328   factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
329                                        kNumAttempts);
330
331   base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
332   factory()->Connect();
333   WaitForConnections();
334   EXPECT_FALSE(factory()->IsEndpointReachable());
335   base::TimeTicks retry_time = factory()->NextRetryAttempt();
336   EXPECT_FALSE(retry_time.is_null());
337   EXPECT_GE((retry_time - connect_time).InMilliseconds(),
338             CalculateBackoff(kNumAttempts));
339
340   factory()->SetConnectResult(net::OK);
341   WaitForConnections();
342   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
343   EXPECT_TRUE(factory()->IsEndpointReachable());
344 }
345
346 // IP events should trigger canary connections.
347 TEST_F(ConnectionFactoryImplTest, FailThenIPEvent) {
348   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
349   factory()->Connect();
350   WaitForConnections();
351   base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
352   EXPECT_FALSE(initial_backoff.is_null());
353
354   factory()->SetConnectResult(net::ERR_FAILED);
355   factory()->OnIPAddressChanged();
356   WaitForConnections();
357
358   // Backoff should increase.
359   base::TimeTicks next_backoff = factory()->NextRetryAttempt();
360   EXPECT_GT(next_backoff, initial_backoff);
361   EXPECT_FALSE(factory()->IsEndpointReachable());
362 }
363
364 // Connection type events should trigger canary connections.
365 TEST_F(ConnectionFactoryImplTest, FailThenConnectionTypeEvent) {
366   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
367   factory()->Connect();
368   WaitForConnections();
369   base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
370   EXPECT_FALSE(initial_backoff.is_null());
371
372   factory()->SetConnectResult(net::ERR_FAILED);
373   factory()->OnConnectionTypeChanged(
374       net::NetworkChangeNotifier::CONNECTION_WIFI);
375   WaitForConnections();
376
377   // Backoff should increase.
378   base::TimeTicks next_backoff = factory()->NextRetryAttempt();
379   EXPECT_GT(next_backoff, initial_backoff);
380   EXPECT_FALSE(factory()->IsEndpointReachable());
381 }
382
383 // Verify that we reconnect even if a canary succeeded then disconnected while
384 // a backoff was pending.
385 TEST_F(ConnectionFactoryImplTest, CanarySucceedsThenDisconnects) {
386   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
387   factory()->Connect();
388   WaitForConnections();
389   base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
390   EXPECT_FALSE(initial_backoff.is_null());
391
392   factory()->SetConnectResult(net::OK);
393   factory()->OnConnectionTypeChanged(
394       net::NetworkChangeNotifier::CONNECTION_WIFI);
395   WaitForConnections();
396   EXPECT_TRUE(factory()->IsEndpointReachable());
397
398   factory()->SetConnectResult(net::OK);
399   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
400   EXPECT_FALSE(factory()->IsEndpointReachable());
401   WaitForConnections();
402   EXPECT_TRUE(factory()->IsEndpointReachable());
403 }
404
405 // Fail after successful connection via signal reset.
406 TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
407   factory()->SetConnectResult(net::OK);
408   factory()->Connect();
409   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
410
411   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
412   EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
413   EXPECT_FALSE(factory()->IsEndpointReachable());
414 }
415
416 TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
417   factory()->SetConnectResult(net::OK);
418   factory()->Connect();
419   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
420
421   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
422   base::TimeTicks retry_time = factory()->NextRetryAttempt();
423   EXPECT_FALSE(retry_time.is_null());
424   EXPECT_FALSE(factory()->IsEndpointReachable());
425
426   const int kNumAttempts = 5;
427   for (int i = 0; i < kNumAttempts; ++i)
428     factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
429   EXPECT_EQ(retry_time, factory()->NextRetryAttempt());
430   EXPECT_FALSE(factory()->IsEndpointReachable());
431 }
432
433 // Go into backoff due to connection failure. On successful connection, receive
434 // a signal reset. The original backoff should be restored and extended, rather
435 // than a new backoff starting from scratch.
436 TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
437   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
438   base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
439   factory()->Connect();
440   WaitForConnections();
441   base::TimeTicks retry_time = factory()->NextRetryAttempt();
442   EXPECT_FALSE(retry_time.is_null());
443
444   factory()->SetConnectResult(net::OK);
445   connect_time = factory()->tick_clock()->NowTicks();
446   WaitForConnections();
447   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
448
449   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
450   EXPECT_FALSE(factory()->IsEndpointReachable());
451   EXPECT_NE(retry_time, factory()->NextRetryAttempt());
452   retry_time = factory()->NextRetryAttempt();
453   EXPECT_FALSE(retry_time.is_null());
454   EXPECT_GE((retry_time - connect_time).InMilliseconds(),
455             CalculateBackoff(2));
456
457   factory()->SetConnectResult(net::OK);
458   connect_time = factory()->tick_clock()->NowTicks();
459   factory()->tick_clock()->Advance(
460       factory()->NextRetryAttempt() - connect_time);
461   WaitForConnections();
462   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
463   EXPECT_TRUE(factory()->IsEndpointReachable());
464
465   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
466   EXPECT_NE(retry_time, factory()->NextRetryAttempt());
467   retry_time = factory()->NextRetryAttempt();
468   EXPECT_FALSE(retry_time.is_null());
469   EXPECT_GE((retry_time - connect_time).InMilliseconds(),
470             CalculateBackoff(3));
471   EXPECT_FALSE(factory()->IsEndpointReachable());
472 }
473
474 }  // namespace
475 }  // namespace gcm