Update ASan/Android runtime and setup script to LLVM r200682.
[chromium-blink-merge.git] / google_apis / gcm / engine / connection_factory_impl_unittest.cc
blobd0fd2455fb21e960a5a45b79c259afdd7542eafb
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 "net/base/backoff_entry.h"
13 #include "net/http/http_network_session.h"
14 #include "testing/gtest/include/gtest/gtest.h"
16 class Policy;
18 namespace gcm {
19 namespace {
21 const char kMCSEndpoint[] = "http://my.server";
23 const int kBackoffDelayMs = 1;
24 const int kBackoffMultiplier = 2;
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.
32 // Initial delay for exponential back-off in ms.
33 kBackoffDelayMs,
35 // Factor by which the waiting time will be multiplied.
36 kBackoffMultiplier,
38 // Fuzzing percentage. ex: 10% will spread requests randomly
39 // between 90%-100% of the calculated time.
42 // Maximum amount of time we are willing to delay our request in ms.
43 10,
45 // Time to keep an entry from being discarded even when it
46 // has no significant state, -1 to never discard.
47 -1,
49 // Don't use initial delay unless the last request was an error.
50 false,
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);
61 DVLOG(1) << "Expected backoff " << delay << " milliseconds.";
62 return delay;
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();
72 void WriteContinuation() {
73 ADD_FAILURE();
76 class TestBackoffEntry : public net::BackoffEntry {
77 public:
78 explicit TestBackoffEntry(base::SimpleTestTickClock* tick_clock);
79 virtual ~TestBackoffEntry();
81 virtual base::TimeTicks ImplGetTimeNow() const OVERRIDE;
83 private:
84 base::SimpleTestTickClock* tick_clock_;
87 TestBackoffEntry::TestBackoffEntry(base::SimpleTestTickClock* tick_clock)
88 : BackoffEntry(&kTestBackoffPolicy),
89 tick_clock_(tick_clock) {
92 TestBackoffEntry::~TestBackoffEntry() {}
94 base::TimeTicks TestBackoffEntry::ImplGetTimeNow() const {
95 return tick_clock_->NowTicks();
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();
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;
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);
117 base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
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_;
133 TestConnectionFactoryImpl::TestConnectionFactoryImpl(
134 const base::Closure& finished_callback)
135 : ConnectionFactoryImpl(GURL(kMCSEndpoint), NULL, NULL),
136 connect_result_(net::ERR_UNEXPECTED),
137 num_expected_attempts_(0),
138 connections_fulfilled_(true),
139 finished_callback_(finished_callback) {
140 // Set a non-null time.
141 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
144 TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
145 EXPECT_EQ(0, num_expected_attempts_);
148 void TestConnectionFactoryImpl::ConnectImpl() {
149 ASSERT_GT(num_expected_attempts_, 0);
151 OnConnectDone(connect_result_);
152 if (!NextRetryAttempt().is_null()) {
153 // Advance the time to the next retry time.
154 base::TimeDelta time_till_retry =
155 NextRetryAttempt() - tick_clock_.NowTicks();
156 tick_clock_.Advance(time_till_retry);
158 --num_expected_attempts_;
159 if (num_expected_attempts_ == 0) {
160 connect_result_ = net::ERR_UNEXPECTED;
161 connections_fulfilled_ = true;
162 finished_callback_.Run();
166 void TestConnectionFactoryImpl::InitHandler() {
167 EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
168 ConnectionHandlerCallback(net::OK);
171 scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
172 const net::BackoffEntry::Policy* const policy) {
173 return scoped_ptr<net::BackoffEntry>(new TestBackoffEntry(&tick_clock_));
176 base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
177 return tick_clock_.NowTicks();
180 void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
181 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
182 ASSERT_EQ(0, num_expected_attempts_);
183 connections_fulfilled_ = false;
184 connect_result_ = connect_result;
185 num_expected_attempts_ = 1;
188 void TestConnectionFactoryImpl::SetMultipleConnectResults(
189 int connect_result,
190 int num_expected_attempts) {
191 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
192 DCHECK_GT(num_expected_attempts, 0);
193 ASSERT_EQ(0, num_expected_attempts_);
194 connections_fulfilled_ = false;
195 connect_result_ = connect_result;
196 num_expected_attempts_ = num_expected_attempts;
199 class ConnectionFactoryImplTest : public testing::Test {
200 public:
201 ConnectionFactoryImplTest();
202 virtual ~ConnectionFactoryImplTest();
204 TestConnectionFactoryImpl* factory() { return &factory_; }
206 void WaitForConnections();
208 private:
209 void ConnectionsComplete();
211 TestConnectionFactoryImpl factory_;
212 base::MessageLoop message_loop_;
213 scoped_ptr<base::RunLoop> run_loop_;
216 ConnectionFactoryImplTest::ConnectionFactoryImplTest()
217 : factory_(base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
218 base::Unretained(this))),
219 run_loop_(new base::RunLoop()) {}
220 ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
222 void ConnectionFactoryImplTest::WaitForConnections() {
223 run_loop_->Run();
224 run_loop_.reset(new base::RunLoop());
227 void ConnectionFactoryImplTest::ConnectionsComplete() {
228 if (!run_loop_)
229 return;
230 run_loop_->Quit();
233 // Verify building a connection handler works.
234 TEST_F(ConnectionFactoryImplTest, Initialize) {
235 EXPECT_FALSE(factory()->IsEndpointReachable());
236 factory()->Initialize(
237 ConnectionFactory::BuildLoginRequestCallback(),
238 base::Bind(&ReadContinuation),
239 base::Bind(&WriteContinuation));
240 ConnectionHandler* handler = factory()->GetConnectionHandler();
241 ASSERT_TRUE(handler);
242 EXPECT_FALSE(factory()->IsEndpointReachable());
245 // An initial successful connection should not result in backoff.
246 TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
247 factory()->Initialize(
248 ConnectionFactory::BuildLoginRequestCallback(),
249 ConnectionHandler::ProtoReceivedCallback(),
250 ConnectionHandler::ProtoSentCallback());
251 factory()->SetConnectResult(net::OK);
252 factory()->Connect();
253 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
256 // A connection failure should result in backoff.
257 TEST_F(ConnectionFactoryImplTest, ConnectFail) {
258 factory()->Initialize(
259 ConnectionFactory::BuildLoginRequestCallback(),
260 ConnectionHandler::ProtoReceivedCallback(),
261 ConnectionHandler::ProtoSentCallback());
262 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
263 factory()->Connect();
264 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
267 // A connection success after a failure should reset backoff.
268 TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
269 factory()->Initialize(
270 ConnectionFactory::BuildLoginRequestCallback(),
271 ConnectionHandler::ProtoReceivedCallback(),
272 ConnectionHandler::ProtoSentCallback());
273 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
274 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
275 factory()->Connect();
276 WaitForConnections();
277 base::TimeTicks retry_time = factory()->NextRetryAttempt();
278 EXPECT_FALSE(retry_time.is_null());
279 EXPECT_GE((retry_time - connect_time).InMilliseconds(), CalculateBackoff(1));
280 factory()->SetConnectResult(net::OK);
281 WaitForConnections();
282 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
285 // Multiple connection failures should retry with an exponentially increasing
286 // backoff, then reset on success.
287 TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
288 factory()->Initialize(
289 ConnectionFactory::BuildLoginRequestCallback(),
290 ConnectionHandler::ProtoReceivedCallback(),
291 ConnectionHandler::ProtoSentCallback());
293 const int kNumAttempts = 5;
294 factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
295 kNumAttempts);
297 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
298 factory()->Connect();
299 WaitForConnections();
300 base::TimeTicks retry_time = factory()->NextRetryAttempt();
301 EXPECT_FALSE(retry_time.is_null());
302 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
303 CalculateBackoff(kNumAttempts));
305 factory()->SetConnectResult(net::OK);
306 WaitForConnections();
307 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
310 // IP events should reset backoff.
311 TEST_F(ConnectionFactoryImplTest, FailThenIPEvent) {
312 factory()->Initialize(
313 ConnectionFactory::BuildLoginRequestCallback(),
314 ConnectionHandler::ProtoReceivedCallback(),
315 ConnectionHandler::ProtoSentCallback());
316 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
317 factory()->Connect();
318 WaitForConnections();
319 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
321 factory()->OnIPAddressChanged();
322 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
325 // Connection type events should reset backoff.
326 TEST_F(ConnectionFactoryImplTest, FailThenConnectionTypeEvent) {
327 factory()->Initialize(
328 ConnectionFactory::BuildLoginRequestCallback(),
329 ConnectionHandler::ProtoReceivedCallback(),
330 ConnectionHandler::ProtoSentCallback());
331 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
332 factory()->Connect();
333 WaitForConnections();
334 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
336 factory()->OnConnectionTypeChanged(
337 net::NetworkChangeNotifier::CONNECTION_WIFI);
338 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
341 // Fail after successful connection via signal reset.
342 TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
343 factory()->Initialize(
344 ConnectionFactory::BuildLoginRequestCallback(),
345 ConnectionHandler::ProtoReceivedCallback(),
346 ConnectionHandler::ProtoSentCallback());
347 factory()->SetConnectResult(net::OK);
348 factory()->Connect();
349 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
351 factory()->SignalConnectionReset();
352 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
355 TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
356 factory()->Initialize(
357 ConnectionFactory::BuildLoginRequestCallback(),
358 ConnectionHandler::ProtoReceivedCallback(),
359 ConnectionHandler::ProtoSentCallback());
360 factory()->SetConnectResult(net::OK);
361 factory()->Connect();
362 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
364 factory()->SignalConnectionReset();
365 base::TimeTicks retry_time = factory()->NextRetryAttempt();
366 EXPECT_FALSE(retry_time.is_null());
368 const int kNumAttempts = 5;
369 for (int i = 0; i < kNumAttempts; ++i)
370 factory()->SignalConnectionReset();
371 EXPECT_EQ(retry_time, factory()->NextRetryAttempt());
374 // Go into backoff due to connection failure. On successful connection, receive
375 // a signal reset. The original backoff should be restored and extended, rather
376 // than a new backoff starting from scratch.
377 TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
378 factory()->Initialize(
379 ConnectionFactory::BuildLoginRequestCallback(),
380 ConnectionHandler::ProtoReceivedCallback(),
381 ConnectionHandler::ProtoSentCallback());
382 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
383 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
384 factory()->Connect();
385 WaitForConnections();
386 base::TimeTicks retry_time = factory()->NextRetryAttempt();
387 EXPECT_FALSE(retry_time.is_null());
389 factory()->SetConnectResult(net::OK);
390 connect_time = factory()->tick_clock()->NowTicks();
391 WaitForConnections();
392 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
394 factory()->SignalConnectionReset();
395 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
396 retry_time = factory()->NextRetryAttempt();
397 EXPECT_FALSE(retry_time.is_null());
398 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
399 CalculateBackoff(2));
401 factory()->SetConnectResult(net::OK);
402 connect_time = factory()->tick_clock()->NowTicks();
403 factory()->tick_clock()->Advance(
404 factory()->NextRetryAttempt() - connect_time);
405 WaitForConnections();
406 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
408 factory()->SignalConnectionReset();
409 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
410 retry_time = factory()->NextRetryAttempt();
411 EXPECT_FALSE(retry_time.is_null());
412 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
413 CalculateBackoff(3));
416 } // namespace
417 } // namespace gcm