| Index: google_apis/gcm/engine/connection_factory_impl_unittest.cc
|
| diff --git a/google_apis/gcm/engine/connection_factory_impl_unittest.cc b/google_apis/gcm/engine/connection_factory_impl_unittest.cc
|
| index eebe14a9b0ad444e44f67975ec13a57293606f84..4983ea9d54b3dfa6ca85f1277eb73c37309a7a93 100644
|
| --- a/google_apis/gcm/engine/connection_factory_impl_unittest.cc
|
| +++ b/google_apis/gcm/engine/connection_factory_impl_unittest.cc
|
| @@ -9,6 +9,8 @@
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/run_loop.h"
|
| #include "base/test/simple_test_tick_clock.h"
|
| +#include "google_apis/gcm/base/mcs_util.h"
|
| +#include "google_apis/gcm/engine/fake_connection_handler.h"
|
| #include "net/base/backoff_entry.h"
|
| #include "net/http/http_network_session.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| @@ -70,15 +72,11 @@ double CalculateBackoff(int num_attempts) {
|
| return delay;
|
| }
|
|
|
| -// Helper methods that should never actually be called due to real connections
|
| -// being stubbed out.
|
| void ReadContinuation(
|
| scoped_ptr<google::protobuf::MessageLite> message) {
|
| - ADD_FAILURE();
|
| }
|
|
|
| void WriteContinuation() {
|
| - ADD_FAILURE();
|
| }
|
|
|
| class TestBackoffEntry : public net::BackoffEntry {
|
| @@ -110,11 +108,19 @@ class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
|
| TestConnectionFactoryImpl(const base::Closure& finished_callback);
|
| virtual ~TestConnectionFactoryImpl();
|
|
|
| + void InitializeFactory();
|
| +
|
| // Overridden stubs.
|
| virtual void ConnectImpl() OVERRIDE;
|
| virtual void InitHandler() OVERRIDE;
|
| virtual scoped_ptr<net::BackoffEntry> CreateBackoffEntry(
|
| const net::BackoffEntry::Policy* const policy) OVERRIDE;
|
| + virtual scoped_ptr<ConnectionHandler> CreateConnectionHandler(
|
| + base::TimeDelta read_timeout,
|
| + const ConnectionHandler::ProtoReceivedCallback& read_callback,
|
| + const ConnectionHandler::ProtoSentCallback& write_callback,
|
| + const ConnectionHandler::ConnectionChangedCallback& connection_callback)
|
| + OVERRIDE;
|
| virtual base::TimeTicks NowTicks() OVERRIDE;
|
|
|
| // Helpers for verifying connection attempts are made. Connection results
|
| @@ -136,6 +142,8 @@ class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
|
| bool connections_fulfilled_;
|
| // Callback to invoke when all connection attempts have been made.
|
| base::Closure finished_callback_;
|
| + // The current fake connection handler..
|
| + FakeConnectionHandler* fake_handler_;
|
| };
|
|
|
| TestConnectionFactoryImpl::TestConnectionFactoryImpl(
|
| @@ -147,7 +155,8 @@ TestConnectionFactoryImpl::TestConnectionFactoryImpl(
|
| connect_result_(net::ERR_UNEXPECTED),
|
| num_expected_attempts_(0),
|
| connections_fulfilled_(true),
|
| - finished_callback_(finished_callback) {
|
| + finished_callback_(finished_callback),
|
| + fake_handler_(NULL) {
|
| // Set a non-null time.
|
| tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
|
| }
|
| @@ -158,7 +167,8 @@ TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
|
|
|
| void TestConnectionFactoryImpl::ConnectImpl() {
|
| ASSERT_GT(num_expected_attempts_, 0);
|
| -
|
| + scoped_ptr<mcs_proto::LoginRequest> request(BuildLoginRequest(0, 0, ""));
|
| + GetConnectionHandler()->Init(*request, NULL);
|
| OnConnectDone(connect_result_);
|
| if (!NextRetryAttempt().is_null()) {
|
| // Advance the time to the next retry time.
|
| @@ -184,6 +194,18 @@ scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
|
| return scoped_ptr<net::BackoffEntry>(new TestBackoffEntry(&tick_clock_));
|
| }
|
|
|
| +scoped_ptr<ConnectionHandler>
|
| +TestConnectionFactoryImpl::CreateConnectionHandler(
|
| + base::TimeDelta read_timeout,
|
| + const ConnectionHandler::ProtoReceivedCallback& read_callback,
|
| + const ConnectionHandler::ProtoSentCallback& write_callback,
|
| + const ConnectionHandler::ConnectionChangedCallback& connection_callback) {
|
| + fake_handler_ = new FakeConnectionHandler(
|
| + base::Bind(&ReadContinuation),
|
| + base::Bind(&WriteContinuation));
|
| + return make_scoped_ptr<ConnectionHandler>(fake_handler_);
|
| +}
|
| +
|
| base::TimeTicks TestConnectionFactoryImpl::NowTicks() {
|
| return tick_clock_.NowTicks();
|
| }
|
| @@ -194,6 +216,10 @@ void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
|
| connections_fulfilled_ = false;
|
| connect_result_ = connect_result;
|
| num_expected_attempts_ = 1;
|
| + fake_handler_->ExpectOutgoingMessage(
|
| + MCSMessage(kLoginRequestTag,
|
| + BuildLoginRequest(0, 0, "").PassAs<
|
| + const google::protobuf::MessageLite>()));
|
| }
|
|
|
| void TestConnectionFactoryImpl::SetMultipleConnectResults(
|
| @@ -205,6 +231,12 @@ void TestConnectionFactoryImpl::SetMultipleConnectResults(
|
| connections_fulfilled_ = false;
|
| connect_result_ = connect_result;
|
| num_expected_attempts_ = num_expected_attempts;
|
| + for (int i = 0 ; i < num_expected_attempts; ++i) {
|
| + fake_handler_->ExpectOutgoingMessage(
|
| + MCSMessage(kLoginRequestTag,
|
| + BuildLoginRequest(0, 0, "").PassAs<
|
| + const google::protobuf::MessageLite>()));
|
| + }
|
| }
|
|
|
| class ConnectionFactoryImplTest : public testing::Test {
|
| @@ -227,7 +259,12 @@ class ConnectionFactoryImplTest : public testing::Test {
|
| ConnectionFactoryImplTest::ConnectionFactoryImplTest()
|
| : factory_(base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
|
| base::Unretained(this))),
|
| - run_loop_(new base::RunLoop()) {}
|
| + run_loop_(new base::RunLoop()) {
|
| + factory()->Initialize(
|
| + ConnectionFactory::BuildLoginRequestCallback(),
|
| + ConnectionHandler::ProtoReceivedCallback(),
|
| + ConnectionHandler::ProtoSentCallback());
|
| +}
|
| ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
|
|
|
| void ConnectionFactoryImplTest::WaitForConnections() {
|
| @@ -243,11 +280,6 @@ void ConnectionFactoryImplTest::ConnectionsComplete() {
|
|
|
| // Verify building a connection handler works.
|
| TEST_F(ConnectionFactoryImplTest, Initialize) {
|
| - EXPECT_FALSE(factory()->IsEndpointReachable());
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - base::Bind(&ReadContinuation),
|
| - base::Bind(&WriteContinuation));
|
| ConnectionHandler* handler = factory()->GetConnectionHandler();
|
| ASSERT_TRUE(handler);
|
| EXPECT_FALSE(factory()->IsEndpointReachable());
|
| @@ -255,54 +287,42 @@ TEST_F(ConnectionFactoryImplTest, Initialize) {
|
|
|
| // An initial successful connection should not result in backoff.
|
| TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - ConnectionHandler::ProtoReceivedCallback(),
|
| - ConnectionHandler::ProtoSentCallback());
|
| factory()->SetConnectResult(net::OK);
|
| factory()->Connect();
|
| EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
|
| EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[0]);
|
| + EXPECT_TRUE(factory()->IsEndpointReachable());
|
| }
|
|
|
| // A connection failure should result in backoff, and attempting the fallback
|
| // endpoint next.
|
| TEST_F(ConnectionFactoryImplTest, ConnectFail) {
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - ConnectionHandler::ProtoReceivedCallback(),
|
| - ConnectionHandler::ProtoSentCallback());
|
| factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
|
| factory()->Connect();
|
| EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
|
| EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[1]);
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| }
|
|
|
| // A connection success after a failure should reset backoff.
|
| TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - ConnectionHandler::ProtoReceivedCallback(),
|
| - ConnectionHandler::ProtoSentCallback());
|
| factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
|
| base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
|
| factory()->Connect();
|
| WaitForConnections();
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| base::TimeTicks retry_time = factory()->NextRetryAttempt();
|
| EXPECT_FALSE(retry_time.is_null());
|
| EXPECT_GE((retry_time - connect_time).InMilliseconds(), CalculateBackoff(1));
|
| factory()->SetConnectResult(net::OK);
|
| WaitForConnections();
|
| EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
|
| + EXPECT_TRUE(factory()->IsEndpointReachable());
|
| }
|
|
|
| // Multiple connection failures should retry with an exponentially increasing
|
| // backoff, then reset on success.
|
| TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - ConnectionHandler::ProtoReceivedCallback(),
|
| - ConnectionHandler::ProtoSentCallback());
|
|
|
| const int kNumAttempts = 5;
|
| factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
|
| @@ -311,6 +331,7 @@ TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
|
| base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
|
| factory()->Connect();
|
| WaitForConnections();
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| base::TimeTicks retry_time = factory()->NextRetryAttempt();
|
| EXPECT_FALSE(retry_time.is_null());
|
| EXPECT_GE((retry_time - connect_time).InMilliseconds(),
|
| @@ -319,59 +340,80 @@ TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
|
| factory()->SetConnectResult(net::OK);
|
| WaitForConnections();
|
| EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
|
| + EXPECT_TRUE(factory()->IsEndpointReachable());
|
| }
|
|
|
| -// IP events should reset backoff.
|
| +// IP events should trigger canary connections.
|
| TEST_F(ConnectionFactoryImplTest, FailThenIPEvent) {
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - ConnectionHandler::ProtoReceivedCallback(),
|
| - ConnectionHandler::ProtoSentCallback());
|
| factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
|
| factory()->Connect();
|
| WaitForConnections();
|
| - EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
|
| + base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
|
| + EXPECT_FALSE(initial_backoff.is_null());
|
|
|
| + factory()->SetConnectResult(net::ERR_FAILED);
|
| factory()->OnIPAddressChanged();
|
| - EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
|
| + WaitForConnections();
|
| +
|
| + // Backoff should increase.
|
| + base::TimeTicks next_backoff = factory()->NextRetryAttempt();
|
| + EXPECT_GT(next_backoff, initial_backoff);
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| }
|
|
|
| -// Connection type events should reset backoff.
|
| +// Connection type events should trigger canary connections.
|
| TEST_F(ConnectionFactoryImplTest, FailThenConnectionTypeEvent) {
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - ConnectionHandler::ProtoReceivedCallback(),
|
| - ConnectionHandler::ProtoSentCallback());
|
| factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
|
| factory()->Connect();
|
| WaitForConnections();
|
| - EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
|
| + base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
|
| + EXPECT_FALSE(initial_backoff.is_null());
|
|
|
| + factory()->SetConnectResult(net::ERR_FAILED);
|
| factory()->OnConnectionTypeChanged(
|
| net::NetworkChangeNotifier::CONNECTION_WIFI);
|
| - EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
|
| + WaitForConnections();
|
| +
|
| + // Backoff should increase.
|
| + base::TimeTicks next_backoff = factory()->NextRetryAttempt();
|
| + EXPECT_GT(next_backoff, initial_backoff);
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| +}
|
| +
|
| +// Verify that we reconnect even if a canary succeeded then disconnected while
|
| +// a backoff was pending.
|
| +TEST_F(ConnectionFactoryImplTest, CanarySucceedsThenDisconnects) {
|
| + factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
|
| + factory()->Connect();
|
| + WaitForConnections();
|
| + base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
|
| + EXPECT_FALSE(initial_backoff.is_null());
|
| +
|
| + factory()->SetConnectResult(net::OK);
|
| + factory()->OnConnectionTypeChanged(
|
| + net::NetworkChangeNotifier::CONNECTION_WIFI);
|
| + WaitForConnections();
|
| + EXPECT_TRUE(factory()->IsEndpointReachable());
|
| +
|
| + factory()->SetConnectResult(net::OK);
|
| + factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| + WaitForConnections();
|
| + EXPECT_TRUE(factory()->IsEndpointReachable());
|
| }
|
|
|
| // Fail after successful connection via signal reset.
|
| TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - ConnectionHandler::ProtoReceivedCallback(),
|
| - ConnectionHandler::ProtoSentCallback());
|
| factory()->SetConnectResult(net::OK);
|
| factory()->Connect();
|
| EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
|
|
|
| factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
|
| EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
|
| - EXPECT_FALSE(factory()->GetConnectionHandler()->CanSendMessage());
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| }
|
|
|
| TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - ConnectionHandler::ProtoReceivedCallback(),
|
| - ConnectionHandler::ProtoSentCallback());
|
| factory()->SetConnectResult(net::OK);
|
| factory()->Connect();
|
| EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
|
| @@ -379,21 +421,19 @@ TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
|
| factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
|
| base::TimeTicks retry_time = factory()->NextRetryAttempt();
|
| EXPECT_FALSE(retry_time.is_null());
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
|
|
| const int kNumAttempts = 5;
|
| for (int i = 0; i < kNumAttempts; ++i)
|
| factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
|
| EXPECT_EQ(retry_time, factory()->NextRetryAttempt());
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| }
|
|
|
| // Go into backoff due to connection failure. On successful connection, receive
|
| // a signal reset. The original backoff should be restored and extended, rather
|
| // than a new backoff starting from scratch.
|
| TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
|
| - factory()->Initialize(
|
| - ConnectionFactory::BuildLoginRequestCallback(),
|
| - ConnectionHandler::ProtoReceivedCallback(),
|
| - ConnectionHandler::ProtoSentCallback());
|
| factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
|
| base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
|
| factory()->Connect();
|
| @@ -407,7 +447,7 @@ TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
|
| EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
|
|
|
| factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
|
| - EXPECT_FALSE(factory()->GetConnectionHandler()->CanSendMessage());
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| EXPECT_NE(retry_time, factory()->NextRetryAttempt());
|
| retry_time = factory()->NextRetryAttempt();
|
| EXPECT_FALSE(retry_time.is_null());
|
| @@ -420,6 +460,7 @@ TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
|
| factory()->NextRetryAttempt() - connect_time);
|
| WaitForConnections();
|
| EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
|
| + EXPECT_TRUE(factory()->IsEndpointReachable());
|
|
|
| factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
|
| EXPECT_NE(retry_time, factory()->NextRetryAttempt());
|
| @@ -427,6 +468,7 @@ TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
|
| EXPECT_FALSE(retry_time.is_null());
|
| EXPECT_GE((retry_time - connect_time).InMilliseconds(),
|
| CalculateBackoff(3));
|
| + EXPECT_FALSE(factory()->IsEndpointReachable());
|
| }
|
|
|
| } // namespace
|
|
|