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

Unified Diff: sync/notifier/gcm_network_channel_unittest.cc

Issue 308413002: Revert of Move some sync/notifier to components/invalidation (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months 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 | « sync/notifier/gcm_network_channel_delegate.h ('k') | sync/notifier/invalidation_handler.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sync/notifier/gcm_network_channel_unittest.cc
diff --git a/sync/notifier/gcm_network_channel_unittest.cc b/sync/notifier/gcm_network_channel_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2564d0b9d2fd63230df0059d2580f0e3880b6e9a
--- /dev/null
+++ b/sync/notifier/gcm_network_channel_unittest.cc
@@ -0,0 +1,494 @@
+// Copyright 2014 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 "base/run_loop.h"
+#include "base/strings/string_util.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_test_util.h"
+#include "sync/notifier/gcm_network_channel.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+class TestGCMNetworkChannelDelegate : public GCMNetworkChannelDelegate {
+ public:
+ TestGCMNetworkChannelDelegate()
+ : register_call_count_(0) {}
+
+ virtual void Initialize() OVERRIDE {}
+
+ virtual void RequestToken(RequestTokenCallback callback) OVERRIDE {
+ request_token_callback = callback;
+ }
+
+ virtual void InvalidateToken(const std::string& token) OVERRIDE {
+ invalidated_token = token;
+ }
+
+ virtual void Register(RegisterCallback callback) OVERRIDE {
+ ++register_call_count_;
+ register_callback = callback;
+ }
+
+ virtual void SetMessageReceiver(MessageCallback callback) OVERRIDE {
+ message_callback = callback;
+ }
+
+ RequestTokenCallback request_token_callback;
+ std::string invalidated_token;
+ RegisterCallback register_callback;
+ int register_call_count_;
+ MessageCallback message_callback;
+};
+
+// Backoff policy for test. Run first 5 retries without delay.
+const net::BackoffEntry::Policy kTestBackoffPolicy = {
+ // Number of initial errors (in sequence) to ignore before applying
+ // exponential back-off rules.
+ 5,
+
+ // Initial delay for exponential back-off in ms.
+ 2000, // 2 seconds.
+
+ // Factor by which the waiting time will be multiplied.
+ 2,
+
+ // Fuzzing percentage. ex: 10% will spread requests randomly
+ // between 90%-100% of the calculated time.
+ 0.2, // 20%.
+
+ // Maximum amount of time we are willing to delay our request in ms.
+ 1000 * 3600 * 4, // 4 hours.
+
+ // 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,
+};
+
+class TestGCMNetworkChannel : public GCMNetworkChannel {
+ public:
+ TestGCMNetworkChannel(
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ scoped_ptr<GCMNetworkChannelDelegate> delegate)
+ : GCMNetworkChannel(request_context_getter, delegate.Pass()) {
+ ResetRegisterBackoffEntryForTest(&kTestBackoffPolicy);
+ }
+
+ protected:
+ // On Android GCMNetworkChannel::BuildUrl hits NOTREACHED(). I still want
+ // tests to run.
+ virtual GURL BuildUrl(const std::string& registration_id) OVERRIDE {
+ return GURL("http://test.url.com");
+ }
+};
+
+class GCMNetworkChannelTest;
+
+// Test needs to capture setting echo-token header on http request.
+// This class is going to do that.
+class TestNetworkChannelURLFetcher : public net::FakeURLFetcher {
+ public:
+ TestNetworkChannelURLFetcher(GCMNetworkChannelTest* test,
+ const GURL& url,
+ net::URLFetcherDelegate* delegate,
+ const std::string& response_data,
+ net::HttpStatusCode response_code,
+ net::URLRequestStatus::Status status)
+ : net::FakeURLFetcher(url,
+ delegate,
+ response_data,
+ response_code,
+ status),
+ test_(test) {}
+
+ virtual void AddExtraRequestHeader(const std::string& header_line) OVERRIDE;
+
+ private:
+ GCMNetworkChannelTest* test_;
+};
+
+class GCMNetworkChannelTest
+ : public ::testing::Test,
+ public SyncNetworkChannel::Observer {
+ public:
+ GCMNetworkChannelTest()
+ : delegate_(NULL),
+ url_fetchers_created_count_(0),
+ last_invalidator_state_(TRANSIENT_INVALIDATION_ERROR) {}
+
+ virtual ~GCMNetworkChannelTest() {
+ }
+
+ virtual void SetUp() {
+ request_context_getter_ = new net::TestURLRequestContextGetter(
+ base::MessageLoopProxy::current());
+ // Ownership of delegate goes to GCNMentworkChannel but test needs pointer
+ // to it.
+ delegate_ = new TestGCMNetworkChannelDelegate();
+ scoped_ptr<GCMNetworkChannelDelegate> delegate(delegate_);
+ gcm_network_channel_.reset(new TestGCMNetworkChannel(
+ request_context_getter_,
+ delegate.Pass()));
+ gcm_network_channel_->AddObserver(this);
+ gcm_network_channel_->SetMessageReceiver(
+ invalidation::NewPermanentCallback(
+ this, &GCMNetworkChannelTest::OnIncomingMessage));
+ url_fetcher_factory_.reset(new net::FakeURLFetcherFactory(NULL,
+ base::Bind(&GCMNetworkChannelTest::CreateURLFetcher,
+ base::Unretained(this))));
+ }
+
+ virtual void TearDown() {
+ gcm_network_channel_->RemoveObserver(this);
+ }
+
+ // Helper functions to call private methods from test
+ GURL BuildUrl(const std::string& registration_id) {
+ return gcm_network_channel_->GCMNetworkChannel::BuildUrl(registration_id);
+ }
+
+ static void Base64EncodeURLSafe(const std::string& input,
+ std::string* output) {
+ GCMNetworkChannel::Base64EncodeURLSafe(input, output);
+ }
+
+ static bool Base64DecodeURLSafe(const std::string& input,
+ std::string* output) {
+ return GCMNetworkChannel::Base64DecodeURLSafe(input, output);
+ }
+
+ virtual void OnNetworkChannelStateChanged(
+ InvalidatorState invalidator_state) OVERRIDE {
+ last_invalidator_state_ = invalidator_state;
+ }
+
+ void OnIncomingMessage(std::string incoming_message) {
+ }
+
+ GCMNetworkChannel* network_channel() {
+ return gcm_network_channel_.get();
+ }
+
+ TestGCMNetworkChannelDelegate* delegate() {
+ return delegate_;
+ }
+
+ int url_fetchers_created_count() {
+ return url_fetchers_created_count_;
+ }
+
+ net::FakeURLFetcherFactory* url_fetcher_factory() {
+ return url_fetcher_factory_.get();
+ }
+
+ scoped_ptr<net::FakeURLFetcher> CreateURLFetcher(
+ const GURL& url,
+ net::URLFetcherDelegate* delegate,
+ const std::string& response_data,
+ net::HttpStatusCode response_code,
+ net::URLRequestStatus::Status status) {
+ ++url_fetchers_created_count_;
+ return scoped_ptr<net::FakeURLFetcher>(new TestNetworkChannelURLFetcher(
+ this, url, delegate, response_data, response_code, status));
+ }
+
+ void set_last_echo_token(const std::string& echo_token) {
+ last_echo_token_ = echo_token;
+ }
+
+ const std::string& get_last_echo_token() {
+ return last_echo_token_;
+ }
+
+ InvalidatorState get_last_invalidator_state() {
+ return last_invalidator_state_;
+ }
+
+ void RunLoopUntilIdle() {
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+ TestGCMNetworkChannelDelegate* delegate_;
+ scoped_ptr<GCMNetworkChannel> gcm_network_channel_;
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+ scoped_ptr<net::FakeURLFetcherFactory> url_fetcher_factory_;
+ int url_fetchers_created_count_;
+ std::string last_echo_token_;
+ InvalidatorState last_invalidator_state_;
+};
+
+void TestNetworkChannelURLFetcher::AddExtraRequestHeader(
+ const std::string& header_line) {
+ net::FakeURLFetcher::AddExtraRequestHeader(header_line);
+ std::string header_name("echo-token: ");
+ std::string echo_token;
+ if (StartsWithASCII(header_line, header_name, false)) {
+ echo_token = header_line;
+ ReplaceFirstSubstringAfterOffset(
+ &echo_token, 0, header_name, std::string());
+ test_->set_last_echo_token(echo_token);
+ }
+}
+
+TEST_F(GCMNetworkChannelTest, HappyCase) {
+ EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
+ EXPECT_FALSE(delegate()->message_callback.is_null());
+ url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
+ std::string(),
+ net::HTTP_NO_CONTENT,
+ net::URLRequestStatus::SUCCESS);
+
+ // After construction GCMNetworkChannel should have called Register.
+ EXPECT_FALSE(delegate()->register_callback.is_null());
+ // Return valid registration id.
+ delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
+
+ network_channel()->SendMessage("abra.cadabra");
+ // SendMessage should have triggered RequestToken. No HTTP request should be
+ // started yet.
+ EXPECT_FALSE(delegate()->request_token_callback.is_null());
+ EXPECT_EQ(url_fetchers_created_count(), 0);
+ // Return valid access token. This should trigger HTTP request.
+ delegate()->request_token_callback.Run(
+ GoogleServiceAuthError::AuthErrorNone(), "access.token");
+ RunLoopUntilIdle();
+ EXPECT_EQ(url_fetchers_created_count(), 1);
+
+ // Return another access token. Message should be cleared by now and shouldn't
+ // be sent.
+ delegate()->request_token_callback.Run(
+ GoogleServiceAuthError::AuthErrorNone(), "access.token2");
+ RunLoopUntilIdle();
+ EXPECT_EQ(url_fetchers_created_count(), 1);
+ EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
+}
+
+TEST_F(GCMNetworkChannelTest, FailedRegister) {
+ // After construction GCMNetworkChannel should have called Register.
+ EXPECT_FALSE(delegate()->register_callback.is_null());
+ EXPECT_EQ(1, delegate()->register_call_count_);
+ // Return transient error from Register call.
+ delegate()->register_callback.Run("", gcm::GCMClient::NETWORK_ERROR);
+ RunLoopUntilIdle();
+ // GcmNetworkChannel should have scheduled Register retry.
+ EXPECT_EQ(2, delegate()->register_call_count_);
+ // Return persistent error from Register call.
+ delegate()->register_callback.Run("", gcm::GCMClient::NOT_SIGNED_IN);
+ RunLoopUntilIdle();
+ // GcmNetworkChannel should give up trying.
+ EXPECT_EQ(2, delegate()->register_call_count_);
+
+ network_channel()->SendMessage("abra.cadabra");
+ // SendMessage shouldn't trigger RequestToken.
+ EXPECT_TRUE(delegate()->request_token_callback.is_null());
+ EXPECT_EQ(0, url_fetchers_created_count());
+}
+
+TEST_F(GCMNetworkChannelTest, RegisterFinishesAfterSendMessage) {
+ url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
+ "",
+ net::HTTP_NO_CONTENT,
+ net::URLRequestStatus::SUCCESS);
+
+ // After construction GCMNetworkChannel should have called Register.
+ EXPECT_FALSE(delegate()->register_callback.is_null());
+
+ network_channel()->SendMessage("abra.cadabra");
+ // SendMessage shouldn't trigger RequestToken.
+ EXPECT_TRUE(delegate()->request_token_callback.is_null());
+ EXPECT_EQ(url_fetchers_created_count(), 0);
+
+ // Return valid registration id.
+ delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
+
+ EXPECT_FALSE(delegate()->request_token_callback.is_null());
+ EXPECT_EQ(url_fetchers_created_count(), 0);
+ // Return valid access token. This should trigger HTTP request.
+ delegate()->request_token_callback.Run(
+ GoogleServiceAuthError::AuthErrorNone(), "access.token");
+ RunLoopUntilIdle();
+ EXPECT_EQ(url_fetchers_created_count(), 1);
+}
+
+TEST_F(GCMNetworkChannelTest, RequestTokenFailure) {
+ // After construction GCMNetworkChannel should have called Register.
+ EXPECT_FALSE(delegate()->register_callback.is_null());
+ // Return valid registration id.
+ delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
+
+ network_channel()->SendMessage("abra.cadabra");
+ // SendMessage should have triggered RequestToken. No HTTP request should be
+ // started yet.
+ EXPECT_FALSE(delegate()->request_token_callback.is_null());
+ EXPECT_EQ(url_fetchers_created_count(), 0);
+ // RequestToken returns failure.
+ delegate()->request_token_callback.Run(
+ GoogleServiceAuthError::FromConnectionError(1), "");
+
+ // Should be no HTTP requests.
+ EXPECT_EQ(url_fetchers_created_count(), 0);
+}
+
+TEST_F(GCMNetworkChannelTest, AuthErrorFromServer) {
+ // Setup fake response to return AUTH_ERROR.
+ url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
+ "",
+ net::HTTP_UNAUTHORIZED,
+ net::URLRequestStatus::SUCCESS);
+
+ // After construction GCMNetworkChannel should have called Register.
+ EXPECT_FALSE(delegate()->register_callback.is_null());
+ // Return valid registration id.
+ delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
+
+ network_channel()->SendMessage("abra.cadabra");
+ // SendMessage should have triggered RequestToken. No HTTP request should be
+ // started yet.
+ EXPECT_FALSE(delegate()->request_token_callback.is_null());
+ EXPECT_EQ(url_fetchers_created_count(), 0);
+ // Return valid access token. This should trigger HTTP request.
+ delegate()->request_token_callback.Run(
+ GoogleServiceAuthError::AuthErrorNone(), "access.token");
+ RunLoopUntilIdle();
+ EXPECT_EQ(url_fetchers_created_count(), 1);
+ EXPECT_EQ(delegate()->invalidated_token, "access.token");
+}
+
+// Following two tests are to check for memory leaks/crashes when Register and
+// RequestToken don't complete by the teardown.
+TEST_F(GCMNetworkChannelTest, RegisterNeverCompletes) {
+ network_channel()->SendMessage("abra.cadabra");
+ // Register should be called by now. Let's not complete and see what happens.
+ EXPECT_FALSE(delegate()->register_callback.is_null());
+}
+
+TEST_F(GCMNetworkChannelTest, RequestTokenNeverCompletes) {
+ network_channel()->SendMessage("abra.cadabra");
+ // Return valid registration id.
+ delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
+ // RequestToken should be called by now. Let's not complete and see what
+ // happens.
+ EXPECT_FALSE(delegate()->request_token_callback.is_null());
+}
+
+TEST_F(GCMNetworkChannelTest, Base64EncodeDecode) {
+ std::string input;
+ std::string plain;
+ std::string base64;
+ // Empty string.
+ Base64EncodeURLSafe(input, &base64);
+ EXPECT_TRUE(base64.empty());
+ EXPECT_TRUE(Base64DecodeURLSafe(base64, &plain));
+ EXPECT_EQ(input, plain);
+ // String length: 1..7.
+ for (int length = 1; length < 8; length++) {
+ input = "abra.cadabra";
+ input.resize(length);
+ Base64EncodeURLSafe(input, &base64);
+ // Ensure no padding at the end.
+ EXPECT_NE(base64[base64.size() - 1], '=');
+ EXPECT_TRUE(Base64DecodeURLSafe(base64, &plain));
+ EXPECT_EQ(input, plain);
+ }
+ // Presence of '-', '_'.
+ input = "\xfb\xff";
+ Base64EncodeURLSafe(input, &base64);
+ EXPECT_EQ("-_8", base64);
+ EXPECT_TRUE(Base64DecodeURLSafe(base64, &plain));
+ EXPECT_EQ(input, plain);
+}
+
+TEST_F(GCMNetworkChannelTest, TransientError) {
+ EXPECT_FALSE(delegate()->message_callback.is_null());
+ // POST will fail.
+ url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
+ std::string(),
+ net::HTTP_SERVICE_UNAVAILABLE,
+ net::URLRequestStatus::SUCCESS);
+
+ delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
+
+ network_channel()->SendMessage("abra.cadabra");
+ EXPECT_FALSE(delegate()->request_token_callback.is_null());
+ delegate()->request_token_callback.Run(
+ GoogleServiceAuthError::AuthErrorNone(), "access.token");
+ RunLoopUntilIdle();
+ EXPECT_EQ(url_fetchers_created_count(), 1);
+ // Failing HTTP POST should cause TRANSIENT_INVALIDATION_ERROR.
+ EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
+ // Network change to CONNECTION_NONE shouldn't affect invalidator state.
+ network_channel()->OnNetworkChanged(
+ net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
+ // Network change to something else should trigger retry.
+ network_channel()->OnNetworkChanged(
+ net::NetworkChangeNotifier::CONNECTION_WIFI);
+ EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
+ network_channel()->OnNetworkChanged(
+ net::NetworkChangeNotifier::CONNECTION_NONE);
+ EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
+}
+
+#if !defined(OS_ANDROID)
+TEST_F(GCMNetworkChannelTest, BuildUrl) {
+ GURL url = BuildUrl("registration.id");
+ EXPECT_TRUE(url.SchemeIsHTTPOrHTTPS());
+ EXPECT_FALSE(url.host().empty());
+ EXPECT_FALSE(url.path().empty());
+ std::vector<std::string> parts;
+ Tokenize(url.path(), "/", &parts);
+ std::string buffer;
+ EXPECT_TRUE(Base64DecodeURLSafe(parts[parts.size() - 1], &buffer));
+}
+
+TEST_F(GCMNetworkChannelTest, EchoToken) {
+ url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
+ std::string(),
+ net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ // After construction GCMNetworkChannel should have called Register.
+ // Return valid registration id.
+ delegate()->register_callback.Run("registration.id", gcm::GCMClient::SUCCESS);
+
+ network_channel()->SendMessage("abra.cadabra");
+ // Return valid access token. This should trigger HTTP request.
+ delegate()->request_token_callback.Run(
+ GoogleServiceAuthError::AuthErrorNone(), "access.token");
+ RunLoopUntilIdle();
+ EXPECT_EQ(url_fetchers_created_count(), 1);
+ EXPECT_TRUE(get_last_echo_token().empty());
+
+ // Trigger response.
+ delegate()->message_callback.Run("abra.cadabra", "echo.token");
+ // Send another message.
+ network_channel()->SendMessage("abra.cadabra");
+ // Return valid access token. This should trigger HTTP request.
+ delegate()->request_token_callback.Run(
+ GoogleServiceAuthError::AuthErrorNone(), "access.token");
+ RunLoopUntilIdle();
+ EXPECT_EQ(url_fetchers_created_count(), 2);
+ EXPECT_EQ("echo.token", get_last_echo_token());
+
+ // Trigger response with empty echo token.
+ delegate()->message_callback.Run("abra.cadabra", "");
+ // Send another message.
+ network_channel()->SendMessage("abra.cadabra");
+ // Return valid access token. This should trigger HTTP request.
+ delegate()->request_token_callback.Run(
+ GoogleServiceAuthError::AuthErrorNone(), "access.token");
+ RunLoopUntilIdle();
+ EXPECT_EQ(url_fetchers_created_count(), 3);
+ // Echo_token should be from second message.
+ EXPECT_EQ("echo.token", get_last_echo_token());
+}
+#endif
+
+} // namespace syncer
« no previous file with comments | « sync/notifier/gcm_network_channel_delegate.h ('k') | sync/notifier/invalidation_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698