Upstream version 5.34.104.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 "net/base/backoff_entry.h"
13 #include "net/http/http_network_session.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 class Policy;
17
18 namespace gcm {
19 namespace {
20
21 const char kMCSEndpoint[] = "http://my.server";
22
23 const int kBackoffDelayMs = 1;
24 const int kBackoffMultiplier = 2;
25
26 // A backoff policy with small enough delays that tests aren't burdened.
27 const net::BackoffEntry::Policy kTestBackoffPolicy = {
28   // Number of initial errors (in sequence) to ignore before applying
29   // exponential back-off rules.
30   0,
31
32   // Initial delay for exponential back-off in ms.
33   kBackoffDelayMs,
34
35   // Factor by which the waiting time will be multiplied.
36   kBackoffMultiplier,
37
38   // Fuzzing percentage. ex: 10% will spread requests randomly
39   // between 90%-100% of the calculated time.
40   0,
41
42   // Maximum amount of time we are willing to delay our request in ms.
43   10,
44
45   // Time to keep an entry from being discarded even when it
46   // has no significant state, -1 to never discard.
47   -1,
48
49   // Don't use initial delay unless the last request was an error.
50   false,
51 };
52
53 // Helper for calculating total expected exponential backoff delay given an
54 // arbitrary number of failed attempts. See BackoffEntry::CalculateReleaseTime.
55 double CalculateBackoff(int num_attempts) {
56   double delay = kBackoffDelayMs;
57   for (int i = 1; i < num_attempts; ++i) {
58     delay += kBackoffDelayMs * pow(static_cast<double>(kBackoffMultiplier),
59                                    i - 1);
60   }
61   DVLOG(1) << "Expected backoff " << delay << " milliseconds.";
62   return delay;
63 }
64
65 // Helper methods that should never actually be called due to real connections
66 // being stubbed out.
67 void ReadContinuation(
68     scoped_ptr<google::protobuf::MessageLite> message) {
69   ADD_FAILURE();
70 }
71
72 void WriteContinuation() {
73   ADD_FAILURE();
74 }
75
76 class TestBackoffEntry : public net::BackoffEntry {
77  public:
78   explicit TestBackoffEntry(base::SimpleTestTickClock* tick_clock);
79   virtual ~TestBackoffEntry();
80
81   virtual base::TimeTicks ImplGetTimeNow() const OVERRIDE;
82
83  private:
84   base::SimpleTestTickClock* tick_clock_;
85 };
86
87 TestBackoffEntry::TestBackoffEntry(base::SimpleTestTickClock* tick_clock)
88     : BackoffEntry(&kTestBackoffPolicy),
89       tick_clock_(tick_clock) {
90 }
91
92 TestBackoffEntry::~TestBackoffEntry() {}
93
94 base::TimeTicks TestBackoffEntry::ImplGetTimeNow() const {
95   return tick_clock_->NowTicks();
96 }
97
98 // A connection factory that stubs out network requests and overrides the
99 // backoff policy.
100 class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
101  public:
102   TestConnectionFactoryImpl(const base::Closure& finished_callback);
103   virtual ~TestConnectionFactoryImpl();
104
105   // Overridden stubs.
106   virtual void ConnectImpl() OVERRIDE;
107   virtual void InitHandler() OVERRIDE;
108   virtual scoped_ptr<net::BackoffEntry> CreateBackoffEntry(
109       const net::BackoffEntry::Policy* const policy) OVERRIDE;
110   virtual base::TimeTicks NowTicks() OVERRIDE;
111
112   // Helpers for verifying connection attempts are made. Connection results
113   // must be consumed.
114   void SetConnectResult(int connect_result);
115   void SetMultipleConnectResults(int connect_result, int num_expected_attempts);
116
117   base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
118
119  private:
120   // Clock for controlling delay.
121   base::SimpleTestTickClock tick_clock_;
122   // The result to return on the next connect attempt.
123   int connect_result_;
124   // The number of expected connection attempts;
125   int num_expected_attempts_;
126   // Whether all expected connection attempts have been fulfilled since an
127   // expectation was last set.
128   bool connections_fulfilled_;
129   // Callback to invoke when all connection attempts have been made.
130   base::Closure finished_callback_;
131 };
132
133 TestConnectionFactoryImpl::TestConnectionFactoryImpl(
134     const base::Closure& finished_callback)
135     : ConnectionFactoryImpl(GURL(kMCSEndpoint),
136                             net::BackoffEntry::Policy(),
137                             NULL,
138                             NULL),
139       connect_result_(net::ERR_UNEXPECTED),
140       num_expected_attempts_(0),
141       connections_fulfilled_(true),
142       finished_callback_(finished_callback) {
143   // Set a non-null time.
144   tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
145 }
146
147 TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
148   EXPECT_EQ(0, num_expected_attempts_);
149 }
150
151 void TestConnectionFactoryImpl::ConnectImpl() {
152   ASSERT_GT(num_expected_attempts_, 0);
153
154   OnConnectDone(connect_result_);
155   if (!NextRetryAttempt().is_null()) {
156     // Advance the time to the next retry time.
157     base::TimeDelta time_till_retry =
158         NextRetryAttempt() - tick_clock_.NowTicks();
159     tick_clock_.Advance(time_till_retry);
160   }
161   --num_expected_attempts_;
162   if (num_expected_attempts_ == 0) {
163     connect_result_ = net::ERR_UNEXPECTED;
164     connections_fulfilled_ = true;
165     finished_callback_.Run();
166   }
167 }
168
169 void TestConnectionFactoryImpl::InitHandler() {
170   EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
171   ConnectionHandlerCallback(net::OK);
172 }
173
174 scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
175     const net::BackoffEntry::Policy* const policy) {
176   return scoped_ptr<net::BackoffEntry>(new TestBackoffEntry(&tick_clock_));
177 }
178
179 base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
180   return tick_clock_.NowTicks();
181 }
182
183 void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
184   DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
185   ASSERT_EQ(0, num_expected_attempts_);
186   connections_fulfilled_ = false;
187   connect_result_ = connect_result;
188   num_expected_attempts_ = 1;
189 }
190
191 void TestConnectionFactoryImpl::SetMultipleConnectResults(
192     int connect_result,
193     int num_expected_attempts) {
194   DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
195   DCHECK_GT(num_expected_attempts, 0);
196   ASSERT_EQ(0, num_expected_attempts_);
197   connections_fulfilled_ = false;
198   connect_result_ = connect_result;
199   num_expected_attempts_ = num_expected_attempts;
200 }
201
202 class ConnectionFactoryImplTest : public testing::Test {
203  public:
204   ConnectionFactoryImplTest();
205   virtual ~ConnectionFactoryImplTest();
206
207   TestConnectionFactoryImpl* factory() { return &factory_; }
208
209   void WaitForConnections();
210
211  private:
212   void ConnectionsComplete();
213
214   TestConnectionFactoryImpl factory_;
215   base::MessageLoop message_loop_;
216   scoped_ptr<base::RunLoop> run_loop_;
217 };
218
219 ConnectionFactoryImplTest::ConnectionFactoryImplTest()
220    : factory_(base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
221                          base::Unretained(this))),
222      run_loop_(new base::RunLoop()) {}
223 ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
224
225 void ConnectionFactoryImplTest::WaitForConnections() {
226   run_loop_->Run();
227   run_loop_.reset(new base::RunLoop());
228 }
229
230 void ConnectionFactoryImplTest::ConnectionsComplete() {
231   if (!run_loop_)
232     return;
233   run_loop_->Quit();
234 }
235
236 // Verify building a connection handler works.
237 TEST_F(ConnectionFactoryImplTest, Initialize) {
238   EXPECT_FALSE(factory()->IsEndpointReachable());
239   factory()->Initialize(
240       ConnectionFactory::BuildLoginRequestCallback(),
241       base::Bind(&ReadContinuation),
242       base::Bind(&WriteContinuation));
243   ConnectionHandler* handler = factory()->GetConnectionHandler();
244   ASSERT_TRUE(handler);
245   EXPECT_FALSE(factory()->IsEndpointReachable());
246 }
247
248 // An initial successful connection should not result in backoff.
249 TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
250   factory()->Initialize(
251       ConnectionFactory::BuildLoginRequestCallback(),
252       ConnectionHandler::ProtoReceivedCallback(),
253       ConnectionHandler::ProtoSentCallback());
254   factory()->SetConnectResult(net::OK);
255   factory()->Connect();
256   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
257 }
258
259 // A connection failure should result in backoff.
260 TEST_F(ConnectionFactoryImplTest, ConnectFail) {
261   factory()->Initialize(
262       ConnectionFactory::BuildLoginRequestCallback(),
263       ConnectionHandler::ProtoReceivedCallback(),
264       ConnectionHandler::ProtoSentCallback());
265   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
266   factory()->Connect();
267   EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
268 }
269
270 // A connection success after a failure should reset backoff.
271 TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
272   factory()->Initialize(
273       ConnectionFactory::BuildLoginRequestCallback(),
274       ConnectionHandler::ProtoReceivedCallback(),
275       ConnectionHandler::ProtoSentCallback());
276   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
277   base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
278   factory()->Connect();
279   WaitForConnections();
280   base::TimeTicks retry_time = factory()->NextRetryAttempt();
281   EXPECT_FALSE(retry_time.is_null());
282   EXPECT_GE((retry_time - connect_time).InMilliseconds(), CalculateBackoff(1));
283   factory()->SetConnectResult(net::OK);
284   WaitForConnections();
285   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
286 }
287
288 // Multiple connection failures should retry with an exponentially increasing
289 // backoff, then reset on success.
290 TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
291   factory()->Initialize(
292       ConnectionFactory::BuildLoginRequestCallback(),
293       ConnectionHandler::ProtoReceivedCallback(),
294       ConnectionHandler::ProtoSentCallback());
295
296   const int kNumAttempts = 5;
297   factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
298                                        kNumAttempts);
299
300   base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
301   factory()->Connect();
302   WaitForConnections();
303   base::TimeTicks retry_time = factory()->NextRetryAttempt();
304   EXPECT_FALSE(retry_time.is_null());
305   EXPECT_GE((retry_time - connect_time).InMilliseconds(),
306             CalculateBackoff(kNumAttempts));
307
308   factory()->SetConnectResult(net::OK);
309   WaitForConnections();
310   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
311 }
312
313 // IP events should reset backoff.
314 TEST_F(ConnectionFactoryImplTest, FailThenIPEvent) {
315   factory()->Initialize(
316       ConnectionFactory::BuildLoginRequestCallback(),
317       ConnectionHandler::ProtoReceivedCallback(),
318       ConnectionHandler::ProtoSentCallback());
319   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
320   factory()->Connect();
321   WaitForConnections();
322   EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
323
324   factory()->OnIPAddressChanged();
325   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
326 }
327
328 // Connection type events should reset backoff.
329 TEST_F(ConnectionFactoryImplTest, FailThenConnectionTypeEvent) {
330   factory()->Initialize(
331       ConnectionFactory::BuildLoginRequestCallback(),
332       ConnectionHandler::ProtoReceivedCallback(),
333       ConnectionHandler::ProtoSentCallback());
334   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
335   factory()->Connect();
336   WaitForConnections();
337   EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
338
339   factory()->OnConnectionTypeChanged(
340       net::NetworkChangeNotifier::CONNECTION_WIFI);
341   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
342 }
343
344 // Fail after successful connection via signal reset.
345 TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
346   factory()->Initialize(
347       ConnectionFactory::BuildLoginRequestCallback(),
348       ConnectionHandler::ProtoReceivedCallback(),
349       ConnectionHandler::ProtoSentCallback());
350   factory()->SetConnectResult(net::OK);
351   factory()->Connect();
352   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
353
354   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
355   EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
356   EXPECT_FALSE(factory()->GetConnectionHandler()->CanSendMessage());
357 }
358
359 TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
360   factory()->Initialize(
361       ConnectionFactory::BuildLoginRequestCallback(),
362       ConnectionHandler::ProtoReceivedCallback(),
363       ConnectionHandler::ProtoSentCallback());
364   factory()->SetConnectResult(net::OK);
365   factory()->Connect();
366   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
367
368   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
369   base::TimeTicks retry_time = factory()->NextRetryAttempt();
370   EXPECT_FALSE(retry_time.is_null());
371
372   const int kNumAttempts = 5;
373   for (int i = 0; i < kNumAttempts; ++i)
374     factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
375   EXPECT_EQ(retry_time, factory()->NextRetryAttempt());
376 }
377
378 // Go into backoff due to connection failure. On successful connection, receive
379 // a signal reset. The original backoff should be restored and extended, rather
380 // than a new backoff starting from scratch.
381 TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
382   factory()->Initialize(
383       ConnectionFactory::BuildLoginRequestCallback(),
384       ConnectionHandler::ProtoReceivedCallback(),
385       ConnectionHandler::ProtoSentCallback());
386   factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
387   base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
388   factory()->Connect();
389   WaitForConnections();
390   base::TimeTicks retry_time = factory()->NextRetryAttempt();
391   EXPECT_FALSE(retry_time.is_null());
392
393   factory()->SetConnectResult(net::OK);
394   connect_time = factory()->tick_clock()->NowTicks();
395   WaitForConnections();
396   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
397
398   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
399   EXPECT_FALSE(factory()->GetConnectionHandler()->CanSendMessage());
400   EXPECT_NE(retry_time, factory()->NextRetryAttempt());
401   retry_time = factory()->NextRetryAttempt();
402   EXPECT_FALSE(retry_time.is_null());
403   EXPECT_GE((retry_time - connect_time).InMilliseconds(),
404             CalculateBackoff(2));
405
406   factory()->SetConnectResult(net::OK);
407   connect_time = factory()->tick_clock()->NowTicks();
408   factory()->tick_clock()->Advance(
409       factory()->NextRetryAttempt() - connect_time);
410   WaitForConnections();
411   EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
412
413   factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
414   EXPECT_NE(retry_time, factory()->NextRetryAttempt());
415   retry_time = factory()->NextRetryAttempt();
416   EXPECT_FALSE(retry_time.is_null());
417   EXPECT_GE((retry_time - connect_time).InMilliseconds(),
418             CalculateBackoff(3));
419 }
420
421 }  // namespace
422 }  // namespace gcm