From 28935deb05428f98b1a051cd9ccb3c2c862a967b Mon Sep 17 00:00:00 2001 From: "pavely@chromium.org" Date: Fri, 6 Dec 2013 12:45:18 +0000 Subject: [PATCH] Refactor PushClientChannel Move code responsible for working with invalidations library out of PushClientChannel into SyncNetworkChannel. PushClientChannel only has code related to PushClient. Create PushClient independent SyncNetworkChannel::Observer interface and make SyncInvalidationListener observe it instead of PushClientObserver. Move ownership of PushClientChannel from SyncSystemResources to SyncInvalidationListener. Tests for PushClientChannel are still in push_client_channel_unittest.cc. I'll split those in subsequent patch. BUG=325020 Review URL: https://codereview.chromium.org/103223004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239176 0039d316-1c4b-4281-b951-d872f2087c98 --- sync/notifier/push_client_channel.cc | 224 +++++--------- sync/notifier/push_client_channel.h | 54 +--- sync/notifier/push_client_channel_unittest.cc | 371 ++++++++---------------- sync/notifier/sync_invalidation_listener.cc | 28 +- sync/notifier/sync_invalidation_listener.h | 16 +- sync/notifier/sync_system_resources.cc | 138 ++++++++- sync/notifier/sync_system_resources.h | 106 ++++++- sync/notifier/sync_system_resources_unittest.cc | 231 ++++++++++++++- 8 files changed, 660 insertions(+), 508 deletions(-) rewrite sync/notifier/push_client_channel.cc (68%) rewrite sync/notifier/push_client_channel_unittest.cc (64%) diff --git a/sync/notifier/push_client_channel.cc b/sync/notifier/push_client_channel.cc dissimilarity index 68% index b5f31c14a14b..a067a215d644 100644 --- a/sync/notifier/push_client_channel.cc +++ b/sync/notifier/push_client_channel.cc @@ -1,159 +1,65 @@ -// Copyright (c) 2012 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 "sync/notifier/push_client_channel.h" - -#include "base/stl_util.h" -#include "google/cacheinvalidation/client_gateway.pb.h" -#include "jingle/notifier/listener/push_client.h" - -namespace syncer { - -namespace { - -const char kBotJid[] = "tango@bot.talk.google.com"; -const char kChannelName[] = "tango_raw"; - -} // namespace - -PushClientChannel::PushClientChannel( - scoped_ptr push_client) - : push_client_(push_client.Pass()), - notifications_enabled_(false), - scheduling_hash_(0) { - push_client_->AddObserver(this); - notifier::Subscription subscription; - subscription.channel = kChannelName; - subscription.from = ""; - notifier::SubscriptionList subscriptions; - subscriptions.push_back(subscription); - push_client_->UpdateSubscriptions(subscriptions); -} - -PushClientChannel::~PushClientChannel() { - push_client_->RemoveObserver(this); - STLDeleteElements(&network_status_receivers_); -} - -void PushClientChannel::UpdateCredentials( - const std::string& email, const std::string& token) { - push_client_->UpdateCredentials(email, token); -} - -void PushClientChannel::SendMessage(const std::string& outgoing_message) { - push_client_->SendNotification( - EncodeMessage(outgoing_message, service_context_, scheduling_hash_)); -} - -void PushClientChannel::SetMessageReceiver( - invalidation::MessageCallback* incoming_receiver) { - incoming_receiver_.reset(incoming_receiver); -} - -void PushClientChannel::AddNetworkStatusReceiver( - invalidation::NetworkStatusCallback* network_status_receiver) { - network_status_receiver->Run(notifications_enabled_); - network_status_receivers_.push_back(network_status_receiver); -} - -void PushClientChannel::SetSystemResources( - invalidation::SystemResources* resources) { - // Do nothing. -} - -void PushClientChannel::OnNotificationsEnabled() { - for (NetworkStatusReceiverList::const_iterator it = - network_status_receivers_.begin(); - it != network_status_receivers_.end(); ++it) { - (*it)->Run(true); - } -} - -void PushClientChannel::OnNotificationsDisabled( - notifier::NotificationsDisabledReason reason) { - for (NetworkStatusReceiverList::const_iterator it = - network_status_receivers_.begin(); - it != network_status_receivers_.end(); ++it) { - (*it)->Run(false); - } -} - -void PushClientChannel::OnIncomingNotification( - const notifier::Notification& notification) { - if (!incoming_receiver_) { - DLOG(ERROR) << "No receiver for incoming notification"; - return; - } - std::string message; - if (!DecodeMessage(notification, - &message, &service_context_, &scheduling_hash_)) { - DLOG(ERROR) << "Could not parse ClientGatewayMessage from: " - << notification.ToString(); - } - incoming_receiver_->Run(message); -} - -const std::string& PushClientChannel::GetServiceContextForTest() const { - return service_context_; -} - -int64 PushClientChannel::GetSchedulingHashForTest() const { - return scheduling_hash_; -} - -notifier::Notification PushClientChannel::EncodeMessageForTest( - const std::string& message, const std::string& service_context, - int64 scheduling_hash) { - return EncodeMessage(message, service_context, scheduling_hash); -} - -bool PushClientChannel::DecodeMessageForTest( - const notifier::Notification& notification, - std::string* message, - std::string* service_context, - int64* scheduling_hash) { - return DecodeMessage( - notification, message, service_context, scheduling_hash); -} - -notifier::Notification PushClientChannel::EncodeMessage( - const std::string& message, const std::string& service_context, - int64 scheduling_hash) { - ipc::invalidation::ClientGatewayMessage envelope; - envelope.set_is_client_to_server(true); - if (!service_context.empty()) { - envelope.set_service_context(service_context); - envelope.set_rpc_scheduling_hash(scheduling_hash); - } - envelope.set_network_message(message); - - notifier::Recipient recipient; - recipient.to = kBotJid; - notifier::Notification notification; - notification.channel = kChannelName; - notification.recipients.push_back(recipient); - envelope.SerializeToString(¬ification.data); - return notification; -} - -bool PushClientChannel::DecodeMessage( - const notifier::Notification& notification, - std::string* message, - std::string* service_context, - int64* scheduling_hash) { - ipc::invalidation::ClientGatewayMessage envelope; - if (!envelope.ParseFromString(notification.data)) { - return false; - } - *message = envelope.network_message(); - if (envelope.has_service_context()) { - *service_context = envelope.service_context(); - } - if (envelope.has_rpc_scheduling_hash()) { - *scheduling_hash = envelope.rpc_scheduling_hash(); - } - return true; -} - -} // namespace syncer +// Copyright (c) 2012 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 "sync/notifier/push_client_channel.h" + +#include "base/stl_util.h" +#include "google/cacheinvalidation/client_gateway.pb.h" +#include "jingle/notifier/listener/push_client.h" + +namespace syncer { + +namespace { + +const char kBotJid[] = "tango@bot.talk.google.com"; +const char kChannelName[] = "tango_raw"; + +} // namespace + +PushClientChannel::PushClientChannel( + scoped_ptr push_client) + : push_client_(push_client.Pass()) { + push_client_->AddObserver(this); + notifier::Subscription subscription; + subscription.channel = kChannelName; + subscription.from = ""; + notifier::SubscriptionList subscriptions; + subscriptions.push_back(subscription); + push_client_->UpdateSubscriptions(subscriptions); +} + +PushClientChannel::~PushClientChannel() { + push_client_->RemoveObserver(this); +} + +void PushClientChannel::UpdateCredentials( + const std::string& email, const std::string& token) { + push_client_->UpdateCredentials(email, token); +} + +void PushClientChannel::SendEncodedMessage(const std::string& encoded_message) { + notifier::Recipient recipient; + recipient.to = kBotJid; + notifier::Notification notification; + notification.channel = kChannelName; + notification.recipients.push_back(recipient); + notification.data = encoded_message; + push_client_->SendNotification(notification); +} + +void PushClientChannel::OnNotificationsEnabled() { + NotifyStateChange(INVALIDATIONS_ENABLED); +} + +void PushClientChannel::OnNotificationsDisabled( + notifier::NotificationsDisabledReason reason) { + NotifyStateChange(FromNotifierReason(reason)); +} + +void PushClientChannel::OnIncomingNotification( + const notifier::Notification& notification) { + DeliverIncomingMessage(notification.data); +} + +} // namespace syncer diff --git a/sync/notifier/push_client_channel.h b/sync/notifier/push_client_channel.h index 7bf908aa5af1..fa029ab91cde 100644 --- a/sync/notifier/push_client_channel.h +++ b/sync/notifier/push_client_channel.h @@ -6,14 +6,13 @@ #define SYNC_NOTIFIER_PUSH_CLIENT_CHANNEL_H_ #include -#include #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" -#include "google/cacheinvalidation/include/system-resources.h" #include "jingle/notifier/listener/push_client_observer.h" #include "sync/base/sync_export.h" +#include "sync/notifier/sync_system_resources.h" namespace notifier { class PushClient; @@ -24,7 +23,7 @@ namespace syncer { // A PushClientChannel is an implementation of NetworkChannel that // routes messages through a PushClient. class SYNC_EXPORT_PRIVATE PushClientChannel - : public NON_EXPORTED_BASE(invalidation::NetworkChannel), + : public SyncNetworkChannel, public NON_EXPORTED_BASE(notifier::PushClientObserver) { public: // |push_client| is guaranteed to be destroyed only when this object @@ -38,14 +37,8 @@ class SYNC_EXPORT_PRIVATE PushClientChannel // credentials. void UpdateCredentials(const std::string& email, const std::string& token); - // invalidation::NetworkChannel implementation. - virtual void SendMessage(const std::string& outgoing_message) OVERRIDE; - virtual void SetMessageReceiver( - invalidation::MessageCallback* incoming_receiver) OVERRIDE; - virtual void AddNetworkStatusReceiver( - invalidation::NetworkStatusCallback* network_status_receiver) OVERRIDE; - virtual void SetSystemResources( - invalidation::SystemResources* resources) OVERRIDE; + // SyncNetworkChannel implementation. + virtual void SendEncodedMessage(const std::string& encoded_message) OVERRIDE; // notifier::PushClient::Observer implementation. virtual void OnNotificationsEnabled() OVERRIDE; @@ -54,47 +47,8 @@ class SYNC_EXPORT_PRIVATE PushClientChannel virtual void OnIncomingNotification( const notifier::Notification& notification) OVERRIDE; - const std::string& GetServiceContextForTest() const; - - int64 GetSchedulingHashForTest() const; - - static notifier::Notification EncodeMessageForTest( - const std::string& message, - const std::string& service_context, - int64 scheduling_hash); - - static bool DecodeMessageForTest( - const notifier::Notification& notification, - std::string* message, - std::string* service_context, - int64* scheduling_hash); - private: - typedef std::vector - NetworkStatusReceiverList; - - static notifier::Notification EncodeMessage( - const std::string& message, - const std::string& service_context, - int64 scheduling_hash); - - static bool DecodeMessage( - const notifier::Notification& notification, - std::string* message, - std::string* service_context, - int64* scheduling_hash); - scoped_ptr push_client_; - scoped_ptr incoming_receiver_; - NetworkStatusReceiverList network_status_receivers_; - - bool notifications_enabled_; - - // Service context. - std::string service_context_; - - // Scheduling hash. - int64 scheduling_hash_; DISALLOW_COPY_AND_ASSIGN(PushClientChannel); }; diff --git a/sync/notifier/push_client_channel_unittest.cc b/sync/notifier/push_client_channel_unittest.cc dissimilarity index 64% index d017e1b9fdac..d0b75e417769 100644 --- a/sync/notifier/push_client_channel_unittest.cc +++ b/sync/notifier/push_client_channel_unittest.cc @@ -1,253 +1,118 @@ -// Copyright (c) 2012 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 "sync/notifier/push_client_channel.h" - -#include -#include - -#include "base/compiler_specific.h" -#include "jingle/notifier/listener/fake_push_client.h" -#include "jingle/notifier/listener/notification_defines.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace syncer { -namespace { - -class PushClientChannelTest : public ::testing::Test { - protected: - PushClientChannelTest() - : fake_push_client_(new notifier::FakePushClient()), - push_client_channel_( - scoped_ptr(fake_push_client_)), - connected_(false) { - push_client_channel_.SetMessageReceiver( - invalidation::NewPermanentCallback( - this, &PushClientChannelTest::OnIncomingMessage)); - push_client_channel_.AddNetworkStatusReceiver( - invalidation::NewPermanentCallback( - this, &PushClientChannelTest::OnNetworkStatusChange)); - push_client_channel_.SetSystemResources(NULL); - } - - virtual ~PushClientChannelTest() {} - - void OnIncomingMessage(std::string incoming_message) { - last_message_ = incoming_message; - } - - void OnNetworkStatusChange(bool connected) { - connected_ = connected; - } - - notifier::FakePushClient* fake_push_client_; - PushClientChannel push_client_channel_; - std::string last_message_; - bool connected_; -}; - -const char kMessage[] = "message"; -const char kServiceContext[] = "service context"; -const int64 kSchedulingHash = 100; - -// Encode a message with some context into a notification and then -// decode it. The decoded info should match the original info. -TEST_F(PushClientChannelTest, EncodeDecode) { - const notifier::Notification& notification = - PushClientChannel::EncodeMessageForTest( - kMessage, kServiceContext, kSchedulingHash); - std::string message; - std::string service_context; - int64 scheduling_hash = 0LL; - EXPECT_TRUE(PushClientChannel::DecodeMessageForTest( - notification, &message, &service_context, &scheduling_hash)); - EXPECT_EQ(kMessage, message); - EXPECT_EQ(kServiceContext, service_context); - EXPECT_EQ(kSchedulingHash, scheduling_hash); -} - -// Encode a message with no context into a notification and then -// decode it. The decoded message should match the original message, -// but the context and hash should be untouched. -TEST_F(PushClientChannelTest, EncodeDecodeNoContext) { - const notifier::Notification& notification = - PushClientChannel::EncodeMessageForTest( - kMessage, std::string(), kSchedulingHash); - std::string message; - std::string service_context = kServiceContext; - int64 scheduling_hash = kSchedulingHash + 1; - EXPECT_TRUE(PushClientChannel::DecodeMessageForTest( - notification, &message, &service_context, &scheduling_hash)); - EXPECT_EQ(kMessage, message); - EXPECT_EQ(kServiceContext, service_context); - EXPECT_EQ(kSchedulingHash + 1, scheduling_hash); -} - -// Decode an empty notification. It should result in an empty message -// but should leave the context and hash untouched. -TEST_F(PushClientChannelTest, DecodeEmpty) { - std::string message = kMessage; - std::string service_context = kServiceContext; - int64 scheduling_hash = kSchedulingHash; - EXPECT_TRUE(PushClientChannel::DecodeMessageForTest( - notifier::Notification(), - &message, &service_context, &scheduling_hash)); - EXPECT_TRUE(message.empty()); - EXPECT_EQ(kServiceContext, service_context); - EXPECT_EQ(kSchedulingHash, scheduling_hash); -} - -// Try to decode a garbage notification. It should leave all its -// arguments untouched and return false. -TEST_F(PushClientChannelTest, DecodeGarbage) { - notifier::Notification notification; - notification.data = "garbage"; - std::string message = kMessage; - std::string service_context = kServiceContext; - int64 scheduling_hash = kSchedulingHash; - EXPECT_FALSE(PushClientChannel::DecodeMessageForTest( - notification, &message, &service_context, &scheduling_hash)); - EXPECT_EQ(kMessage, message); - EXPECT_EQ(kServiceContext, service_context); - EXPECT_EQ(kSchedulingHash, scheduling_hash); -} - -// Make sure the channel subscribes to the correct notifications -// channel on construction. -TEST_F(PushClientChannelTest, Subscriptions) { - notifier::Subscription expected_subscription; - expected_subscription.channel = "tango_raw"; - EXPECT_TRUE(notifier::SubscriptionListsEqual( - fake_push_client_->subscriptions(), - notifier::SubscriptionList(1, expected_subscription))); -} - -// Call UpdateCredentials on the channel. It should propagate it to -// the push client. -TEST_F(PushClientChannelTest, UpdateCredentials) { - const char kEmail[] = "foo@bar.com"; - const char kToken[] = "token"; - EXPECT_TRUE(fake_push_client_->email().empty()); - EXPECT_TRUE(fake_push_client_->token().empty()); - push_client_channel_.UpdateCredentials(kEmail, kToken); - EXPECT_EQ(kEmail, fake_push_client_->email()); - EXPECT_EQ(kToken, fake_push_client_->token()); -} - -// Call SendMessage on the channel. It should propagate it to the -// push client. -TEST_F(PushClientChannelTest, SendMessage) { - EXPECT_TRUE(fake_push_client_->sent_notifications().empty()); - push_client_channel_.SendMessage(kMessage); - const notifier::Notification expected_notification = - PushClientChannel::EncodeMessageForTest( - kMessage, - push_client_channel_.GetServiceContextForTest(), - push_client_channel_.GetSchedulingHashForTest()); - ASSERT_EQ(1u, fake_push_client_->sent_notifications().size()); - EXPECT_TRUE( - fake_push_client_->sent_notifications()[0].Equals( - expected_notification)); -} - -// Simulate push client state changes on the push client. It should -// propagate to the channel. -TEST_F(PushClientChannelTest, OnPushClientStateChange) { - EXPECT_FALSE(connected_); - fake_push_client_->EnableNotifications(); - EXPECT_TRUE(connected_); - fake_push_client_->DisableNotifications( - notifier::TRANSIENT_NOTIFICATION_ERROR); - EXPECT_FALSE(connected_); - fake_push_client_->EnableNotifications(); - EXPECT_TRUE(connected_); - fake_push_client_->DisableNotifications( - notifier::NOTIFICATION_CREDENTIALS_REJECTED); - EXPECT_FALSE(connected_); -} - -// Simulate an incoming notification. It should be decoded properly -// by the channel. -TEST_F(PushClientChannelTest, OnIncomingNotification) { - const notifier::Notification notification = - PushClientChannel::EncodeMessageForTest( - kMessage, kServiceContext, kSchedulingHash); - - fake_push_client_->SimulateIncomingNotification(notification); - EXPECT_EQ(kServiceContext, - push_client_channel_.GetServiceContextForTest()); - EXPECT_EQ(kSchedulingHash, - push_client_channel_.GetSchedulingHashForTest()); - EXPECT_EQ(kMessage, last_message_); -} - -// Simulate an incoming notification with no receiver. It should be -// dropped by the channel. -TEST_F(PushClientChannelTest, OnIncomingNotificationNoReceiver) { - const notifier::Notification notification = - PushClientChannel::EncodeMessageForTest( - kMessage, kServiceContext, kSchedulingHash); - - push_client_channel_.SetMessageReceiver(NULL); - fake_push_client_->SimulateIncomingNotification(notification); - EXPECT_TRUE(push_client_channel_.GetServiceContextForTest().empty()); - EXPECT_EQ(static_cast(0), - push_client_channel_.GetSchedulingHashForTest()); - EXPECT_TRUE(last_message_.empty()); -} - -// Simulate an incoming garbage notification. It should be dropped by -// the channel. -TEST_F(PushClientChannelTest, OnIncomingNotificationGarbage) { - notifier::Notification notification; - notification.data = "garbage"; - - fake_push_client_->SimulateIncomingNotification(notification); - EXPECT_TRUE(push_client_channel_.GetServiceContextForTest().empty()); - EXPECT_EQ(static_cast(0), - push_client_channel_.GetSchedulingHashForTest()); - EXPECT_TRUE(last_message_.empty()); -} - -// Send a message, simulate an incoming message with context, and then -// send the same message again. The first sent message should not -// have any context, but the second sent message should have the -// context from the incoming emssage. -TEST_F(PushClientChannelTest, PersistedMessageState) { - push_client_channel_.SendMessage(kMessage); - ASSERT_EQ(1u, fake_push_client_->sent_notifications().size()); - { - std::string message; - std::string service_context; - int64 scheduling_hash = 0LL; - EXPECT_TRUE(PushClientChannel::DecodeMessageForTest( - fake_push_client_->sent_notifications()[0], - &message, &service_context, &scheduling_hash)); - EXPECT_EQ(kMessage, message); - EXPECT_TRUE(service_context.empty()); - EXPECT_EQ(0LL, scheduling_hash); - } - - const notifier::Notification notification = - PushClientChannel::EncodeMessageForTest( - kMessage, kServiceContext, kSchedulingHash); - fake_push_client_->SimulateIncomingNotification(notification); - - push_client_channel_.SendMessage(kMessage); - ASSERT_EQ(2u, fake_push_client_->sent_notifications().size()); - { - std::string message; - std::string service_context; - int64 scheduling_hash = 0LL; - EXPECT_TRUE(PushClientChannel::DecodeMessageForTest( - fake_push_client_->sent_notifications()[1], - &message, &service_context, &scheduling_hash)); - EXPECT_EQ(kMessage, message); - EXPECT_EQ(kServiceContext, service_context); - EXPECT_EQ(kSchedulingHash, scheduling_hash); - } -} - -} // namespace -} // namespace syncer +// Copyright (c) 2012 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 "sync/notifier/push_client_channel.h" + +#include +#include + +#include "base/compiler_specific.h" +#include "jingle/notifier/listener/fake_push_client.h" +#include "jingle/notifier/listener/notification_defines.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace syncer { +namespace { + +class PushClientChannelTest + : public ::testing::Test, + public SyncNetworkChannel::Observer { + protected: + PushClientChannelTest() + : fake_push_client_(new notifier::FakePushClient()), + push_client_channel_( + scoped_ptr(fake_push_client_)), + last_invalidator_state_(DEFAULT_INVALIDATION_ERROR) { + push_client_channel_.AddObserver(this); + push_client_channel_.SetMessageReceiver( + invalidation::NewPermanentCallback( + this, &PushClientChannelTest::OnIncomingMessage)); + push_client_channel_.SetSystemResources(NULL); + } + + virtual ~PushClientChannelTest() { + push_client_channel_.RemoveObserver(this); + } + + virtual void OnNetworkChannelStateChanged( + InvalidatorState invalidator_state) OVERRIDE { + last_invalidator_state_ = invalidator_state; + } + + void OnIncomingMessage(std::string incoming_message) { + last_message_ = incoming_message; + } + + notifier::FakePushClient* fake_push_client_; + PushClientChannel push_client_channel_; + std::string last_message_; + InvalidatorState last_invalidator_state_; +}; + +const char kMessage[] = "message"; +const char kServiceContext[] = "service context"; +const int64 kSchedulingHash = 100; + +// Make sure the channel subscribes to the correct notifications +// channel on construction. +TEST_F(PushClientChannelTest, Subscriptions) { + notifier::Subscription expected_subscription; + expected_subscription.channel = "tango_raw"; + EXPECT_TRUE(notifier::SubscriptionListsEqual( + fake_push_client_->subscriptions(), + notifier::SubscriptionList(1, expected_subscription))); +} + +// Call UpdateCredentials on the channel. It should propagate it to +// the push client. +TEST_F(PushClientChannelTest, UpdateCredentials) { + const char kEmail[] = "foo@bar.com"; + const char kToken[] = "token"; + EXPECT_TRUE(fake_push_client_->email().empty()); + EXPECT_TRUE(fake_push_client_->token().empty()); + push_client_channel_.UpdateCredentials(kEmail, kToken); + EXPECT_EQ(kEmail, fake_push_client_->email()); + EXPECT_EQ(kToken, fake_push_client_->token()); +} + +// Simulate push client state changes on the push client. It should +// propagate to the channel. +TEST_F(PushClientChannelTest, OnPushClientStateChange) { + EXPECT_EQ(DEFAULT_INVALIDATION_ERROR, last_invalidator_state_); + fake_push_client_->EnableNotifications(); + EXPECT_EQ(INVALIDATIONS_ENABLED, last_invalidator_state_); + fake_push_client_->DisableNotifications( + notifier::TRANSIENT_NOTIFICATION_ERROR); + EXPECT_EQ(TRANSIENT_INVALIDATION_ERROR, last_invalidator_state_); + fake_push_client_->DisableNotifications( + notifier::NOTIFICATION_CREDENTIALS_REJECTED); + EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, last_invalidator_state_); +} + +// Call SendMessage on the channel. It should propagate it to the +// push client. +TEST_F(PushClientChannelTest, SendMessage) { + EXPECT_TRUE(fake_push_client_->sent_notifications().empty()); + push_client_channel_.SendMessage(kMessage); + ASSERT_EQ(1u, fake_push_client_->sent_notifications().size()); +} + +// Simulate an incoming notification. It should be decoded properly +// by the channel. +TEST_F(PushClientChannelTest, OnIncomingNotification) { + notifier::Notification notification; + notification.data = + PushClientChannel::EncodeMessageForTest( + kMessage, kServiceContext, kSchedulingHash); + + fake_push_client_->SimulateIncomingNotification(notification); + EXPECT_EQ(kServiceContext, + push_client_channel_.GetServiceContextForTest()); + EXPECT_EQ(kSchedulingHash, + push_client_channel_.GetSchedulingHashForTest()); + EXPECT_EQ(kMessage, last_message_); +} + +} // namespace +} // namespace syncer diff --git a/sync/notifier/sync_invalidation_listener.cc b/sync/notifier/sync_invalidation_listener.cc index f95513111d42..9adb897bd1b5 100644 --- a/sync/notifier/sync_invalidation_listener.cc +++ b/sync/notifier/sync_invalidation_listener.cc @@ -31,19 +31,19 @@ SyncInvalidationListener::Delegate::~Delegate() {} SyncInvalidationListener::SyncInvalidationListener( scoped_ptr push_client) - : push_client_(push_client.get()), - sync_system_resources_(push_client.Pass(), this), + : push_client_channel_(push_client.Pass()), + sync_system_resources_(&push_client_channel_, this), delegate_(NULL), ticl_state_(DEFAULT_INVALIDATION_ERROR), push_client_state_(DEFAULT_INVALIDATION_ERROR), weak_ptr_factory_(this) { DCHECK(CalledOnValidThread()); - push_client_->AddObserver(this); + push_client_channel_.AddObserver(this); } SyncInvalidationListener::~SyncInvalidationListener() { DCHECK(CalledOnValidThread()); - push_client_->RemoveObserver(this); + push_client_channel_.RemoveObserver(this); Stop(); DCHECK(!delegate_); } @@ -94,7 +94,7 @@ void SyncInvalidationListener::Start( void SyncInvalidationListener::UpdateCredentials( const std::string& email, const std::string& token) { DCHECK(CalledOnValidThread()); - sync_system_resources_.network()->UpdateCredentials(email, token); + push_client_channel_.UpdateCredentials(email, token); } void SyncInvalidationListener::UpdateRegisteredIds(const ObjectIdSet& ids) { @@ -410,23 +410,11 @@ WeakHandle SyncInvalidationListener::GetThisAsAckHandler() { return WeakHandle(weak_ptr_factory_.GetWeakPtr()); } -void SyncInvalidationListener::OnNotificationsEnabled() { +void SyncInvalidationListener::OnNetworkChannelStateChanged( + InvalidatorState invalidator_state) { DCHECK(CalledOnValidThread()); - push_client_state_ = INVALIDATIONS_ENABLED; + push_client_state_ = invalidator_state; EmitStateChange(); } -void SyncInvalidationListener::OnNotificationsDisabled( - notifier::NotificationsDisabledReason reason) { - DCHECK(CalledOnValidThread()); - push_client_state_ = FromNotifierReason(reason); - EmitStateChange(); -} - -void SyncInvalidationListener::OnIncomingNotification( - const notifier::Notification& notification) { - DCHECK(CalledOnValidThread()); - // Do nothing, since this is already handled by |invalidation_client_|. -} - } // namespace syncer diff --git a/sync/notifier/sync_invalidation_listener.h b/sync/notifier/sync_invalidation_listener.h index a43e57bbbc94..2b4632d1da7c 100644 --- a/sync/notifier/sync_invalidation_listener.h +++ b/sync/notifier/sync_invalidation_listener.h @@ -17,12 +17,12 @@ #include "base/memory/weak_ptr.h" #include "base/threading/non_thread_safe.h" #include "google/cacheinvalidation/include/invalidation-listener.h" -#include "jingle/notifier/listener/push_client_observer.h" #include "sync/base/sync_export.h" #include "sync/internal_api/public/util/weak_handle.h" #include "sync/notifier/ack_handler.h" #include "sync/notifier/invalidation_state_tracker.h" #include "sync/notifier/invalidator_state.h" +#include "sync/notifier/push_client_channel.h" #include "sync/notifier/state_writer.h" #include "sync/notifier/sync_system_resources.h" #include "sync/notifier/unacked_invalidation_set.h" @@ -45,7 +45,7 @@ class RegistrationManager; class SYNC_EXPORT_PRIVATE SyncInvalidationListener : public NON_EXPORTED_BASE(invalidation::InvalidationListener), public StateWriter, - public NON_EXPORTED_BASE(notifier::PushClientObserver), + public SyncNetworkChannel::Observer, public AckHandler, public base::NonThreadSafe { public: @@ -131,12 +131,9 @@ class SYNC_EXPORT_PRIVATE SyncInvalidationListener // StateWriter implementation. virtual void WriteState(const std::string& state) OVERRIDE; - // notifier::PushClientObserver implementation. - virtual void OnNotificationsEnabled() OVERRIDE; - virtual void OnNotificationsDisabled( - notifier::NotificationsDisabledReason reason) OVERRIDE; - virtual void OnIncomingNotification( - const notifier::Notification& notification) OVERRIDE; + // SyncNetworkChannel::Observer implementation. + virtual void OnNetworkChannelStateChanged( + InvalidatorState invalidator_state) OVERRIDE; void DoRegistrationUpdate(); @@ -170,8 +167,7 @@ class SYNC_EXPORT_PRIVATE SyncInvalidationListener WeakHandle GetThisAsAckHandler(); - // Owned by |sync_system_resources_|. - notifier::PushClient* const push_client_; + PushClientChannel push_client_channel_; SyncSystemResources sync_system_resources_; UnackedInvalidationsMap unacked_invalidations_map_; WeakHandle invalidation_state_tracker_; diff --git a/sync/notifier/sync_system_resources.cc b/sync/notifier/sync_system_resources.cc index 74dacaa63861..99e3ee5ea5de 100644 --- a/sync/notifier/sync_system_resources.cc +++ b/sync/notifier/sync_system_resources.cc @@ -14,9 +14,9 @@ #include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "google/cacheinvalidation/client_gateway.pb.h" #include "google/cacheinvalidation/deps/callback.h" #include "google/cacheinvalidation/include/types.h" -#include "jingle/notifier/listener/push_client.h" #include "sync/notifier/invalidation_util.h" namespace syncer { @@ -128,6 +128,134 @@ void SyncInvalidationScheduler::RunPostedTask(invalidation::Closure* task) { delete task; } +SyncNetworkChannel::SyncNetworkChannel() + : invalidator_state_(DEFAULT_INVALIDATION_ERROR), + scheduling_hash_(0) { +} + +SyncNetworkChannel::~SyncNetworkChannel() { + STLDeleteElements(&network_status_receivers_); +} + +void SyncNetworkChannel::SendMessage(const std::string& outgoing_message) { + std::string encoded_message; + EncodeMessage(&encoded_message, outgoing_message, service_context_, + scheduling_hash_); + SendEncodedMessage(encoded_message); +} + +void SyncNetworkChannel::SetMessageReceiver( + invalidation::MessageCallback* incoming_receiver) { + incoming_receiver_.reset(incoming_receiver); +} + +void SyncNetworkChannel::AddNetworkStatusReceiver( + invalidation::NetworkStatusCallback* network_status_receiver) { + network_status_receiver->Run(invalidator_state_ == INVALIDATIONS_ENABLED); + network_status_receivers_.push_back(network_status_receiver); +} + +void SyncNetworkChannel::SetSystemResources( + invalidation::SystemResources* resources) { + // Do nothing. +} + +void SyncNetworkChannel::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void SyncNetworkChannel::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +const std::string& SyncNetworkChannel::GetServiceContextForTest() const { + return service_context_; +} + +int64 SyncNetworkChannel::GetSchedulingHashForTest() const { + return scheduling_hash_; +} + +std::string SyncNetworkChannel::EncodeMessageForTest( + const std::string& message, const std::string& service_context, + int64 scheduling_hash) { + std::string encoded_message; + EncodeMessage(&encoded_message, message, service_context, scheduling_hash); + return encoded_message; +} + +bool SyncNetworkChannel::DecodeMessageForTest( + const std::string& data, + std::string* message, + std::string* service_context, + int64* scheduling_hash) { + return DecodeMessage(data, message, service_context, scheduling_hash); +} + +void SyncNetworkChannel::NotifyStateChange(InvalidatorState invalidator_state) { + // Remember state for future NetworkStatusReceivers. + invalidator_state_ = invalidator_state; + // Notify NetworkStatusReceivers in cacheinvalidation. + for (NetworkStatusReceiverList::const_iterator it = + network_status_receivers_.begin(); + it != network_status_receivers_.end(); ++it) { + (*it)->Run(invalidator_state_ == INVALIDATIONS_ENABLED); + } + // Notify observers. + FOR_EACH_OBSERVER(Observer, observers_, + OnNetworkChannelStateChanged(invalidator_state_)); +} + +void SyncNetworkChannel::DeliverIncomingMessage(const std::string& data) { + if (!incoming_receiver_) { + DLOG(ERROR) << "No receiver for incoming notification"; + return; + } + std::string message; + if (!DecodeMessage(data, + &message, &service_context_, &scheduling_hash_)) { + DLOG(ERROR) << "Could not parse ClientGatewayMessage"; + return; + } + incoming_receiver_->Run(message); +} + +void SyncNetworkChannel::EncodeMessage( + std::string* encoded_message, + const std::string& message, + const std::string& service_context, + int64 scheduling_hash) { + ipc::invalidation::ClientGatewayMessage envelope; + envelope.set_is_client_to_server(true); + if (!service_context.empty()) { + envelope.set_service_context(service_context); + envelope.set_rpc_scheduling_hash(scheduling_hash); + } + envelope.set_network_message(message); + envelope.SerializeToString(encoded_message); +} + + +bool SyncNetworkChannel::DecodeMessage( + const std::string& data, + std::string* message, + std::string* service_context, + int64* scheduling_hash) { + ipc::invalidation::ClientGatewayMessage envelope; + if (!envelope.ParseFromString(data)) { + return false; + } + *message = envelope.network_message(); + if (envelope.has_service_context()) { + *service_context = envelope.service_context(); + } + if (envelope.has_rpc_scheduling_hash()) { + *scheduling_hash = envelope.rpc_scheduling_hash(); + } + return true; +} + + SyncStorage::SyncStorage(StateWriter* state_writer, invalidation::Scheduler* scheduler) : state_writer_(state_writer), @@ -195,14 +323,14 @@ void SyncStorage::RunAndDeleteReadKeyCallback( } SyncSystemResources::SyncSystemResources( - scoped_ptr push_client, + SyncNetworkChannel* sync_network_channel, StateWriter* state_writer) : is_started_(false), logger_(new SyncLogger()), internal_scheduler_(new SyncInvalidationScheduler()), listener_scheduler_(new SyncInvalidationScheduler()), storage_(new SyncStorage(state_writer, internal_scheduler_.get())), - push_client_channel_(push_client.Pass()) { + sync_network_channel_(sync_network_channel) { } SyncSystemResources::~SyncSystemResources() { @@ -240,8 +368,8 @@ SyncStorage* SyncSystemResources::storage() { return storage_.get(); } -PushClientChannel* SyncSystemResources::network() { - return &push_client_channel_; +SyncNetworkChannel* SyncSystemResources::network() { + return sync_network_channel_; } SyncInvalidationScheduler* SyncSystemResources::internal_scheduler() { diff --git a/sync/notifier/sync_system_resources.h b/sync/notifier/sync_system_resources.h index b14d352bd1f1..3ddc7087c944 100644 --- a/sync/notifier/sync_system_resources.h +++ b/sync/notifier/sync_system_resources.h @@ -20,13 +20,9 @@ #include "base/threading/non_thread_safe.h" #include "google/cacheinvalidation/include/system-resources.h" #include "sync/base/sync_export.h" -#include "sync/notifier/push_client_channel.h" +#include "sync/notifier/invalidator_state.h" #include "sync/notifier/state_writer.h" -namespace notifier { -class PushClient; -} // namespace notifier - namespace syncer { class SyncLogger : public invalidation::Logger { @@ -78,6 +74,99 @@ class SyncInvalidationScheduler : public invalidation::Scheduler { base::WeakPtrFactory weak_factory_; }; +// SyncNetworkChannel implements common tasks needed to interact with +// invalidation library: +// - registering message and network status callbacks +// - Encoding/Decoding message to ClientGatewayMessage +// - notifying observers about network channel state change +// Implementation of particular network protocol should implement +// SendEncodedMessage and call NotifyStateChange and DeliverIncomingMessage. +class SYNC_EXPORT_PRIVATE SyncNetworkChannel + : public NON_EXPORTED_BASE(invalidation::NetworkChannel) { + public: + class Observer { + public: + // Called when network channel state changes. Possible states are: + // - INVALIDATIONS_ENABLED : connection is established and working + // - TRANSIENT_INVALIDATION_ERROR : no network, connection lost, etc. + // - INVALIDATION_CREDENTIALS_REJECTED : Issues with auth token + virtual void OnNetworkChannelStateChanged( + InvalidatorState invalidator_state) = 0; + }; + + SyncNetworkChannel(); + + virtual ~SyncNetworkChannel(); + + // invalidation::NetworkChannel implementation. + virtual void SendMessage(const std::string& outgoing_message) OVERRIDE; + virtual void SetMessageReceiver( + invalidation::MessageCallback* incoming_receiver) OVERRIDE; + virtual void AddNetworkStatusReceiver( + invalidation::NetworkStatusCallback* network_status_receiver) OVERRIDE; + virtual void SetSystemResources( + invalidation::SystemResources* resources) OVERRIDE; + + // Subclass should implement SendEncodedMessage to send encoded message to + // Tango over network. + virtual void SendEncodedMessage(const std::string& encoded_message) = 0; + + // Classes interested in network channel state changes should implement + // SyncNetworkChannel::Observer and register here. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + const std::string& GetServiceContextForTest() const; + + int64 GetSchedulingHashForTest() const; + + static std::string EncodeMessageForTest( + const std::string& message, + const std::string& service_context, + int64 scheduling_hash); + + static bool DecodeMessageForTest( + const std::string& notification, + std::string* message, + std::string* service_context, + int64* scheduling_hash); + + protected: + // Subclass should notify about connection state through NotifyStateChange. + void NotifyStateChange(InvalidatorState invalidator_state); + // Subclass should call DeliverIncomingMessage for message to reach + // invalidations library. + void DeliverIncomingMessage(const std::string& message); + + private: + typedef std::vector + NetworkStatusReceiverList; + + static void EncodeMessage( + std::string* encoded_message, + const std::string& message, + const std::string& service_context, + int64 scheduling_hash); + + static bool DecodeMessage( + const std::string& data, + std::string* message, + std::string* service_context, + int64* scheduling_hash); + + // Callbacks into invalidation library + scoped_ptr incoming_receiver_; + NetworkStatusReceiverList network_status_receivers_; + + // Last channel state for new network status receivers. + InvalidatorState invalidator_state_; + + ObserverList observers_; + + std::string service_context_; + int64 scheduling_hash_; +}; + class SyncStorage : public invalidation::Storage { public: SyncStorage(StateWriter* state_writer, invalidation::Scheduler* scheduler); @@ -121,7 +210,7 @@ class SyncStorage : public invalidation::Storage { class SYNC_EXPORT_PRIVATE SyncSystemResources : public NON_EXPORTED_BASE(invalidation::SystemResources) { public: - SyncSystemResources(scoped_ptr push_client, + SyncSystemResources(SyncNetworkChannel* sync_network_channel, StateWriter* state_writer); virtual ~SyncSystemResources(); @@ -134,7 +223,7 @@ class SYNC_EXPORT_PRIVATE SyncSystemResources virtual std::string platform() const OVERRIDE; virtual SyncLogger* logger() OVERRIDE; virtual SyncStorage* storage() OVERRIDE; - virtual PushClientChannel* network() OVERRIDE; + virtual SyncNetworkChannel* network() OVERRIDE; virtual SyncInvalidationScheduler* internal_scheduler() OVERRIDE; virtual SyncInvalidationScheduler* listener_scheduler() OVERRIDE; @@ -145,7 +234,8 @@ class SYNC_EXPORT_PRIVATE SyncSystemResources scoped_ptr internal_scheduler_; scoped_ptr listener_scheduler_; scoped_ptr storage_; - PushClientChannel push_client_channel_; + // sync_network_channel_ is owned by SyncInvalidationListener. + SyncNetworkChannel* sync_network_channel_; }; } // namespace syncer diff --git a/sync/notifier/sync_system_resources_unittest.cc b/sync/notifier/sync_system_resources_unittest.cc index e8ee38c5c3e9..f63e90621a0d 100644 --- a/sync/notifier/sync_system_resources_unittest.cc +++ b/sync/notifier/sync_system_resources_unittest.cc @@ -13,6 +13,7 @@ #include "google/cacheinvalidation/include/types.h" #include "jingle/notifier/listener/fake_push_client.h" +#include "sync/notifier/push_client_channel.h" #include "sync/notifier/state_writer.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -49,9 +50,9 @@ class MockStorageCallback { class SyncSystemResourcesTest : public testing::Test { protected: SyncSystemResourcesTest() - : sync_system_resources_( - scoped_ptr(new notifier::FakePushClient()), - &mock_state_writer_) {} + : push_client_channel_( + scoped_ptr(new notifier::FakePushClient())), + sync_system_resources_(&push_client_channel_, &mock_state_writer_) {} virtual ~SyncSystemResourcesTest() {} @@ -85,6 +86,7 @@ class SyncSystemResourcesTest : public testing::Test { // Needed by |sync_system_resources_|. base::MessageLoop message_loop_; MockStateWriter mock_state_writer_; + PushClientChannel push_client_channel_; SyncSystemResources sync_system_resources_; private: @@ -174,5 +176,228 @@ TEST_F(SyncSystemResourcesTest, WriteState) { results); } +class TestSyncNetworkChannel : public SyncNetworkChannel { + public: + TestSyncNetworkChannel() {} + virtual ~TestSyncNetworkChannel() {} + + using SyncNetworkChannel::NotifyStateChange; + using SyncNetworkChannel::DeliverIncomingMessage; + + virtual void SendEncodedMessage(const std::string& encoded_message) OVERRIDE { + last_encoded_message_ = encoded_message; + } + + std::string last_encoded_message_; +}; + +class SyncNetworkChannelTest + : public testing::Test, + public SyncNetworkChannel::Observer { + protected: + SyncNetworkChannelTest() + : last_invalidator_state_(DEFAULT_INVALIDATION_ERROR), + connected_(false) { + network_channel_.AddObserver(this); + network_channel_.SetMessageReceiver( + invalidation::NewPermanentCallback( + this, &SyncNetworkChannelTest::OnIncomingMessage)); + network_channel_.AddNetworkStatusReceiver( + invalidation::NewPermanentCallback( + this, &SyncNetworkChannelTest::OnNetworkStatusChange)); + } + + virtual ~SyncNetworkChannelTest() { + network_channel_.RemoveObserver(this); + } + + virtual void OnNetworkChannelStateChanged( + InvalidatorState invalidator_state) OVERRIDE { + last_invalidator_state_ = invalidator_state; + } + + void OnIncomingMessage(std::string incoming_message) { + last_message_ = incoming_message; + } + + void OnNetworkStatusChange(bool connected) { + connected_ = connected; + } + + TestSyncNetworkChannel network_channel_; + InvalidatorState last_invalidator_state_; + std::string last_message_; + bool connected_; +}; + +const char kMessage[] = "message"; +const char kServiceContext[] = "service context"; +const int64 kSchedulingHash = 100; + +// Encode a message with some context and then decode it. The decoded info +// should match the original info. +TEST_F(SyncNetworkChannelTest, EncodeDecode) { + const std::string& data = + SyncNetworkChannel::EncodeMessageForTest( + kMessage, kServiceContext, kSchedulingHash); + std::string message; + std::string service_context; + int64 scheduling_hash = 0LL; + EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest( + data, &message, &service_context, &scheduling_hash)); + EXPECT_EQ(kMessage, message); + EXPECT_EQ(kServiceContext, service_context); + EXPECT_EQ(kSchedulingHash, scheduling_hash); +} + +// Encode a message with no context and then decode it. The decoded message +// should match the original message, but the context and hash should be +// untouched. +TEST_F(SyncNetworkChannelTest, EncodeDecodeNoContext) { + const std::string& data = + SyncNetworkChannel::EncodeMessageForTest( + kMessage, std::string(), kSchedulingHash); + std::string message; + std::string service_context = kServiceContext; + int64 scheduling_hash = kSchedulingHash + 1; + EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest( + data, &message, &service_context, &scheduling_hash)); + EXPECT_EQ(kMessage, message); + EXPECT_EQ(kServiceContext, service_context); + EXPECT_EQ(kSchedulingHash + 1, scheduling_hash); +} + +// Decode an empty notification. It should result in an empty message +// but should leave the context and hash untouched. +TEST_F(SyncNetworkChannelTest, DecodeEmpty) { + std::string message = kMessage; + std::string service_context = kServiceContext; + int64 scheduling_hash = kSchedulingHash; + EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest( + std::string(), &message, &service_context, &scheduling_hash)); + EXPECT_TRUE(message.empty()); + EXPECT_EQ(kServiceContext, service_context); + EXPECT_EQ(kSchedulingHash, scheduling_hash); +} + +// Try to decode a garbage notification. It should leave all its +// arguments untouched and return false. +TEST_F(SyncNetworkChannelTest, DecodeGarbage) { + std::string data = "garbage"; + std::string message = kMessage; + std::string service_context = kServiceContext; + int64 scheduling_hash = kSchedulingHash; + EXPECT_FALSE(SyncNetworkChannel::DecodeMessageForTest( + data, &message, &service_context, &scheduling_hash)); + EXPECT_EQ(kMessage, message); + EXPECT_EQ(kServiceContext, service_context); + EXPECT_EQ(kSchedulingHash, scheduling_hash); +} + +// Simulate network channel state change. It should propagate to observer. +TEST_F(SyncNetworkChannelTest, OnNetworkChannelStateChanged) { + EXPECT_EQ(DEFAULT_INVALIDATION_ERROR, last_invalidator_state_); + EXPECT_FALSE(connected_); + network_channel_.NotifyStateChange(INVALIDATIONS_ENABLED); + EXPECT_EQ(INVALIDATIONS_ENABLED, last_invalidator_state_); + EXPECT_TRUE(connected_); + network_channel_.NotifyStateChange(INVALIDATION_CREDENTIALS_REJECTED); + EXPECT_EQ(INVALIDATION_CREDENTIALS_REJECTED, last_invalidator_state_); + EXPECT_FALSE(connected_); +} + +// Call SendMessage on the channel. SendEncodedMessage should be called for it. +TEST_F(SyncNetworkChannelTest, SendMessage) { + network_channel_.SendMessage(kMessage); + std::string expected_encoded_message = + SyncNetworkChannel::EncodeMessageForTest( + kMessage, + network_channel_.GetServiceContextForTest(), + network_channel_.GetSchedulingHashForTest()); + ASSERT_EQ(expected_encoded_message, network_channel_.last_encoded_message_); +} + +// Simulate an incoming notification. It should be decoded properly +// by the channel. +TEST_F(SyncNetworkChannelTest, OnIncomingMessage) { + const std::string message = + SyncNetworkChannel::EncodeMessageForTest( + kMessage, kServiceContext, kSchedulingHash); + + network_channel_.DeliverIncomingMessage(message); + EXPECT_EQ(kServiceContext, + network_channel_.GetServiceContextForTest()); + EXPECT_EQ(kSchedulingHash, + network_channel_.GetSchedulingHashForTest()); + EXPECT_EQ(kMessage, last_message_); +} + +// Simulate an incoming notification with no receiver. It should be dropped by +// the channel. +TEST_F(SyncNetworkChannelTest, OnIncomingMessageNoReceiver) { + const std::string message = + SyncNetworkChannel::EncodeMessageForTest( + kMessage, kServiceContext, kSchedulingHash); + + network_channel_.SetMessageReceiver(NULL); + network_channel_.DeliverIncomingMessage(message); + EXPECT_TRUE(network_channel_.GetServiceContextForTest().empty()); + EXPECT_EQ(static_cast(0), + network_channel_.GetSchedulingHashForTest()); + EXPECT_TRUE(last_message_.empty()); +} + +// Simulate an incoming garbage notification. It should be dropped by +// the channel. +TEST_F(SyncNetworkChannelTest, OnIncomingMessageGarbage) { + std::string message = "garbage"; + + network_channel_.DeliverIncomingMessage(message); + EXPECT_TRUE(network_channel_.GetServiceContextForTest().empty()); + EXPECT_EQ(static_cast(0), + network_channel_.GetSchedulingHashForTest()); + EXPECT_TRUE(last_message_.empty()); +} + +// Send a message, simulate an incoming message with context, and then +// send the same message again. The first sent message should not +// have any context, but the second sent message should have the +// context from the incoming emssage. +TEST_F(SyncNetworkChannelTest, PersistedMessageState) { + network_channel_.SendMessage(kMessage); + ASSERT_FALSE(network_channel_.last_encoded_message_.empty()); + { + std::string message; + std::string service_context; + int64 scheduling_hash = 0LL; + EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest( + network_channel_.last_encoded_message_, + &message, &service_context, &scheduling_hash)); + EXPECT_EQ(kMessage, message); + EXPECT_TRUE(service_context.empty()); + EXPECT_EQ(0LL, scheduling_hash); + } + + const std::string& encoded_message = + SyncNetworkChannel::EncodeMessageForTest( + kMessage, kServiceContext, kSchedulingHash); + network_channel_.DeliverIncomingMessage(encoded_message); + + network_channel_.last_encoded_message_.clear(); + network_channel_.SendMessage(kMessage); + ASSERT_FALSE(network_channel_.last_encoded_message_.empty()); + { + std::string message; + std::string service_context; + int64 scheduling_hash = 0LL; + EXPECT_TRUE(SyncNetworkChannel::DecodeMessageForTest( + network_channel_.last_encoded_message_, + &message, &service_context, &scheduling_hash)); + EXPECT_EQ(kMessage, message); + EXPECT_EQ(kServiceContext, service_context); + EXPECT_EQ(kSchedulingHash, scheduling_hash); + } +} + } // namespace } // namespace syncer -- 2.11.4.GIT