Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Unified Diff: google_apis/gcm/engine/connection_factory_impl_unittest.cc

Issue 54743007: [GCM] Add connection factory for creating MCS connections (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix compile Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « google_apis/gcm/engine/connection_factory_impl.cc ('k') | google_apis/gcm/engine/connection_handler.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
new file mode 100644
index 0000000000000000000000000000000000000000..40adcf2783285f3a0f09d90e73aa972a2f96a87a
--- /dev/null
+++ b/google_apis/gcm/engine/connection_factory_impl_unittest.cc
@@ -0,0 +1,295 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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/time/time.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 int kBackoffDelayMs = 1;
+const int kBackoffMultiplier = 2;
+
+// A backoff policy with small enough delays that tests aren't burdened.
+const net::BackoffEntry::Policy kTestBackoffPolicy = {
+ // Number of initial errors (in sequence) to ignore before applying
+ // exponential back-off rules.
+ 0,
+
+ // Initial delay for exponential back-off in ms.
+ kBackoffDelayMs,
+
+ // Factor by which the waiting time will be multiplied.
+ kBackoffMultiplier,
+
+ // Fuzzing percentage. ex: 10% will spread requests randomly
+ // between 90%-100% of the calculated time.
+ 0,
+
+ // Maximum amount of time we are willing to delay our request in ms.
+ 10,
+
+ // Time to keep an entry from being discarded even when it
+ // has no significant state, -1 to never discard.
+ -1,
+
+ // Don't use initial delay unless the last request was an error.
+ false,
+};
+
+// Helper for calculating total expected exponential backoff delay given an
+// arbitrary number of failed attempts. See BackoffEntry::CalculateReleaseTime.
+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;
+}
+
+// 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();
+}
+
+// A connection factory that stubs out network requests and overrides the
+// backoff policy.
+class TestConnectionFactoryImpl : public ConnectionFactoryImpl {
+ public:
+ TestConnectionFactoryImpl(const base::Closure& finished_callback);
+ virtual ~TestConnectionFactoryImpl();
+
+ // Overridden stubs.
+ virtual void ConnectImpl() OVERRIDE;
+ virtual void InitHandler() OVERRIDE;
+ virtual scoped_ptr<net::BackoffEntry> CreateBackoffEntry(
+ const net::BackoffEntry::Policy* const policy) OVERRIDE;
+
+ // Helpers for verifying connection attempts are made. Connection results
+ // must be consumed.
+ void SetConnectResult(int connect_result);
+ void SetMultipleConnectResults(int connect_result, int num_expected_attempts);
+
+ private:
+ // The result to return on the next connect attempt.
+ int connect_result_;
+ // The number of expected connection attempts;
+ int num_expected_attempts_;
+ // Whether all expected connection attempts have been fulfilled since an
+ // expectation was last set.
+ bool connections_fulfilled_;
+ // Callback to invoke when all connection attempts have been made.
+ base::Closure finished_callback_;
+};
+
+TestConnectionFactoryImpl::TestConnectionFactoryImpl(
+ const base::Closure& finished_callback)
+ : ConnectionFactoryImpl(GURL(kMCSEndpoint), NULL, NULL),
+ connect_result_(net::ERR_UNEXPECTED),
+ num_expected_attempts_(0),
+ connections_fulfilled_(true),
+ finished_callback_(finished_callback) {
+}
+
+TestConnectionFactoryImpl::~TestConnectionFactoryImpl() {
+ EXPECT_EQ(0, num_expected_attempts_);
+}
+
+void TestConnectionFactoryImpl::ConnectImpl() {
+ ASSERT_GT(num_expected_attempts_, 0);
+
+ OnConnectDone(connect_result_);
+ --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);
+}
+
+scoped_ptr<net::BackoffEntry> TestConnectionFactoryImpl::CreateBackoffEntry(
+ const net::BackoffEntry::Policy* const policy) {
+ return scoped_ptr<net::BackoffEntry>(
+ new net::BackoffEntry(&kTestBackoffPolicy));
+}
+
+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;
+}
+
+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;
+}
+
+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()) {}
+ConnectionFactoryImplTest::~ConnectionFactoryImplTest() {}
+
+void ConnectionFactoryImplTest::WaitForConnections() {
+ run_loop_->Run();
+ run_loop_.reset(new base::RunLoop());
+}
+
+void ConnectionFactoryImplTest::ConnectionsComplete() {
+ if (!run_loop_)
+ return;
+ run_loop_->Quit();
+}
+
+// Verify building a connection handler works.
+TEST_F(ConnectionFactoryImplTest, BuildConnectionHandler) {
+ EXPECT_FALSE(factory()->IsEndpointReachable());
+ ConnectionHandler* handler = factory()->BuildConnectionHandler(
+ base::Bind(&ReadContinuation),
+ base::Bind(&WriteContinuation));
+ ASSERT_TRUE(handler);
+ EXPECT_FALSE(factory()->IsEndpointReachable());
+}
+
+// An initial successful connection should not result in backoff.
+TEST_F(ConnectionFactoryImplTest, ConnectSuccess) {
+ factory()->BuildConnectionHandler(
+ ConnectionHandler::ProtoReceivedCallback(),
+ ConnectionHandler::ProtoSentCallback());
+ factory()->SetConnectResult(net::OK);
+ factory()->Connect(mcs_proto::LoginRequest());
+ EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
+}
+
+// A connection failure should result in backoff.
+TEST_F(ConnectionFactoryImplTest, ConnectFail) {
+ factory()->BuildConnectionHandler(
+ ConnectionHandler::ProtoReceivedCallback(),
+ ConnectionHandler::ProtoSentCallback());
+ factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
+ factory()->Connect(mcs_proto::LoginRequest());
+ EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
+}
+
+// A connection success after a failure should reset backoff.
+TEST_F(ConnectionFactoryImplTest, FailThenSucceed) {
+ factory()->BuildConnectionHandler(
+ ConnectionHandler::ProtoReceivedCallback(),
+ ConnectionHandler::ProtoSentCallback());
+ factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
+ base::TimeTicks connect_time = base::TimeTicks::Now();
+ factory()->Connect(mcs_proto::LoginRequest());
+ WaitForConnections();
+ 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());
+}
+
+// Multiple connection failures should retry with an exponentially increasing
+// backoff, then reset on success.
+TEST_F(ConnectionFactoryImplTest, MultipleFailuresThenSucceed) {
+ factory()->BuildConnectionHandler(
+ ConnectionHandler::ProtoReceivedCallback(),
+ ConnectionHandler::ProtoSentCallback());
+
+ const int kNumAttempts = 5;
+ factory()->SetMultipleConnectResults(net::ERR_CONNECTION_FAILED,
+ kNumAttempts);
+
+ base::TimeTicks connect_time = base::TimeTicks::Now();
+ factory()->Connect(mcs_proto::LoginRequest());
+ WaitForConnections();
+ 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());
+}
+
+// IP events should reset backoff.
+TEST_F(ConnectionFactoryImplTest, FailThenIPEvent) {
+ factory()->BuildConnectionHandler(
+ ConnectionHandler::ProtoReceivedCallback(),
+ ConnectionHandler::ProtoSentCallback());
+ factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
+ factory()->Connect(mcs_proto::LoginRequest());
+ WaitForConnections();
+ EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
+
+ factory()->OnIPAddressChanged();
+ EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
+}
+
+// Connection type events should reset backoff.
+TEST_F(ConnectionFactoryImplTest, FailThenConnectionTypeEvent) {
+ factory()->BuildConnectionHandler(
+ ConnectionHandler::ProtoReceivedCallback(),
+ ConnectionHandler::ProtoSentCallback());
+ factory()->SetConnectResult(net::ERR_CONNECTION_FAILED);
+ factory()->Connect(mcs_proto::LoginRequest());
+ WaitForConnections();
+ EXPECT_FALSE(factory()->NextRetryAttempt().is_null());
+
+ factory()->OnConnectionTypeChanged(
+ net::NetworkChangeNotifier::CONNECTION_WIFI);
+ EXPECT_TRUE(factory()->NextRetryAttempt().is_null());
+}
+
+} // namespace
+} // namespace gcm
« no previous file with comments | « google_apis/gcm/engine/connection_factory_impl.cc ('k') | google_apis/gcm/engine/connection_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698