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 #include <memory>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/optional.h"
13 #include "base/run_loop.h"
14 #include "base/test/simple_test_tick_clock.h"
15 #include "base/test/task_environment.h"
16 #include "base/threading/thread_task_runner_handle.h"
17 #include "google_apis/gcm/base/mcs_util.h"
18 #include "google_apis/gcm/engine/fake_connection_handler.h"
19 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
20 #include "mojo/public/cpp/bindings/pending_receiver.h"
21 #include "net/base/backoff_entry.h"
22 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
23 #include "net/url_request/url_request_test_util.h"
24 #include "services/network/network_context.h"
25 #include "services/network/network_service.h"
26 #include "services/network/public/mojom/proxy_resolving_socket.mojom.h"
27 #include "services/network/test/fake_test_cert_verifier_params_factory.h"
28 #include "services/network/test/test_network_connection_tracker.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30
31 class Policy;
32
33 namespace gcm {
34 namespace {
35
36 const char kMCSEndpoint[] = "http://my.server";
37 const char kMCSEndpoint2[] = "http://my.alt.server";
38
39 const int kBackoffDelayMs = 1;
40 const int kBackoffMultiplier = 2;
41
42 // A backoff policy with small enough delays that tests aren't burdened.
43 const net::BackoffEntry::Policy kTestBackoffPolicy = {
44 // Number of initial errors (in sequence) to ignore before applying
45 // exponential back-off rules.
46 0,
47
48 // Initial delay for exponential back-off in ms.
49 kBackoffDelayMs,
50
51 // Factor by which the waiting time will be multiplied.
52 kBackoffMultiplier,
53
54 // Fuzzing percentage. ex: 10% will spread requests randomly
55 // between 90%-100% of the calculated time.
56 0,
57
58 // Maximum amount of time we are willing to delay our request in ms.
59 10,
60
61 // Time to keep an entry from being discarded even when it
62 // has no significant state, -1 to never discard.
63 -1,
64
65 // Don't use initial delay unless the last request was an error.
66 false,
67 };
68
BuildEndpoints()69 std::vector<GURL> BuildEndpoints() {
70 std::vector<GURL> endpoints;
71 endpoints.push_back(GURL(kMCSEndpoint));
72 endpoints.push_back(GURL(kMCSEndpoint2));
73 return endpoints;
74 }
75
76 // Helper for calculating total expected exponential backoff delay given an
77 // arbitrary number of failed attempts. See BackoffEntry::CalculateReleaseTime.
CalculateBackoff(int num_attempts)78 double CalculateBackoff(int num_attempts) {
79 double delay = kBackoffDelayMs;
80 for (int i = 1; i < num_attempts; ++i) {
81 delay += kBackoffDelayMs * pow(static_cast<double>(kBackoffMultiplier),
82 i - 1);
83 }
84 DVLOG(1) << "Expected backoff " << delay << " milliseconds.";
85 return delay;
86 }
87
ReadContinuation(std::unique_ptr<google::protobuf::MessageLite> message)88 void ReadContinuation(std::unique_ptr<google::protobuf::MessageLite> message) {}
89
WriteContinuation()90 void WriteContinuation() {
91 }
92
93 // A connection factory that stubs out network requests and overrides the
94 // backoff policy.
95 class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
96 public:
97 TestConnectionFactoryImpl(
98 GetProxyResolvingFactoryCallback get_socket_factory_callback,
99 base::RepeatingClosure finished_callback);
100 ~TestConnectionFactoryImpl() override;
101
102 void InitializeFactory();
103
104 // Overridden stubs.
105 void StartConnection() override;
106 void InitHandler(mojo::ScopedDataPipeConsumerHandle receive_stream,
107 mojo::ScopedDataPipeProducerHandle send_stream) override;
108 std::unique_ptr<net::BackoffEntry> CreateBackoffEntry(
109 const net::BackoffEntry::Policy* const policy) override;
110 std::unique_ptr<ConnectionHandler> CreateConnectionHandler(
111 base::TimeDelta read_timeout,
112 const ConnectionHandler::ProtoReceivedCallback& read_callback,
113 const ConnectionHandler::ProtoSentCallback& write_callback,
114 const ConnectionHandler::ConnectionChangedCallback& connection_callback)
115 override;
116 base::TimeTicks NowTicks() override;
117
118 // Helpers for verifying connection attempts are made. Connection results
119 // must be consumed.
120 void SetConnectResult(int connect_result);
121 void SetMultipleConnectResults(int connect_result, int num_expected_attempts);
122
123 // Force a login handshake to be delayed.
124 void SetDelayLogin(bool delay_login);
125
126 // Simulate a socket error.
127 void SetSocketError();
128
tick_clock()129 base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
130
131 private:
132 // Clock for controlling delay.
133 base::SimpleTestTickClock tick_clock_;
134 // The result to return on the next connect attempt.
135 int connect_result_;
136 // The number of expected connection attempts;
137 int num_expected_attempts_;
138 // Whether all expected connection attempts have been fulfilled since an
139 // expectation was last set.
140 bool connections_fulfilled_;
141 // Whether to delay a login handshake completion or not.
142 bool delay_login_;
143 // Callback to invoke when all connection attempts have been made.
144 base::RepeatingClosure finished_callback_;
145 // A temporary scoped pointer to make sure we don't leak the handler in the
146 // cases it's never consumed by the ConnectionFactory.
147 std::unique_ptr<FakeConnectionHandler> scoped_handler_;
148 // The current fake connection handler..
149 FakeConnectionHandler* fake_handler_;
150 // Dummy GCM Stats recorder.
151 FakeGCMStatsRecorder dummy_recorder_;
152 // Dummy mojo pipes.
153 mojo::DataPipe receive_pipe_;
154 mojo::DataPipe send_pipe_;
155 };
156
TestConnectionFactoryImpl(GetProxyResolvingFactoryCallback get_socket_factory_callback,base::RepeatingClosure finished_callback)157 TestConnectionFactoryImpl::TestConnectionFactoryImpl(
158 GetProxyResolvingFactoryCallback get_socket_factory_callback,
159 base::RepeatingClosure finished_callback)
160 : ConnectionFactoryImpl(
161 BuildEndpoints(),
162 net::BackoffEntry::Policy(),
163 get_socket_factory_callback,
164 base::ThreadTaskRunnerHandle::Get(),
165 &dummy_recorder_,
166 network::TestNetworkConnectionTracker::GetInstance()),
167 connect_result_(net::ERR_UNEXPECTED),
168 num_expected_attempts_(0),
169 connections_fulfilled_(true),
170 delay_login_(false),
171 finished_callback_(finished_callback),
172 scoped_handler_(std::make_unique<FakeConnectionHandler>(
173 base::BindRepeating(&ReadContinuation),
174 base::BindRepeating(&WriteContinuation))),
175 fake_handler_(scoped_handler_.get()) {
176 // Set a non-null time.
177 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
178 }
179
~TestConnectionFactoryImpl()180 TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
181 EXPECT_EQ(0, num_expected_attempts_);
182 }
183
StartConnection()184 void TestConnectionFactoryImpl::StartConnection() {
185 ASSERT_GT(num_expected_attempts_, 0);
186 ASSERT_FALSE(GetConnectionHandler()->CanSendMessage());
187 std::unique_ptr<mcs_proto::LoginRequest> request(BuildLoginRequest(0, 0, ""));
188 GetConnectionHandler()->Init(*request,
189 std::move(receive_pipe_.consumer_handle),
190 std::move(send_pipe_.producer_handle));
191 OnConnectDone(connect_result_, net::IPEndPoint(), net::IPEndPoint(),
192 mojo::ScopedDataPipeConsumerHandle(),
193 mojo::ScopedDataPipeProducerHandle());
194 if (!NextRetryAttempt().is_null()) {
195 // Advance the time to the next retry time.
196 base::TimeDelta time_till_retry =
197 NextRetryAttempt() - tick_clock_.NowTicks();
198 tick_clock_.Advance(time_till_retry);
199 }
200 --num_expected_attempts_;
201 if (num_expected_attempts_ == 0) {
202 connect_result_ = net::ERR_UNEXPECTED;
203 connections_fulfilled_ = true;
204 finished_callback_.Run();
205 }
206 }
207
InitHandler(mojo::ScopedDataPipeConsumerHandle receive_stream,mojo::ScopedDataPipeProducerHandle send_stream)208 void TestConnectionFactoryImpl::InitHandler(
209 mojo::ScopedDataPipeConsumerHandle receive_stream,
210 mojo::ScopedDataPipeProducerHandle send_stream) {
211 EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
212 if (!delay_login_)
213 ConnectionHandlerCallback(net::OK);
214 }
215
216 std::unique_ptr<net::BackoffEntry>
CreateBackoffEntry(const net::BackoffEntry::Policy * const policy)217 TestConnectionFactoryImpl::CreateBackoffEntry(
218 const net::BackoffEntry::Policy* const policy) {
219 return std::make_unique<net::BackoffEntry>(&kTestBackoffPolicy, &tick_clock_);
220 }
221
222 std::unique_ptr<ConnectionHandler>
CreateConnectionHandler(base::TimeDelta read_timeout,const ConnectionHandler::ProtoReceivedCallback & read_callback,const ConnectionHandler::ProtoSentCallback & write_callback,const ConnectionHandler::ConnectionChangedCallback & connection_callback)223 TestConnectionFactoryImpl::CreateConnectionHandler(
224 base::TimeDelta read_timeout,
225 const ConnectionHandler::ProtoReceivedCallback& read_callback,
226 const ConnectionHandler::ProtoSentCallback& write_callback,
227 const ConnectionHandler::ConnectionChangedCallback& connection_callback) {
228 return std::move(scoped_handler_);
229 }
230
NowTicks()231 base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
232 return tick_clock_.NowTicks();
233 }
234
SetConnectResult(int connect_result)235 void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
236 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
237 ASSERT_EQ(0, num_expected_attempts_);
238 connections_fulfilled_ = false;
239 connect_result_ = connect_result;
240 num_expected_attempts_ = 1;
241 fake_handler_->ExpectOutgoingMessage(
242 MCSMessage(kLoginRequestTag, BuildLoginRequest(0, 0, "")));
243 }
244
SetMultipleConnectResults(int connect_result,int num_expected_attempts)245 void TestConnectionFactoryImpl::SetMultipleConnectResults(
246 int connect_result,
247 int num_expected_attempts) {
248 DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
249 DCHECK_GT(num_expected_attempts, 0);
250 ASSERT_EQ(0, num_expected_attempts_);
251 connections_fulfilled_ = false;
252 connect_result_ = connect_result;
253 num_expected_attempts_ = num_expected_attempts;
254 for (int i = 0 ; i < num_expected_attempts; ++i) {
255 fake_handler_->ExpectOutgoingMessage(
256 MCSMessage(kLoginRequestTag, BuildLoginRequest(0, 0, "")));
257 }
258 }
259
SetDelayLogin(bool delay_login)260 void TestConnectionFactoryImpl::SetDelayLogin(bool delay_login) {
261 delay_login_ = delay_login;
262 fake_handler_->set_fail_login(delay_login_);
263 }
264
SetSocketError()265 void TestConnectionFactoryImpl::SetSocketError() {
266 fake_handler_->set_had_error(true);
267 }
268
269 } // namespace
270
271 class ConnectionFactoryImplTest
272 : public testing::Test,
273 public ConnectionFactory::ConnectionListener {
274 public:
275 ConnectionFactoryImplTest();
276 ~ConnectionFactoryImplTest() override;
277
factory()278 TestConnectionFactoryImpl* factory() { return &factory_; }
connected_server()279 GURL& connected_server() { return connected_server_; }
280
281 void WaitForConnections();
282
283 // ConnectionFactory::ConnectionListener
284 void OnConnected(const GURL& current_server,
285 const net::IPEndPoint& ip_endpoint) override;
286 void OnDisconnected() override;
287
288 // Get the client events recorded by the event tracker.
289 const google::protobuf::RepeatedPtrField<mcs_proto::ClientEvent>
GetClientEvents()290 GetClientEvents() {
291 mcs_proto::LoginRequest login_request;
292 factory()->event_tracker_.WriteToLoginRequest(&login_request);
293 return login_request.client_event();
294 }
295
GetRunLoop()296 base::RunLoop* GetRunLoop() { return run_loop_.get(); }
297
298 private:
GetProxyResolvingSocketFactory(mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory> receiver)299 void GetProxyResolvingSocketFactory(
300 mojo::PendingReceiver<network::mojom::ProxyResolvingSocketFactory>
301 receiver) {
302 network_context_->CreateProxyResolvingSocketFactory(std::move(receiver));
303 }
304 void ConnectionsComplete();
305
306 std::unique_ptr<network::TestNetworkConnectionTracker>
307 network_connection_tracker_;
308 base::test::TaskEnvironment task_environment_;
309 TestConnectionFactoryImpl factory_;
310 std::unique_ptr<base::RunLoop> run_loop_;
311
312 GURL connected_server_;
313 std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
314 std::unique_ptr<network::NetworkService> network_service_;
315 mojo::Remote<network::mojom::NetworkContext> network_context_remote_;
316 std::unique_ptr<network::NetworkContext> network_context_;
317 };
318
ConnectionFactoryImplTest()319 ConnectionFactoryImplTest::ConnectionFactoryImplTest()
320 : network_connection_tracker_(
321 network::TestNetworkConnectionTracker::CreateInstance()),
322 task_environment_(base::test::TaskEnvironment::MainThreadType::IO),
323 factory_(
324 base::BindRepeating(
325 &ConnectionFactoryImplTest::GetProxyResolvingSocketFactory,
326 base::Unretained(this)),
327 base::BindRepeating(&ConnectionFactoryImplTest::ConnectionsComplete,
328 base::Unretained(this))),
329 run_loop_(new base::RunLoop()),
330 network_change_notifier_(
331 net::NetworkChangeNotifier::CreateMockIfNeeded()),
332 network_service_(network::NetworkService::CreateForTesting()) {
333 network::mojom::NetworkContextParamsPtr params =
334 network::mojom::NetworkContextParams::New();
335 // Use a dummy CertVerifier that always passes cert verification, since
336 // these unittests don't need to test CertVerifier behavior.
337 params->cert_verifier_params =
338 network::FakeTestCertVerifierParamsFactory::GetCertVerifierParams();
339 // Use a fixed proxy config, to avoid dependencies on local network
340 // configuration.
341 params->initial_proxy_config = net::ProxyConfigWithAnnotation::CreateDirect();
342 network_context_ = std::make_unique<network::NetworkContext>(
343 network_service_.get(),
344 network_context_remote_.BindNewPipeAndPassReceiver(), std::move(params));
345 factory()->SetConnectionListener(this);
346 factory()->Initialize(ConnectionFactory::BuildLoginRequestCallback(),
347 ConnectionHandler::ProtoReceivedCallback(),
348 ConnectionHandler::ProtoSentCallback());
349 }
~ConnectionFactoryImplTest()350 ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
351
WaitForConnections()352 void ConnectionFactoryImplTest::WaitForConnections() {
353 run_loop_->Run();
354 run_loop_.reset(new base::RunLoop());
355 }
356
ConnectionsComplete()357 void ConnectionFactoryImplTest::ConnectionsComplete() {
358 if (!run_loop_)
359 return;
360 run_loop_->Quit();
361 }
362
OnConnected(const GURL & current_server,const net::IPEndPoint & ip_endpoint)363 void ConnectionFactoryImplTest::OnConnected(
364 const GURL& current_server,
365 const net::IPEndPoint& ip_endpoint) {
366 connected_server_ = current_server;
367 }
368
OnDisconnected()369 void ConnectionFactoryImplTest::OnDisconnected() {
370 connected_server_ = GURL();
371 }
372
373 // Verify building a connection handler works.
TEST_F(ConnectionFactoryImplTest,Initialize)374 TEST_F(ConnectionFactoryImplTest, Initialize) {
375 ASSERT_FALSE(factory()->GetConnectionHandler());
376 EXPECT_FALSE(factory()->IsEndpointReachable());
377 EXPECT_FALSE(connected_server().is_valid());
378 }
379
380 // An initial successful connection should not result in backoff.
TEST_F(ConnectionFactoryImplTest,ConnectSuccess)381 TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
382 factory()->SetConnectResult(net::OK);
383 factory()->Connect();
384 ASSERT_TRUE(factory()->GetConnectionHandler());
385 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
386 EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[0]);
387 EXPECT_TRUE(factory()->IsEndpointReachable());
388 EXPECT_TRUE(connected_server().is_valid());
389 }
390
391 // A connection failure should result in backoff, and attempting the fallback
392 // endpoint next.
TEST_F(ConnectionFactoryImplTest,ConnectFail)393 TEST_F(ConnectionFactoryImplTest, ConnectFail) {
394 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
395 factory()->Connect();
396 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
397 EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[1]);
398 EXPECT_FALSE(factory()->IsEndpointReachable());
399 EXPECT_FALSE(connected_server().is_valid());
400 }
401
402 // A connection success after a failure should reset backoff.
TEST_F(ConnectionFactoryImplTest,FailThenSucceed)403 TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
404 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
405 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
406 factory()->Connect();
407 WaitForConnections();
408 EXPECT_FALSE(factory()->IsEndpointReachable());
409 EXPECT_FALSE(connected_server().is_valid());
410 base::TimeTicks retry_time = factory()->NextRetryAttempt();
411 EXPECT_FALSE(retry_time.is_null());
412 EXPECT_GE((retry_time - connect_time).InMilliseconds(), CalculateBackoff(1));
413 factory()->SetConnectResult(net::OK);
414 WaitForConnections();
415 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
416 EXPECT_TRUE(factory()->IsEndpointReachable());
417 EXPECT_TRUE(connected_server().is_valid());
418 }
419
420 // Multiple connection failures should retry with an exponentially increasing
421 // backoff, then reset on success.
TEST_F(ConnectionFactoryImplTest,MultipleFailuresThenSucceed)422 TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
423 const int kNumAttempts = 5;
424 factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
425 kNumAttempts);
426
427 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
428 factory()->Connect();
429 WaitForConnections();
430 EXPECT_FALSE(factory()->IsEndpointReachable());
431 EXPECT_FALSE(connected_server().is_valid());
432 base::TimeTicks retry_time = factory()->NextRetryAttempt();
433 EXPECT_FALSE(retry_time.is_null());
434 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
435 CalculateBackoff(kNumAttempts));
436
437 // There should be one failed client event for each failed connection.
438 const auto client_events = GetClientEvents();
439 ASSERT_EQ(kNumAttempts, client_events.size());
440
441 for (const auto& client_event : client_events) {
442 EXPECT_EQ(mcs_proto::ClientEvent::FAILED_CONNECTION, client_event.type());
443 EXPECT_EQ(net::ERR_CONNECTION_FAILED, client_event.error_code());
444 }
445
446 factory()->SetConnectResult(net::OK);
447 WaitForConnections();
448 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
449 EXPECT_TRUE(factory()->IsEndpointReachable());
450 EXPECT_TRUE(connected_server().is_valid());
451
452 // Old client events should have been reset after the successful connection.
453 const auto new_client_events = GetClientEvents();
454 ASSERT_EQ(0, new_client_events.size());
455 }
456
457 // Network change events should trigger canary connections.
TEST_F(ConnectionFactoryImplTest,FailThenNetworkChangeEvent)458 TEST_F(ConnectionFactoryImplTest, FailThenNetworkChangeEvent) {
459 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
460 factory()->Connect();
461 WaitForConnections();
462 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
463 EXPECT_FALSE(initial_backoff.is_null());
464
465 factory()->SetConnectResult(net::ERR_FAILED);
466 factory()->OnConnectionChanged(
467 network::mojom::ConnectionType::CONNECTION_WIFI);
468 WaitForConnections();
469
470 // Backoff should increase.
471 base::TimeTicks next_backoff = factory()->NextRetryAttempt();
472 EXPECT_GT(next_backoff, initial_backoff);
473 EXPECT_FALSE(factory()->IsEndpointReachable());
474 }
475
476 // Verify that we reconnect even if a canary succeeded then disconnected while
477 // a backoff was pending.
TEST_F(ConnectionFactoryImplTest,CanarySucceedsThenDisconnects)478 TEST_F(ConnectionFactoryImplTest, CanarySucceedsThenDisconnects) {
479 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
480 factory()->Connect();
481 WaitForConnections();
482 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
483 EXPECT_FALSE(initial_backoff.is_null());
484
485 factory()->SetConnectResult(net::OK);
486 factory()->OnConnectionChanged(
487 network::mojom::ConnectionType::CONNECTION_ETHERNET);
488 WaitForConnections();
489 EXPECT_TRUE(factory()->IsEndpointReachable());
490 EXPECT_TRUE(connected_server().is_valid());
491
492 factory()->SetConnectResult(net::OK);
493 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
494 EXPECT_FALSE(factory()->IsEndpointReachable());
495 EXPECT_FALSE(connected_server().is_valid());
496 WaitForConnections();
497 EXPECT_TRUE(factory()->IsEndpointReachable());
498 EXPECT_TRUE(connected_server().is_valid());
499 }
500
501 // Verify that if a canary connects, but hasn't finished the handshake, a
502 // pending backoff attempt doesn't interrupt the connection.
TEST_F(ConnectionFactoryImplTest,CanarySucceedsRetryDuringLogin)503 TEST_F(ConnectionFactoryImplTest, CanarySucceedsRetryDuringLogin) {
504 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
505 factory()->Connect();
506 WaitForConnections();
507 base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
508 EXPECT_FALSE(initial_backoff.is_null());
509
510 factory()->SetDelayLogin(true);
511 factory()->SetConnectResult(net::OK);
512 factory()->OnConnectionChanged(
513 network::mojom::ConnectionType::CONNECTION_WIFI);
514 WaitForConnections();
515 EXPECT_FALSE(factory()->IsEndpointReachable());
516
517 // Pump the loop, to ensure the pending backoff retry has no effect.
518 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
519 FROM_HERE, GetRunLoop()->QuitWhenIdleClosure(),
520 base::TimeDelta::FromMilliseconds(1));
521 WaitForConnections();
522 }
523
524 // Fail after successful connection via signal reset.
TEST_F(ConnectionFactoryImplTest,FailViaSignalReset)525 TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
526 factory()->SetConnectResult(net::OK);
527 factory()->Connect();
528 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
529
530 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
531 EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
532 EXPECT_FALSE(factory()->IsEndpointReachable());
533 }
534
TEST_F(ConnectionFactoryImplTest,IgnoreResetWhileConnecting)535 TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
536 factory()->SetConnectResult(net::OK);
537 factory()->Connect();
538 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
539
540 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
541 base::TimeTicks retry_time = factory()->NextRetryAttempt();
542 EXPECT_FALSE(retry_time.is_null());
543 EXPECT_FALSE(factory()->IsEndpointReachable());
544
545 const int kNumAttempts = 5;
546 for (int i = 0; i < kNumAttempts; ++i)
547 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
548 EXPECT_EQ(retry_time, factory()->NextRetryAttempt());
549 EXPECT_FALSE(factory()->IsEndpointReachable());
550 }
551
552 // Go into backoff due to connection failure. On successful connection, receive
553 // a signal reset. The original backoff should be restored and extended, rather
554 // than a new backoff starting from scratch.
TEST_F(ConnectionFactoryImplTest,SignalResetRestoresBackoff)555 TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
556 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
557 base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
558 factory()->Connect();
559 WaitForConnections();
560 base::TimeTicks retry_time = factory()->NextRetryAttempt();
561 EXPECT_FALSE(retry_time.is_null());
562
563 factory()->SetConnectResult(net::OK);
564 connect_time = factory()->tick_clock()->NowTicks();
565 WaitForConnections();
566 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
567
568 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
569 EXPECT_FALSE(factory()->IsEndpointReachable());
570 EXPECT_FALSE(connected_server().is_valid());
571 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
572 retry_time = factory()->NextRetryAttempt();
573 EXPECT_FALSE(retry_time.is_null());
574 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
575 CalculateBackoff(2));
576
577 factory()->SetConnectResult(net::OK);
578 connect_time = factory()->tick_clock()->NowTicks();
579 factory()->tick_clock()->Advance(
580 factory()->NextRetryAttempt() - connect_time);
581 WaitForConnections();
582 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
583 EXPECT_TRUE(factory()->IsEndpointReachable());
584 EXPECT_TRUE(connected_server().is_valid());
585
586 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
587 EXPECT_NE(retry_time, factory()->NextRetryAttempt());
588 retry_time = factory()->NextRetryAttempt();
589 EXPECT_FALSE(retry_time.is_null());
590 EXPECT_GE((retry_time - connect_time).InMilliseconds(),
591 CalculateBackoff(3));
592 EXPECT_FALSE(factory()->IsEndpointReachable());
593 EXPECT_FALSE(connected_server().is_valid());
594 }
595
596 // When the network is disconnected, close the socket and suppress further
597 // connection attempts until the network returns.
598 // Disabled while crbug.com/396687 is being investigated.
TEST_F(ConnectionFactoryImplTest,DISABLED_SuppressConnectWhenNoNetwork)599 TEST_F(ConnectionFactoryImplTest, DISABLED_SuppressConnectWhenNoNetwork) {
600 factory()->SetConnectResult(net::OK);
601 factory()->Connect();
602 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
603 EXPECT_TRUE(factory()->IsEndpointReachable());
604
605 // Advance clock so the login window reset isn't encountered.
606 factory()->tick_clock()->Advance(base::TimeDelta::FromSeconds(11));
607
608 // Will trigger reset, but will not attempt a new connection.
609 factory()->OnConnectionChanged(
610 network::mojom::ConnectionType::CONNECTION_NONE);
611 EXPECT_FALSE(factory()->IsEndpointReachable());
612 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
613
614 // When the network returns, attempt to connect.
615 factory()->SetConnectResult(net::OK);
616 factory()->OnConnectionChanged(network::mojom::ConnectionType::CONNECTION_4G);
617 WaitForConnections();
618
619 EXPECT_TRUE(factory()->IsEndpointReachable());
620 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
621 }
622
623 // Receiving a network change event before the initial connection should have
624 // no effect.
TEST_F(ConnectionFactoryImplTest,NetworkChangeBeforeFirstConnection)625 TEST_F(ConnectionFactoryImplTest, NetworkChangeBeforeFirstConnection) {
626 factory()->OnConnectionChanged(network::mojom::ConnectionType::CONNECTION_4G);
627 factory()->SetConnectResult(net::OK);
628 factory()->Connect();
629 EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
630 EXPECT_TRUE(factory()->IsEndpointReachable());
631 }
632
633 // Test that if the client attempts to reconnect while a connection is already
634 // open, we don't crash.
TEST_F(ConnectionFactoryImplTest,ConnectionResetRace)635 TEST_F(ConnectionFactoryImplTest, ConnectionResetRace) {
636 // Initial successful connection.
637 factory()->SetConnectResult(net::OK);
638 factory()->Connect();
639 WaitForConnections();
640 EXPECT_TRUE(factory()->IsEndpointReachable());
641
642 // Trigger a connection error under the hood.
643 factory()->SetSocketError();
644 EXPECT_FALSE(factory()->IsEndpointReachable());
645
646 // Now trigger force a re-connection.
647 factory()->SetConnectResult(net::OK);
648 factory()->Connect();
649 WaitForConnections();
650
651 // Re-connection should succeed.
652 EXPECT_TRUE(factory()->IsEndpointReachable());
653 }
654
TEST_F(ConnectionFactoryImplTest,MultipleFailuresWrapClientEvents)655 TEST_F(ConnectionFactoryImplTest, MultipleFailuresWrapClientEvents) {
656 const int kNumAttempts = 50;
657 factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
658 kNumAttempts);
659
660 factory()->Connect();
661 WaitForConnections();
662
663 // There should be one failed client event for each failed connection, but
664 // there is a maximum cap of kMaxClientEvents, which is 30. There should also
665 // be a single event which records the events which were discarded.
666 auto client_events = GetClientEvents();
667 ASSERT_EQ(31, client_events.size());
668
669 bool found_discarded_events = false;
670 for (const auto& client_event : client_events) {
671 if (client_event.type() == mcs_proto::ClientEvent::DISCARDED_EVENTS) {
672 // There should only be one event for discarded events.
673 EXPECT_FALSE(found_discarded_events);
674 found_discarded_events = true;
675 // There should be 50-30=20 discarded events.
676 EXPECT_EQ(20U, client_event.number_discarded_events());
677 } else {
678 EXPECT_EQ(mcs_proto::ClientEvent::FAILED_CONNECTION, client_event.type());
679 EXPECT_EQ(net::ERR_CONNECTION_FAILED, client_event.error_code());
680 }
681 }
682 EXPECT_TRUE(found_discarded_events);
683
684 factory()->SetConnectResult(net::OK);
685 WaitForConnections();
686 EXPECT_TRUE(factory()->IsEndpointReachable());
687 EXPECT_TRUE(connected_server().is_valid());
688
689 // Old client events should have been reset after the successful connection.
690 client_events = GetClientEvents();
691 ASSERT_EQ(0, client_events.size());
692
693 // Test that EndConnectionAttempt doesn't write empty events to the tracker.
694 // There should be 2 events: 1) the successful connection which was previously
695 // established. 2) the unsuccessful connection triggered as a result of the
696 // SOCKET_FAILURE signal. The NETWORK_CHANGE signal should not cause an
697 // additional event since there is no in progress event.
698 factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
699 factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
700 factory()->SignalConnectionReset(ConnectionFactory::NETWORK_CHANGE);
701 WaitForConnections();
702
703 client_events = GetClientEvents();
704 ASSERT_EQ(2, client_events.size());
705 }
706
707 } // namespace gcm
708