Commit dd507f56 authored by pavely@chromium.org's avatar pavely@chromium.org

Notify SyncNetworkChannel about GCM connection state

This change propagates GCM connection state from GCMInvalidationBridge
to SyncNetworkChannel where based on this notification overall
invalidations state is updated.

This change still has issue that when GCM connection is down but HTTP request
succeeds then status is updated to NOTIFICATIONS_ENABLED. Fixing this
requires minor refactoring which I would like to pull into separate change.

BUG=378536
R=rlarocque@chromium.org

Review URL: https://codereview.chromium.org/334253006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278225 0039d316-1c4b-4281-b951-d872f2087c98
parent 688ad62a
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "google_apis/gaia/fake_identity_provider.h" #include "google_apis/gaia/fake_identity_provider.h"
#include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/google_service_auth_error.h"
#include "net/base/ip_endpoint.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace invalidation { namespace invalidation {
...@@ -45,7 +46,9 @@ class CustomFakeGCMDriver : public gcm::FakeGCMDriver { ...@@ -45,7 +46,9 @@ class CustomFakeGCMDriver : public gcm::FakeGCMDriver {
class GCMInvalidationBridgeTest : public ::testing::Test { class GCMInvalidationBridgeTest : public ::testing::Test {
protected: protected:
GCMInvalidationBridgeTest() {} GCMInvalidationBridgeTest()
: connection_state_(
syncer::GCMNetworkChannelDelegate::CONNECTION_STATE_OFFLINE) {}
virtual ~GCMInvalidationBridgeTest() {} virtual ~GCMInvalidationBridgeTest() {}
...@@ -66,7 +69,13 @@ class GCMInvalidationBridgeTest : public ::testing::Test { ...@@ -66,7 +69,13 @@ class GCMInvalidationBridgeTest : public ::testing::Test {
identity_provider_.get())); identity_provider_.get()));
delegate_ = bridge_->CreateDelegate(); delegate_ = bridge_->CreateDelegate();
delegate_->Initialize(); delegate_->Initialize(
base::Bind(&GCMInvalidationBridgeTest::ConnectionStateChanged,
base::Unretained(this)));
RunLoop();
}
void RunLoop() {
base::RunLoop run_loop; base::RunLoop run_loop;
run_loop.RunUntilIdle(); run_loop.RunUntilIdle();
} }
...@@ -83,6 +92,11 @@ class GCMInvalidationBridgeTest : public ::testing::Test { ...@@ -83,6 +92,11 @@ class GCMInvalidationBridgeTest : public ::testing::Test {
request_token_errors_.push_back(error); request_token_errors_.push_back(error);
} }
void ConnectionStateChanged(
syncer::GCMNetworkChannelDelegate::ConnectionState connection_state) {
connection_state_ = connection_state;
}
content::TestBrowserThreadBundle thread_bundle_; content::TestBrowserThreadBundle thread_bundle_;
scoped_ptr<Profile> profile_; scoped_ptr<Profile> profile_;
scoped_ptr<gcm::GCMDriver> gcm_driver_; scoped_ptr<gcm::GCMDriver> gcm_driver_;
...@@ -91,6 +105,7 @@ class GCMInvalidationBridgeTest : public ::testing::Test { ...@@ -91,6 +105,7 @@ class GCMInvalidationBridgeTest : public ::testing::Test {
std::vector<std::string> issued_tokens_; std::vector<std::string> issued_tokens_;
std::vector<GoogleServiceAuthError> request_token_errors_; std::vector<GoogleServiceAuthError> request_token_errors_;
std::string registration_id_; std::string registration_id_;
syncer::GCMNetworkChannelDelegate::ConnectionState connection_state_;
scoped_ptr<GCMInvalidationBridge> bridge_; scoped_ptr<GCMInvalidationBridge> bridge_;
scoped_ptr<syncer::GCMNetworkChannelDelegate> delegate_; scoped_ptr<syncer::GCMNetworkChannelDelegate> delegate_;
...@@ -102,8 +117,7 @@ TEST_F(GCMInvalidationBridgeTest, RequestToken) { ...@@ -102,8 +117,7 @@ TEST_F(GCMInvalidationBridgeTest, RequestToken) {
delegate_->RequestToken( delegate_->RequestToken(
base::Bind(&GCMInvalidationBridgeTest::RequestTokenFinished, base::Bind(&GCMInvalidationBridgeTest::RequestTokenFinished,
base::Unretained(this))); base::Unretained(this)));
base::RunLoop run_loop; RunLoop();
run_loop.RunUntilIdle();
EXPECT_EQ(1U, issued_tokens_.size()); EXPECT_EQ(1U, issued_tokens_.size());
EXPECT_NE("", issued_tokens_[0]); EXPECT_NE("", issued_tokens_[0]);
EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), request_token_errors_[0]); EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), request_token_errors_[0]);
...@@ -118,8 +132,7 @@ TEST_F(GCMInvalidationBridgeTest, RequestTokenTwoConcurrentRequests) { ...@@ -118,8 +132,7 @@ TEST_F(GCMInvalidationBridgeTest, RequestTokenTwoConcurrentRequests) {
delegate_->RequestToken( delegate_->RequestToken(
base::Bind(&GCMInvalidationBridgeTest::RequestTokenFinished, base::Bind(&GCMInvalidationBridgeTest::RequestTokenFinished,
base::Unretained(this))); base::Unretained(this)));
base::RunLoop run_loop; RunLoop();
run_loop.RunUntilIdle();
EXPECT_EQ(2U, issued_tokens_.size()); EXPECT_EQ(2U, issued_tokens_.size());
...@@ -135,11 +148,23 @@ TEST_F(GCMInvalidationBridgeTest, Register) { ...@@ -135,11 +148,23 @@ TEST_F(GCMInvalidationBridgeTest, Register) {
EXPECT_TRUE(registration_id_.empty()); EXPECT_TRUE(registration_id_.empty());
delegate_->Register(base::Bind(&GCMInvalidationBridgeTest::RegisterFinished, delegate_->Register(base::Bind(&GCMInvalidationBridgeTest::RegisterFinished,
base::Unretained(this))); base::Unretained(this)));
base::RunLoop run_loop; RunLoop();
run_loop.RunUntilIdle();
EXPECT_FALSE(registration_id_.empty()); EXPECT_FALSE(registration_id_.empty());
} }
TEST_F(GCMInvalidationBridgeTest, ConnectionState) {
EXPECT_EQ(syncer::GCMNetworkChannelDelegate::CONNECTION_STATE_OFFLINE,
connection_state_);
bridge_->OnConnected(net::IPEndPoint());
RunLoop();
EXPECT_EQ(syncer::GCMNetworkChannelDelegate::CONNECTION_STATE_ONLINE,
connection_state_);
bridge_->OnDisconnected();
RunLoop();
EXPECT_EQ(syncer::GCMNetworkChannelDelegate::CONNECTION_STATE_OFFLINE,
connection_state_);
}
} // namespace } // namespace
} // namespace invalidation } // namespace invalidation
...@@ -41,7 +41,7 @@ class GCMInvalidationBridge::Core : public syncer::GCMNetworkChannelDelegate, ...@@ -41,7 +41,7 @@ class GCMInvalidationBridge::Core : public syncer::GCMNetworkChannelDelegate,
virtual ~Core(); virtual ~Core();
// syncer::GCMNetworkChannelDelegate implementation. // syncer::GCMNetworkChannelDelegate implementation.
virtual void Initialize() OVERRIDE; virtual void Initialize(ConnectionStateCallback callback) OVERRIDE;
virtual void RequestToken(RequestTokenCallback callback) OVERRIDE; virtual void RequestToken(RequestTokenCallback callback) OVERRIDE;
virtual void InvalidateToken(const std::string& token) OVERRIDE; virtual void InvalidateToken(const std::string& token) OVERRIDE;
virtual void Register(RegisterCallback callback) OVERRIDE; virtual void Register(RegisterCallback callback) OVERRIDE;
...@@ -58,11 +58,14 @@ class GCMInvalidationBridge::Core : public syncer::GCMNetworkChannelDelegate, ...@@ -58,11 +58,14 @@ class GCMInvalidationBridge::Core : public syncer::GCMNetworkChannelDelegate,
void OnIncomingMessage(const std::string& message, void OnIncomingMessage(const std::string& message,
const std::string& echo_token); const std::string& echo_token);
void OnConnectionStateChanged(ConnectionState connection_state);
private: private:
base::WeakPtr<GCMInvalidationBridge> bridge_; base::WeakPtr<GCMInvalidationBridge> bridge_;
scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
MessageCallback message_callback_; MessageCallback message_callback_;
ConnectionStateCallback connection_state_callback_;
base::WeakPtrFactory<Core> weak_factory_; base::WeakPtrFactory<Core> weak_factory_;
...@@ -81,8 +84,9 @@ GCMInvalidationBridge::Core::Core( ...@@ -81,8 +84,9 @@ GCMInvalidationBridge::Core::Core(
GCMInvalidationBridge::Core::~Core() {} GCMInvalidationBridge::Core::~Core() {}
void GCMInvalidationBridge::Core::Initialize() { void GCMInvalidationBridge::Core::Initialize(ConnectionStateCallback callback) {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
connection_state_callback_ = callback;
// Pass core WeapPtr and TaskRunner to GCMInvalidationBridge for it to be able // Pass core WeapPtr and TaskRunner to GCMInvalidationBridge for it to be able
// to post back. // to post back.
ui_thread_task_runner_->PostTask( ui_thread_task_runner_->PostTask(
...@@ -145,6 +149,13 @@ void GCMInvalidationBridge::Core::OnIncomingMessage( ...@@ -145,6 +149,13 @@ void GCMInvalidationBridge::Core::OnIncomingMessage(
message_callback_.Run(message, echo_token); message_callback_.Run(message, echo_token);
} }
void GCMInvalidationBridge::Core::OnConnectionStateChanged(
ConnectionState connection_state) {
if (!connection_state_callback_.is_null()) {
connection_state_callback_.Run(connection_state);
}
}
GCMInvalidationBridge::GCMInvalidationBridge( GCMInvalidationBridge::GCMInvalidationBridge(
gcm::GCMDriver* gcm_driver, gcm::GCMDriver* gcm_driver,
IdentityProvider* identity_provider) IdentityProvider* identity_provider)
...@@ -317,11 +328,19 @@ void GCMInvalidationBridge::OnSendError( ...@@ -317,11 +328,19 @@ void GCMInvalidationBridge::OnSendError(
} }
void GCMInvalidationBridge::OnConnected(const net::IPEndPoint& ip_endpoint) { void GCMInvalidationBridge::OnConnected(const net::IPEndPoint& ip_endpoint) {
// TODO(pavely): update invalidator state. core_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GCMInvalidationBridge::Core::OnConnectionStateChanged,
core_,
syncer::GCMNetworkChannelDelegate::CONNECTION_STATE_ONLINE));
} }
void GCMInvalidationBridge::OnDisconnected() { void GCMInvalidationBridge::OnDisconnected() {
// TODO(pavely): update invalidator state. core_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GCMInvalidationBridge::Core::OnConnectionStateChanged,
core_,
syncer::GCMNetworkChannelDelegate::CONNECTION_STATE_OFFLINE));
} }
......
...@@ -110,7 +110,8 @@ GCMNetworkChannel::GCMNetworkChannel( ...@@ -110,7 +110,8 @@ GCMNetworkChannel::GCMNetworkChannel(
diagnostic_info_(this), diagnostic_info_(this),
weak_factory_(this) { weak_factory_(this) {
net::NetworkChangeNotifier::AddNetworkChangeObserver(this); net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
delegate_->Initialize(); delegate_->Initialize(base::Bind(&GCMNetworkChannel::OnConnectionStateChanged,
weak_factory_.GetWeakPtr()));
Register(); Register();
} }
...@@ -283,6 +284,24 @@ void GCMNetworkChannel::OnIncomingMessage(const std::string& message, ...@@ -283,6 +284,24 @@ void GCMNetworkChannel::OnIncomingMessage(const std::string& message,
#endif #endif
} }
void GCMNetworkChannel::OnConnectionStateChanged(
GCMNetworkChannelDelegate::ConnectionState connection_state) {
switch (connection_state) {
case GCMNetworkChannelDelegate::CONNECTION_STATE_OFFLINE: {
NotifyStateChange(TRANSIENT_INVALIDATION_ERROR);
break;
}
case GCMNetworkChannelDelegate::CONNECTION_STATE_ONLINE: {
NotifyStateChange(INVALIDATIONS_ENABLED);
break;
}
default: {
NOTREACHED();
break;
}
}
}
void GCMNetworkChannel::OnNetworkChanged( void GCMNetworkChannel::OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType connection_type) { net::NetworkChangeNotifier::ConnectionType connection_type) {
// Network connection is restored. Let's notify cacheinvalidations so it has // Network connection is restored. Let's notify cacheinvalidations so it has
......
...@@ -93,6 +93,8 @@ class INVALIDATION_EXPORT_PRIVATE GCMNetworkChannel ...@@ -93,6 +93,8 @@ class INVALIDATION_EXPORT_PRIVATE GCMNetworkChannel
const std::string& token); const std::string& token);
void OnIncomingMessage(const std::string& message, void OnIncomingMessage(const std::string& message,
const std::string& echo_token); const std::string& echo_token);
void OnConnectionStateChanged(
GCMNetworkChannelDelegate::ConnectionState connection_state);
// Base64 encoding/decoding with URL safe alphabet. // Base64 encoding/decoding with URL safe alphabet.
// http://tools.ietf.org/html/rfc4648#page-7 // http://tools.ietf.org/html/rfc4648#page-7
......
...@@ -24,16 +24,23 @@ namespace syncer { ...@@ -24,16 +24,23 @@ namespace syncer {
// thread and callbacks should be invoked there as well. // thread and callbacks should be invoked there as well.
class GCMNetworkChannelDelegate { class GCMNetworkChannelDelegate {
public: public:
enum ConnectionState {
CONNECTION_STATE_OFFLINE,
CONNECTION_STATE_ONLINE
};
typedef base::Callback<void(const GoogleServiceAuthError& error, typedef base::Callback<void(const GoogleServiceAuthError& error,
const std::string& token)> RequestTokenCallback; const std::string& token)> RequestTokenCallback;
typedef base::Callback<void(const std::string& registration_id, typedef base::Callback<void(const std::string& registration_id,
gcm::GCMClient::Result result)> RegisterCallback; gcm::GCMClient::Result result)> RegisterCallback;
typedef base::Callback<void(const std::string& message, typedef base::Callback<void(const std::string& message,
const std::string& echo_token)> MessageCallback; const std::string& echo_token)> MessageCallback;
typedef base::Callback<void(ConnectionState connection_state)>
ConnectionStateCallback;
virtual ~GCMNetworkChannelDelegate() {} virtual ~GCMNetworkChannelDelegate() {}
virtual void Initialize() = 0; virtual void Initialize(ConnectionStateCallback callback) = 0;
// Request access token. Callback should be called either with access token or // Request access token. Callback should be called either with access token or
// error code. // error code.
virtual void RequestToken(RequestTokenCallback callback) = 0; virtual void RequestToken(RequestTokenCallback callback) = 0;
......
...@@ -17,7 +17,10 @@ class TestGCMNetworkChannelDelegate : public GCMNetworkChannelDelegate { ...@@ -17,7 +17,10 @@ class TestGCMNetworkChannelDelegate : public GCMNetworkChannelDelegate {
TestGCMNetworkChannelDelegate() TestGCMNetworkChannelDelegate()
: register_call_count_(0) {} : register_call_count_(0) {}
virtual void Initialize() OVERRIDE {} virtual void Initialize(
GCMNetworkChannelDelegate::ConnectionStateCallback callback) OVERRIDE {
connection_state_callback = callback;
}
virtual void RequestToken(RequestTokenCallback callback) OVERRIDE { virtual void RequestToken(RequestTokenCallback callback) OVERRIDE {
request_token_callback = callback; request_token_callback = callback;
...@@ -41,6 +44,7 @@ class TestGCMNetworkChannelDelegate : public GCMNetworkChannelDelegate { ...@@ -41,6 +44,7 @@ class TestGCMNetworkChannelDelegate : public GCMNetworkChannelDelegate {
RegisterCallback register_callback; RegisterCallback register_callback;
int register_call_count_; int register_call_count_;
MessageCallback message_callback; MessageCallback message_callback;
ConnectionStateCallback connection_state_callback;
}; };
// Backoff policy for test. Run first 5 retries without delay. // Backoff policy for test. Run first 5 retries without delay.
...@@ -406,7 +410,7 @@ TEST_F(GCMNetworkChannelTest, Base64EncodeDecode) { ...@@ -406,7 +410,7 @@ TEST_F(GCMNetworkChannelTest, Base64EncodeDecode) {
EXPECT_EQ(input, plain); EXPECT_EQ(input, plain);
} }
TEST_F(GCMNetworkChannelTest, TransientError) { TEST_F(GCMNetworkChannelTest, HttpTransientError) {
EXPECT_FALSE(delegate()->message_callback.is_null()); EXPECT_FALSE(delegate()->message_callback.is_null());
// POST will fail. // POST will fail.
url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"), url_fetcher_factory()->SetFakeResponse(GURL("http://test.url.com"),
...@@ -437,6 +441,15 @@ TEST_F(GCMNetworkChannelTest, TransientError) { ...@@ -437,6 +441,15 @@ TEST_F(GCMNetworkChannelTest, TransientError) {
EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state()); EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
} }
TEST_F(GCMNetworkChannelTest, GcmConnectionState) {
delegate()->connection_state_callback.Run(
GCMNetworkChannelDelegate::CONNECTION_STATE_OFFLINE);
EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, get_last_invalidator_state());
delegate()->connection_state_callback.Run(
GCMNetworkChannelDelegate::CONNECTION_STATE_ONLINE);
EXPECT_EQ(INVALIDATIONS_ENABLED, get_last_invalidator_state());
}
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
TEST_F(GCMNetworkChannelTest, BuildUrl) { TEST_F(GCMNetworkChannelTest, BuildUrl) {
GURL url = BuildUrl("registration.id"); GURL url = BuildUrl("registration.id");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment