This source file includes following definitions.
- BuildEndpoints
- CalculateBackoff
- ReadContinuation
- WriteContinuation
- tick_clock_
- ImplGetTimeNow
- tick_clock
- fake_handler_
- ConnectImpl
- InitHandler
- CreateBackoffEntry
- CreateConnectionHandler
- NowTicks
- SetConnectResult
- SetMultipleConnectResults
- factory
- run_loop_
- WaitForConnections
- ConnectionsComplete
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "google_apis/gcm/engine/connection_factory_impl.h"
#include <cmath>
#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"
class Policy;
namespace gcm {
namespace {
const char kMCSEndpoint[] = "http://my.server";
const char kMCSEndpoint2[] = "http://my.alt.server";
const int kBackoffDelayMs = 1;
const int kBackoffMultiplier = 2;
const net::BackoffEntry::Policy kTestBackoffPolicy = {
0,
kBackoffDelayMs,
kBackoffMultiplier,
0,
10,
-1,
false,
};
std::vector<GURL> BuildEndpoints() {
std::vector<GURL> endpoints;
endpoints.push_back(GURL(kMCSEndpoint));
endpoints.push_back(GURL(kMCSEndpoint2));
return endpoints;
}
double CalculateBackoff(int num_attempts) {
double delay = kBackoffDelayMs;
for (int i = 1; i < num_attempts; ++i) {
delay += kBackoffDelayMs * pow(static_cast<double>(kBackoffMultiplier),
i - 1);
}
DVLOG(1) << "Expected backoff " << delay << " milliseconds.";
return delay;
}
void ReadContinuation(
scoped_ptr<google::protobuf::MessageLite> message) {
}
void WriteContinuation() {
}
class TestBackoffEntry : public net::BackoffEntry {
public:
explicit TestBackoffEntry(base::SimpleTestTickClock* tick_clock);
virtual ~TestBackoffEntry();
virtual base::TimeTicks ImplGetTimeNow() const OVERRIDE;
private:
base::SimpleTestTickClock* tick_clock_;
};
TestBackoffEntry::TestBackoffEntry(base::SimpleTestTickClock* tick_clock)
: BackoffEntry(&kTestBackoffPolicy),
tick_clock_(tick_clock) {
}
TestBackoffEntry::~TestBackoffEntry() {}
base::TimeTicks TestBackoffEntry::ImplGetTimeNow() const {
return tick_clock_->NowTicks();
}
class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
public:
TestConnectionFactoryImpl(const base::Closure& finished_callback);
virtual ~TestConnectionFactoryImpl();
void InitializeFactory();
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;
void SetConnectResult(int connect_result);
void SetMultipleConnectResults(int connect_result, int num_expected_attempts);
base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
private:
base::SimpleTestTickClock tick_clock_;
int connect_result_;
int num_expected_attempts_;
bool connections_fulfilled_;
base::Closure finished_callback_;
FakeConnectionHandler* fake_handler_;
};
TestConnectionFactoryImpl::TestConnectionFactoryImpl(
const base::Closure& finished_callback)
: ConnectionFactoryImpl(BuildEndpoints(),
net::BackoffEntry::Policy(),
NULL,
NULL),
connect_result_(net::ERR_UNEXPECTED),
num_expected_attempts_(0),
connections_fulfilled_(true),
finished_callback_(finished_callback),
fake_handler_(NULL) {
tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1));
}
TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
EXPECT_EQ(0, num_expected_attempts_);
}
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()) {
base::TimeDelta time_till_retry =
NextRetryAttempt() - tick_clock_.NowTicks();
tick_clock_.Advance(time_till_retry);
}
--num_expected_attempts_;
if (num_expected_attempts_ == 0) {
connect_result_ = net::ERR_UNEXPECTED;
connections_fulfilled_ = true;
finished_callback_.Run();
}
}
void TestConnectionFactoryImpl::InitHandler() {
EXPECT_NE(connect_result_, net::ERR_UNEXPECTED);
ConnectionHandlerCallback(net::OK);
}
scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
const net::BackoffEntry::Policy* const policy) {
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();
}
void TestConnectionFactoryImpl::SetConnectResult(int connect_result) {
DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
ASSERT_EQ(0, num_expected_attempts_);
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(
int connect_result,
int num_expected_attempts) {
DCHECK_NE(connect_result, net::ERR_UNEXPECTED);
DCHECK_GT(num_expected_attempts, 0);
ASSERT_EQ(0, num_expected_attempts_);
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 {
public:
ConnectionFactoryImplTest();
virtual ~ConnectionFactoryImplTest();
TestConnectionFactoryImpl* factory() { return &factory_; }
void WaitForConnections();
private:
void ConnectionsComplete();
TestConnectionFactoryImpl factory_;
base::MessageLoop message_loop_;
scoped_ptr<base::RunLoop> run_loop_;
};
ConnectionFactoryImplTest::ConnectionFactoryImplTest()
: factory_(base::Bind(&ConnectionFactoryImplTest::ConnectionsComplete,
base::Unretained(this))),
run_loop_(new base::RunLoop()) {
factory()->Initialize(
ConnectionFactory::BuildLoginRequestCallback(),
ConnectionHandler::ProtoReceivedCallback(),
ConnectionHandler::ProtoSentCallback());
}
ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
void ConnectionFactoryImplTest::WaitForConnections() {
run_loop_->Run();
run_loop_.reset(new base::RunLoop());
}
void ConnectionFactoryImplTest::ConnectionsComplete() {
if (!run_loop_)
return;
run_loop_->Quit();
}
TEST_F(ConnectionFactoryImplTest, Initialize) {
ConnectionHandler* handler = factory()->GetConnectionHandler();
ASSERT_TRUE(handler);
EXPECT_FALSE(factory()->IsEndpointReachable());
}
TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
factory()->SetConnectResult(net::OK);
factory()->Connect();
EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[0]);
EXPECT_TRUE(factory()->IsEndpointReachable());
}
TEST_F(ConnectionFactoryImplTest, ConnectFail) {
factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
factory()->Connect();
EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
EXPECT_EQ(factory()->GetCurrentEndpoint(), BuildEndpoints()[1]);
EXPECT_FALSE(factory()->IsEndpointReachable());
}
TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
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());
}
TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
const int kNumAttempts = 5;
factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
kNumAttempts);
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(kNumAttempts));
factory()->SetConnectResult(net::OK);
WaitForConnections();
EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
EXPECT_TRUE(factory()->IsEndpointReachable());
}
TEST_F(ConnectionFactoryImplTest, FailThenIPEvent) {
factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
factory()->Connect();
WaitForConnections();
base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
EXPECT_FALSE(initial_backoff.is_null());
factory()->SetConnectResult(net::ERR_FAILED);
factory()->OnIPAddressChanged();
WaitForConnections();
base::TimeTicks next_backoff = factory()->NextRetryAttempt();
EXPECT_GT(next_backoff, initial_backoff);
EXPECT_FALSE(factory()->IsEndpointReachable());
}
TEST_F(ConnectionFactoryImplTest, FailThenConnectionTypeEvent) {
factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
factory()->Connect();
WaitForConnections();
base::TimeTicks initial_backoff = factory()->NextRetryAttempt();
EXPECT_FALSE(initial_backoff.is_null());
factory()->SetConnectResult(net::ERR_FAILED);
factory()->OnConnectionTypeChanged(
net::NetworkChangeNotifier::CONNECTION_WIFI);
WaitForConnections();
base::TimeTicks next_backoff = factory()->NextRetryAttempt();
EXPECT_GT(next_backoff, initial_backoff);
EXPECT_FALSE(factory()->IsEndpointReachable());
}
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());
}
TEST_F(ConnectionFactoryImplTest, FailViaSignalReset) {
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()->IsEndpointReachable());
}
TEST_F(ConnectionFactoryImplTest, IgnoreResetWhileConnecting) {
factory()->SetConnectResult(net::OK);
factory()->Connect();
EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
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());
}
TEST_F(ConnectionFactoryImplTest, SignalResetRestoresBackoff) {
factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
base::TimeTicks connect_time = factory()->tick_clock()->NowTicks();
factory()->Connect();
WaitForConnections();
base::TimeTicks retry_time = factory()->NextRetryAttempt();
EXPECT_FALSE(retry_time.is_null());
factory()->SetConnectResult(net::OK);
connect_time = factory()->tick_clock()->NowTicks();
WaitForConnections();
EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
factory()->SignalConnectionReset(ConnectionFactory::SOCKET_FAILURE);
EXPECT_FALSE(factory()->IsEndpointReachable());
EXPECT_NE(retry_time, factory()->NextRetryAttempt());
retry_time = factory()->NextRetryAttempt();
EXPECT_FALSE(retry_time.is_null());
EXPECT_GE((retry_time - connect_time).InMilliseconds(),
CalculateBackoff(2));
factory()->SetConnectResult(net::OK);
connect_time = factory()->tick_clock()->NowTicks();
factory()->tick_clock()->Advance(
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());
retry_time = factory()->NextRetryAttempt();
EXPECT_FALSE(retry_time.is_null());
EXPECT_GE((retry_time - connect_time).InMilliseconds(),
CalculateBackoff(3));
EXPECT_FALSE(factory()->IsEndpointReachable());
}
}
}