summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-31 23:39:25 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-31 23:39:25 +0000
commit33596da5267a8a3e2e6cb0d44bbc8660f615b878 (patch)
treeee9e5b9c4ea8bc6f8d0592f9f784a6a67c447f48
parent939532d0da8b6e19f3424c9a8a6cac9fc1dc5e12 (diff)
downloadchromium_src-33596da5267a8a3e2e6cb0d44bbc8660f615b878.zip
chromium_src-33596da5267a8a3e2e6cb0d44bbc8660f615b878.tar.gz
chromium_src-33596da5267a8a3e2e6cb0d44bbc8660f615b878.tar.bz2
[Sync] Rework Invalidator-related unit tests
Introduce invalidator_test_template.h, which contains tests that should be used for each Invalidator implementation. Make all Invalidator implementations, and also InvalidatorRegistrar, instantiate that test template. Move most InvalidatorRegistrar tests and some of the other Invalidator implementation tests to the template. Make P2PInvalidator support arbitrary object IDs. Also make SendInvalidation take an ObjectIdStateMap. Simplify BridgedInvalidator a bit; it no longer requires a call to UpdateEnabledTypes (it just uses all registered types from its registrar). Rework tests for BridgedInvalidator/ChromeSyncNotifierBridge to not require functions in ChromeSyncNotifierBridge to be marked virtual. Add conversions to/from Values for InvalidationState, ObjectId, and ObjectIdStateMap. BUG=141678 Review URL: https://chromiumcodereview.appspot.com/10874096 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@154538 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/sync/glue/bridged_invalidator.cc4
-rw-r--r--chrome/browser/sync/glue/bridged_invalidator.h2
-rw-r--r--chrome/browser/sync/glue/bridged_invalidator_unittest.cc183
-rw-r--r--chrome/browser/sync/glue/chrome_sync_notification_bridge.cc79
-rw-r--r--chrome/browser/sync/glue/chrome_sync_notification_bridge.h16
-rw-r--r--chrome/browser/sync/glue/chrome_sync_notification_bridge_unittest.cc206
-rw-r--r--chrome/browser/sync/glue/sync_backend_host.cc1
-rw-r--r--chrome/browser/sync/test/integration/sync_test.cc9
-rw-r--r--sync/internal_api/public/base/invalidation_state.cc42
-rw-r--r--sync/internal_api/public/base/invalidation_state.h20
-rw-r--r--sync/internal_api/public/base/model_type_state_map.h6
-rw-r--r--sync/internal_api/sync_manager_impl.cc6
-rw-r--r--sync/notifier/fake_invalidator.cc33
-rw-r--r--sync/notifier/fake_invalidator.h11
-rw-r--r--sync/notifier/fake_invalidator_unittest.cc70
-rw-r--r--sync/notifier/invalidation_notifier.cc3
-rw-r--r--sync/notifier/invalidation_notifier.h2
-rw-r--r--sync/notifier/invalidation_notifier_unittest.cc143
-rw-r--r--sync/notifier/invalidation_util.cc42
-rw-r--r--sync/notifier/invalidation_util.h16
-rw-r--r--sync/notifier/invalidator.h3
-rw-r--r--sync/notifier/invalidator_registrar.cc26
-rw-r--r--sync/notifier/invalidator_registrar.h3
-rw-r--r--sync/notifier/invalidator_registrar_unittest.cc294
-rw-r--r--sync/notifier/invalidator_test_template.h404
-rw-r--r--sync/notifier/non_blocking_invalidator.cc3
-rw-r--r--sync/notifier/non_blocking_invalidator.h2
-rw-r--r--sync/notifier/non_blocking_invalidator_unittest.cc118
-rw-r--r--sync/notifier/notifications_disabled_reason.cc15
-rw-r--r--sync/notifier/notifications_disabled_reason.h3
-rw-r--r--sync/notifier/object_id_state_map.cc61
-rw-r--r--sync/notifier/object_id_state_map.h14
-rw-r--r--sync/notifier/p2p_invalidator.cc103
-rw-r--r--sync/notifier/p2p_invalidator.h19
-rw-r--r--sync/notifier/p2p_invalidator_unittest.cc210
-rw-r--r--sync/sync.gyp9
36 files changed, 1428 insertions, 753 deletions
diff --git a/chrome/browser/sync/glue/bridged_invalidator.cc b/chrome/browser/sync/glue/bridged_invalidator.cc
index 14ecfa8..c85c70b 100644
--- a/chrome/browser/sync/glue/bridged_invalidator.cc
+++ b/chrome/browser/sync/glue/bridged_invalidator.cc
@@ -57,9 +57,9 @@ void BridgedInvalidator::UpdateCredentials(
}
void BridgedInvalidator::SendNotification(
- syncer::ModelTypeSet changed_types) {
+ const syncer::ObjectIdStateMap& id_state_map) {
if (delegate_.get())
- delegate_->SendNotification(changed_types);
+ delegate_->SendNotification(id_state_map);
}
} // namespace browser_sync
diff --git a/chrome/browser/sync/glue/bridged_invalidator.h b/chrome/browser/sync/glue/bridged_invalidator.h
index 73b1c0c..018e876 100644
--- a/chrome/browser/sync/glue/bridged_invalidator.h
+++ b/chrome/browser/sync/glue/bridged_invalidator.h
@@ -39,7 +39,7 @@ class BridgedInvalidator : public syncer::Invalidator {
virtual void UpdateCredentials(
const std::string& email, const std::string& token) OVERRIDE;
virtual void SendNotification(
- syncer::ModelTypeSet changed_types) OVERRIDE;
+ const syncer::ObjectIdStateMap& id_state_map) OVERRIDE;
private:
// The notification bridge that we register the observers with.
diff --git a/chrome/browser/sync/glue/bridged_invalidator_unittest.cc b/chrome/browser/sync/glue/bridged_invalidator_unittest.cc
index a472de4..139f360 100644
--- a/chrome/browser/sync/glue/bridged_invalidator_unittest.cc
+++ b/chrome/browser/sync/glue/bridged_invalidator_unittest.cc
@@ -7,111 +7,184 @@
#include <string>
#include "base/compiler_specific.h"
-#include "base/message_loop.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "chrome/browser/sync/glue/chrome_sync_notification_bridge.h"
#include "chrome/test/base/profile_mock.h"
#include "content/public/test/test_browser_thread.h"
+#include "google/cacheinvalidation/include/types.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/base/model_type_test_util.h"
#include "sync/notifier/fake_invalidation_handler.h"
#include "sync/notifier/fake_invalidator.h"
-#include "sync/notifier/invalidator.h"
+#include "sync/notifier/invalidator_test_template.h"
+#include "sync/notifier/object_id_state_map_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace browser_sync {
-namespace {
+namespace syncer {
+class InvalidationStateTracker;
+} // namespace syncer
-using ::testing::NiceMock;
-using ::testing::StrictMock;
-using content::BrowserThread;
-using syncer::HasModelTypes;
+namespace browser_sync {
-class MockChromeSyncNotificationBridge : public ChromeSyncNotificationBridge {
+// BridgedInvalidatorTestDelegate has to be visible from the syncer
+// namespace (where InvalidatorTest lives).
+class BridgedInvalidatorTestDelegate {
public:
- MockChromeSyncNotificationBridge(
- const Profile* profile,
- const scoped_refptr<base::SequencedTaskRunner>& sync_task_runner)
- : ChromeSyncNotificationBridge(profile, sync_task_runner) {}
- virtual ~MockChromeSyncNotificationBridge() {}
-
- MOCK_METHOD1(RegisterHandler, void(syncer::InvalidationHandler*));
- MOCK_METHOD2(UpdateRegisteredIds,
- void(syncer::InvalidationHandler*,
- const syncer::ObjectIdSet&));
- MOCK_METHOD1(UnregisterHandler, void(syncer::InvalidationHandler*));
+ BridgedInvalidatorTestDelegate()
+ : ui_thread_(content::BrowserThread::UI, &ui_loop_),
+ bridge_(&mock_profile_, ui_loop_.message_loop_proxy()),
+ fake_delegate_(NULL) {
+ // Pump |ui_loop_| to fully initialize |bridge_|.
+ ui_loop_.RunAllPending();
+ }
+
+ ~BridgedInvalidatorTestDelegate() {
+ DestroyInvalidator();
+ }
+
+ void CreateInvalidator(
+ const std::string& /* initial_state (unused) */,
+ const base::WeakPtr<syncer::InvalidationStateTracker>&
+ /* invalidation_state_tracker (unused) */) {
+ DCHECK(!fake_delegate_);
+ DCHECK(!invalidator_.get());
+ fake_delegate_ = new syncer::FakeInvalidator();
+ invalidator_.reset(new BridgedInvalidator(&bridge_, fake_delegate_));
+ }
+
+ BridgedInvalidator* GetInvalidator() {
+ return invalidator_.get();
+ }
+
+ ChromeSyncNotificationBridge* GetBridge() {
+ return &bridge_;
+ }
+
+ syncer::FakeInvalidator* GetFakeDelegate() {
+ return fake_delegate_;
+ }
+
+ void DestroyInvalidator() {
+ invalidator_.reset();
+ fake_delegate_ = NULL;
+ bridge_.StopForShutdown();
+ ui_loop_.RunAllPending();
+ }
+
+ void WaitForInvalidator() {
+ // Do nothing.
+ }
+
+ void TriggerOnNotificationsEnabled() {
+ fake_delegate_->EmitOnNotificationsEnabled();
+ }
+
+ void TriggerOnIncomingNotification(
+ const syncer::ObjectIdStateMap& id_state_map,
+ syncer::IncomingNotificationSource source) {
+ fake_delegate_->EmitOnIncomingNotification(id_state_map, source);
+ }
+
+ void TriggerOnNotificationsDisabled(
+ syncer::NotificationsDisabledReason reason) {
+ fake_delegate_->EmitOnNotificationsDisabled(reason);
+ }
+
+ static bool InvalidatorHandlesDeprecatedState() {
+ return false;
+ }
+
+ private:
+ MessageLoop ui_loop_;
+ content::TestBrowserThread ui_thread_;
+ ::testing::NiceMock<ProfileMock> mock_profile_;
+ ChromeSyncNotificationBridge bridge_;
+ // Owned by |invalidator_|.
+ syncer::FakeInvalidator* fake_delegate_;
+ scoped_ptr<BridgedInvalidator> invalidator_;
};
+namespace {
+
// All tests just verify that each call is passed through to the delegate, with
// the exception of RegisterHandler, UnregisterHandler, and
// UpdateRegisteredIds, which also verifies the call is forwarded to the
// bridge.
class BridgedInvalidatorTest : public testing::Test {
public:
- BridgedInvalidatorTest()
- : ui_thread_(BrowserThread::UI, &ui_loop_),
- mock_bridge_(&mock_profile_, ui_loop_.message_loop_proxy()),
- // Owned by bridged_invalidator_.
- fake_delegate_(new syncer::FakeInvalidator()),
- bridged_invalidator_(&mock_bridge_, fake_delegate_) {}
+ BridgedInvalidatorTest() {
+ delegate_.CreateInvalidator(
+ "fake_state", base::WeakPtr<syncer::InvalidationStateTracker>());
+ }
+
virtual ~BridgedInvalidatorTest() {}
protected:
- MessageLoop ui_loop_;
- content::TestBrowserThread ui_thread_;
- NiceMock<ProfileMock> mock_profile_;
- StrictMock<MockChromeSyncNotificationBridge> mock_bridge_;
- syncer::FakeInvalidator* fake_delegate_;
- BridgedInvalidator bridged_invalidator_;
+ BridgedInvalidatorTestDelegate delegate_;
};
TEST_F(BridgedInvalidatorTest, RegisterHandler) {
- const syncer::ObjectIdSet& ids =
- syncer::ModelTypeSetToObjectIdSet(
- syncer::ModelTypeSet(syncer::APPS, syncer::PREFERENCES));
+ syncer::ObjectIdSet ids;
+ ids.insert(invalidation::ObjectId(1, "id1"));
syncer::FakeInvalidationHandler handler;
- EXPECT_CALL(mock_bridge_, RegisterHandler(&handler));
- EXPECT_CALL(mock_bridge_, UpdateRegisteredIds(&handler, ids));
- EXPECT_CALL(mock_bridge_, UnregisterHandler(&handler));
- bridged_invalidator_.RegisterHandler(&handler);
- EXPECT_TRUE(fake_delegate_->IsHandlerRegistered(&handler));
+ delegate_.GetInvalidator()->RegisterHandler(&handler);
+ EXPECT_TRUE(delegate_.GetFakeDelegate()->IsHandlerRegistered(&handler));
+ EXPECT_TRUE(delegate_.GetBridge()->IsHandlerRegisteredForTest(&handler));
- bridged_invalidator_.UpdateRegisteredIds(&handler, ids);
- EXPECT_EQ(ids, fake_delegate_->GetRegisteredIds(&handler));
+ delegate_.GetInvalidator()->UpdateRegisteredIds(&handler, ids);
+ EXPECT_EQ(ids, delegate_.GetFakeDelegate()->GetRegisteredIds(&handler));
+ EXPECT_EQ(ids, delegate_.GetBridge()->GetRegisteredIdsForTest(&handler));
- bridged_invalidator_.UnregisterHandler(&handler);
- EXPECT_FALSE(fake_delegate_->IsHandlerRegistered(&handler));
+ delegate_.GetInvalidator()->UnregisterHandler(&handler);
+ EXPECT_FALSE(delegate_.GetFakeDelegate()->IsHandlerRegistered(&handler));
+ EXPECT_FALSE(delegate_.GetBridge()->IsHandlerRegisteredForTest(&handler));
}
TEST_F(BridgedInvalidatorTest, SetUniqueId) {
const std::string& unique_id = "unique id";
- bridged_invalidator_.SetUniqueId(unique_id);
- EXPECT_EQ(unique_id, fake_delegate_->GetUniqueId());
+ delegate_.GetInvalidator()->SetUniqueId(unique_id);
+ EXPECT_EQ(unique_id, delegate_.GetFakeDelegate()->GetUniqueId());
}
TEST_F(BridgedInvalidatorTest, SetStateDeprecated) {
const std::string& state = "state";
- bridged_invalidator_.SetStateDeprecated(state);
- EXPECT_EQ(state, fake_delegate_->GetStateDeprecated());
+ delegate_.GetInvalidator()->SetStateDeprecated(state);
+ EXPECT_EQ(state, delegate_.GetFakeDelegate()->GetStateDeprecated());
}
TEST_F(BridgedInvalidatorTest, UpdateCredentials) {
const std::string& email = "email";
const std::string& token = "token";
- bridged_invalidator_.UpdateCredentials(email, token);
- EXPECT_EQ(email, fake_delegate_->GetCredentialsEmail());
- EXPECT_EQ(token, fake_delegate_->GetCredentialsToken());
+ delegate_.GetInvalidator()->UpdateCredentials(email, token);
+ EXPECT_EQ(email, delegate_.GetFakeDelegate()->GetCredentialsEmail());
+ EXPECT_EQ(token, delegate_.GetFakeDelegate()->GetCredentialsToken());
}
TEST_F(BridgedInvalidatorTest, SendNotification) {
- const syncer::ModelTypeSet changed_types(
- syncer::SESSIONS, syncer::EXTENSIONS);
- bridged_invalidator_.SendNotification(changed_types);
- EXPECT_TRUE(fake_delegate_->GetLastChangedTypes().Equals(changed_types));
+ syncer::ObjectIdSet ids;
+ ids.insert(invalidation::ObjectId(1, "id1"));
+ ids.insert(invalidation::ObjectId(2, "id2"));
+ const syncer::ObjectIdStateMap& id_state_map =
+ syncer::ObjectIdSetToStateMap(ids, "payload");
+ delegate_.GetInvalidator()->SendNotification(id_state_map);
+ EXPECT_THAT(id_state_map,
+ Eq(delegate_.GetFakeDelegate()->GetLastSentIdStateMap()));
}
} // namespace
} // namespace browser_sync
+
+namespace syncer {
+namespace {
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+ BridgedInvalidatorTest, InvalidatorTest,
+ ::browser_sync::BridgedInvalidatorTestDelegate);
+
+} // namespace
+} // namespace syncer
diff --git a/chrome/browser/sync/glue/chrome_sync_notification_bridge.cc b/chrome/browser/sync/glue/chrome_sync_notification_bridge.cc
index 6d9b7de..371c9c1 100644
--- a/chrome/browser/sync/glue/chrome_sync_notification_bridge.cc
+++ b/chrome/browser/sync/glue/chrome_sync_notification_bridge.cc
@@ -11,6 +11,7 @@
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
+#include "sync/internal_api/public/base/model_type.h"
#include "sync/notifier/invalidation_handler.h"
#include "sync/notifier/invalidator_registrar.h"
@@ -30,16 +31,19 @@ class ChromeSyncNotificationBridge::Core
void InitializeOnSyncThread();
void CleanupOnSyncThread();
- void UpdateEnabledTypes(syncer::ModelTypeSet enabled_types);
void RegisterHandler(syncer::InvalidationHandler* handler);
void UpdateRegisteredIds(syncer::InvalidationHandler* handler,
const syncer::ObjectIdSet& ids);
void UnregisterHandler(syncer::InvalidationHandler* handler);
void EmitNotification(
- const syncer::ModelTypeStateMap& state_map,
+ const syncer::ObjectIdStateMap& state_map,
syncer::IncomingNotificationSource notification_source);
+ bool IsHandlerRegisteredForTest(syncer::InvalidationHandler* handler) const;
+ syncer::ObjectIdSet GetRegisteredIdsForTest(
+ syncer::InvalidationHandler* handler) const;
+
private:
friend class base::RefCountedThreadSafe<Core>;
@@ -49,8 +53,7 @@ class ChromeSyncNotificationBridge::Core
const scoped_refptr<base::SequencedTaskRunner> sync_task_runner_;
// Used only on |sync_task_runner_|.
- syncer::ModelTypeSet enabled_types_;
- scoped_ptr<syncer::InvalidatorRegistrar> notifier_registrar_;
+ scoped_ptr<syncer::InvalidatorRegistrar> invalidator_registrar_;
};
ChromeSyncNotificationBridge::Core::Core(
@@ -63,54 +66,61 @@ ChromeSyncNotificationBridge::Core::Core(
ChromeSyncNotificationBridge::Core::~Core() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
sync_task_runner_->RunsTasksOnCurrentThread());
- DCHECK(!notifier_registrar_.get());
+ DCHECK(!invalidator_registrar_.get());
}
void ChromeSyncNotificationBridge::Core::InitializeOnSyncThread() {
- notifier_registrar_.reset(new syncer::InvalidatorRegistrar());
+ invalidator_registrar_.reset(new syncer::InvalidatorRegistrar());
}
void ChromeSyncNotificationBridge::Core::CleanupOnSyncThread() {
- notifier_registrar_.reset();
-}
-
-void ChromeSyncNotificationBridge::Core::UpdateEnabledTypes(
- syncer::ModelTypeSet types) {
- DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- enabled_types_ = types;
+ invalidator_registrar_.reset();
}
void ChromeSyncNotificationBridge::Core::RegisterHandler(
syncer::InvalidationHandler* handler) {
DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- notifier_registrar_->RegisterHandler(handler);
+ invalidator_registrar_->RegisterHandler(handler);
}
void ChromeSyncNotificationBridge::Core::UpdateRegisteredIds(
syncer::InvalidationHandler* handler,
const syncer::ObjectIdSet& ids) {
DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- notifier_registrar_->UpdateRegisteredIds(handler, ids);
+ invalidator_registrar_->UpdateRegisteredIds(handler, ids);
}
void ChromeSyncNotificationBridge::Core::UnregisterHandler(
syncer::InvalidationHandler* handler) {
DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- notifier_registrar_->UnregisterHandler(handler);
+ invalidator_registrar_->UnregisterHandler(handler);
}
void ChromeSyncNotificationBridge::Core::EmitNotification(
- const syncer::ModelTypeStateMap& state_map,
+ const syncer::ObjectIdStateMap& state_map,
syncer::IncomingNotificationSource notification_source) {
DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- const syncer::ModelTypeStateMap& effective_state_map =
+ const syncer::ObjectIdStateMap& effective_state_map =
state_map.empty() ?
- syncer::ModelTypeSetToStateMap(enabled_types_, std::string()) :
+ ObjectIdSetToStateMap(
+ invalidator_registrar_->GetAllRegisteredIds(), std::string()) :
state_map;
- notifier_registrar_->DispatchInvalidationsToHandlers(
- ModelTypeStateMapToObjectIdStateMap(effective_state_map),
- notification_source);
+ invalidator_registrar_->DispatchInvalidationsToHandlers(
+ effective_state_map, notification_source);
+}
+
+bool ChromeSyncNotificationBridge::Core::IsHandlerRegisteredForTest(
+ syncer::InvalidationHandler* handler) const {
+ DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
+ return invalidator_registrar_->IsHandlerRegisteredForTest(handler);
+}
+
+syncer::ObjectIdSet
+ChromeSyncNotificationBridge::Core::GetRegisteredIdsForTest(
+ syncer::InvalidationHandler* handler) const {
+ DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
+ return invalidator_registrar_->GetRegisteredIds(handler);
}
ChromeSyncNotificationBridge::ChromeSyncNotificationBridge(
@@ -140,12 +150,6 @@ void ChromeSyncNotificationBridge::StopForShutdown() {
}
}
-void ChromeSyncNotificationBridge::UpdateEnabledTypes(
- syncer::ModelTypeSet types) {
- DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- core_->UpdateEnabledTypes(types);
-}
-
void ChromeSyncNotificationBridge::RegisterHandler(
syncer::InvalidationHandler* handler) {
DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
@@ -165,6 +169,18 @@ void ChromeSyncNotificationBridge::UnregisterHandler(
core_->UnregisterHandler(handler);
}
+bool ChromeSyncNotificationBridge::IsHandlerRegisteredForTest(
+ syncer::InvalidationHandler* handler) const {
+ DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
+ return core_->IsHandlerRegisteredForTest(handler);
+}
+
+syncer::ObjectIdSet ChromeSyncNotificationBridge::GetRegisteredIdsForTest(
+ syncer::InvalidationHandler* handler) const {
+ DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
+ return core_->GetRegisteredIdsForTest(handler);
+}
+
void ChromeSyncNotificationBridge::Observe(
int type,
const content::NotificationSource& source,
@@ -181,13 +197,18 @@ void ChromeSyncNotificationBridge::Observe(
return;
}
+ // TODO(akalin): Use ObjectIdStateMap here instead. We'll have to
+ // make sure all emitters of the relevant notifications also use
+ // ObjectIdStateMap.
content::Details<const syncer::ModelTypeStateMap>
state_details(details);
const syncer::ModelTypeStateMap& state_map = *(state_details.ptr());
if (!sync_task_runner_->PostTask(
FROM_HERE,
base::Bind(&Core::EmitNotification,
- core_, state_map, notification_source))) {
+ core_,
+ ModelTypeStateMapToObjectIdStateMap(state_map),
+ notification_source))) {
NOTREACHED();
}
}
diff --git a/chrome/browser/sync/glue/chrome_sync_notification_bridge.h b/chrome/browser/sync/glue/chrome_sync_notification_bridge.h
index 5d85bec..788303e 100644
--- a/chrome/browser/sync/glue/chrome_sync_notification_bridge.h
+++ b/chrome/browser/sync/glue/chrome_sync_notification_bridge.h
@@ -10,7 +10,6 @@
#include "base/sequenced_task_runner.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-#include "sync/internal_api/public/base/model_type.h"
#include "sync/notifier/invalidation_util.h"
class Profile;
@@ -42,12 +41,15 @@ class ChromeSyncNotificationBridge : public content::NotificationObserver {
void StopForShutdown();
// Must be called on the sync task runner.
- void UpdateEnabledTypes(syncer::ModelTypeSet enabled_types);
- // Marked virtual for tests.
- virtual void RegisterHandler(syncer::InvalidationHandler* handler);
- virtual void UpdateRegisteredIds(syncer::InvalidationHandler* handler,
- const syncer::ObjectIdSet& ids);
- virtual void UnregisterHandler(syncer::InvalidationHandler* handler);
+ void RegisterHandler(syncer::InvalidationHandler* handler);
+ void UpdateRegisteredIds(syncer::InvalidationHandler* handler,
+ const syncer::ObjectIdSet& ids);
+ void UnregisterHandler(syncer::InvalidationHandler* handler);
+
+ bool IsHandlerRegisteredForTest(
+ syncer::InvalidationHandler* handler) const;
+ syncer::ObjectIdSet GetRegisteredIdsForTest(
+ syncer::InvalidationHandler* handler) const;
// NotificationObserver implementation. Called on UI thread.
virtual void Observe(int type,
diff --git a/chrome/browser/sync/glue/chrome_sync_notification_bridge_unittest.cc b/chrome/browser/sync/glue/chrome_sync_notification_bridge_unittest.cc
index 1769b7e..f9250bf 100644
--- a/chrome/browser/sync/glue/chrome_sync_notification_bridge_unittest.cc
+++ b/chrome/browser/sync/glue/chrome_sync_notification_bridge_unittest.cc
@@ -6,14 +6,15 @@
#include <cstddef>
+#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/run_loop.h"
#include "base/sequenced_task_runner.h"
-#include "base/synchronization/waitable_event.h"
-#include "base/test/test_timeouts.h"
#include "base/threading/thread.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/test/base/profile_mock.h"
@@ -22,7 +23,7 @@
#include "content/public/test/test_browser_thread.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/base/model_type_state_map.h"
-#include "sync/notifier/invalidation_handler.h"
+#include "sync/notifier/fake_invalidation_handler.h"
#include "sync/notifier/object_id_state_map_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,88 +31,21 @@
namespace browser_sync {
namespace {
-using ::testing::Mock;
using ::testing::NiceMock;
-using ::testing::StrictMock;
-using content::BrowserThread;
-// Receives a ChromeSyncNotificationBridge to register to, and an expected
-// ModelTypeStateMap. ReceivedProperNotification() will return true only
-// if the observer has received a notification with the proper source and
-// state.
-// Note: Because this object lives on the sync thread, we use a fake
-// (vs a mock) so we don't have to worry about possible thread safety
-// issues within GTest/GMock.
-class FakeInvalidationHandler : public syncer::InvalidationHandler {
- public:
- FakeInvalidationHandler(
- const scoped_refptr<base::SequencedTaskRunner>& sync_task_runner,
- ChromeSyncNotificationBridge* bridge,
- const syncer::ObjectIdStateMap& expected_states,
- syncer::IncomingNotificationSource expected_source)
- : sync_task_runner_(sync_task_runner),
- bridge_(bridge),
- received_improper_notification_(false),
- notification_count_(0),
- expected_states_(expected_states),
- expected_source_(expected_source) {
- DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- bridge_->RegisterHandler(this);
- const syncer::ObjectIdSet& ids =
- syncer::ObjectIdStateMapToSet(expected_states);
- bridge_->UpdateRegisteredIds(this, ids);
- }
-
- virtual ~FakeInvalidationHandler() {
- DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- bridge_->UnregisterHandler(this);
- }
-
- // InvalidationHandler implementation.
- virtual void OnIncomingNotification(
- const syncer::ObjectIdStateMap& id_state_map,
- syncer::IncomingNotificationSource source) OVERRIDE {
- DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- notification_count_++;
- if (source != expected_source_) {
- LOG(ERROR) << "Received notification with wrong source";
- received_improper_notification_ = true;
- }
- if (!::testing::Matches(Eq(expected_states_))(id_state_map)) {
- LOG(ERROR) << "Received wrong state";
- received_improper_notification_ = true;
- }
- }
- virtual void OnNotificationsEnabled() OVERRIDE {
- NOTREACHED();
- }
- virtual void OnNotificationsDisabled(
- syncer::NotificationsDisabledReason reason) OVERRIDE {
- NOTREACHED();
- }
-
- bool ReceivedProperNotification() const {
- DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
- return (notification_count_ == 1) && !received_improper_notification_;
- }
+// Needed by BlockForSyncThread().
+void DoNothing() {}
- private:
- const scoped_refptr<base::SequencedTaskRunner> sync_task_runner_;
- ChromeSyncNotificationBridge* const bridge_;
- bool received_improper_notification_;
- size_t notification_count_;
- const syncer::ObjectIdStateMap expected_states_;
- const syncer::IncomingNotificationSource expected_source_;
-};
+// Since all the interesting stuff happens on the sync thread, we have
+// to be careful to use GTest/GMock only on the main thread since they
+// are not thread-safe.
class ChromeSyncNotificationBridgeTest : public testing::Test {
public:
ChromeSyncNotificationBridgeTest()
- : ui_thread_(BrowserThread::UI),
+ : ui_thread_(content::BrowserThread::UI, &ui_loop_),
sync_thread_("Sync thread"),
- sync_handler_(NULL),
- sync_handler_notification_failure_(false),
- done_(true, false) {}
+ sync_handler_notification_success_(false) {}
virtual ~ChromeSyncNotificationBridgeTest() {}
@@ -128,41 +62,39 @@ class ChromeSyncNotificationBridgeTest : public testing::Test {
sync_thread_.Stop();
// Must be reset only after the sync thread is stopped.
bridge_.reset();
- EXPECT_EQ(NULL, sync_handler_);
- if (sync_handler_notification_failure_)
- ADD_FAILURE() << "Sync Observer did not receive proper notification.";
+ EXPECT_EQ(NULL, sync_handler_.get());
+ if (!sync_handler_notification_success_)
+ ADD_FAILURE() << "Sync handler did not receive proper notification.";
}
- void VerifyAndDestroyObserver() {
+ void VerifyAndDestroyObserver(
+ const syncer::ModelTypeStateMap& expected_states,
+ syncer::IncomingNotificationSource expected_source) {
ASSERT_TRUE(sync_thread_.message_loop_proxy()->PostTask(
FROM_HERE,
base::Bind(&ChromeSyncNotificationBridgeTest::
VerifyAndDestroyObserverOnSyncThread,
- base::Unretained(this))));
+ base::Unretained(this),
+ expected_states,
+ expected_source)));
BlockForSyncThread();
}
- void CreateObserverWithExpectations(
- const syncer::ModelTypeStateMap& expected_states,
- syncer::IncomingNotificationSource expected_source) {
- const syncer::ObjectIdStateMap& expected_id_state_map =
- syncer::ModelTypeStateMapToObjectIdStateMap(expected_states);
+ void CreateObserver() {
ASSERT_TRUE(sync_thread_.message_loop_proxy()->PostTask(
FROM_HERE,
base::Bind(
&ChromeSyncNotificationBridgeTest::CreateObserverOnSyncThread,
- base::Unretained(this),
- expected_id_state_map,
- expected_source)));
+ base::Unretained(this))));
BlockForSyncThread();
}
- void UpdateBridgeEnabledTypes(syncer::ModelTypeSet enabled_types) {
+ void UpdateEnabledTypes(syncer::ModelTypeSet enabled_types) {
ASSERT_TRUE(sync_thread_.message_loop_proxy()->PostTask(
FROM_HERE,
base::Bind(
&ChromeSyncNotificationBridgeTest::
- UpdateBridgeEnabledTypesOnSyncThread,
+ UpdateEnabledTypesOnSyncThread,
base::Unretained(this),
enabled_types)));
BlockForSyncThread();
@@ -175,62 +107,60 @@ class ChromeSyncNotificationBridgeTest : public testing::Test {
type,
content::Source<Profile>(&mock_profile_),
content::Details<const syncer::ModelTypeStateMap>(&state_map));
+ BlockForSyncThread();
}
private:
- void VerifyAndDestroyObserverOnSyncThread() {
+ void VerifyAndDestroyObserverOnSyncThread(
+ const syncer::ModelTypeStateMap& expected_states,
+ syncer::IncomingNotificationSource expected_source) {
DCHECK(sync_thread_.message_loop_proxy()->RunsTasksOnCurrentThread());
- if (!sync_handler_) {
- sync_handler_notification_failure_ = true;
+ if (sync_handler_.get()) {
+ sync_handler_notification_success_ =
+ (sync_handler_->GetNotificationCount() == 1) &&
+ ObjectIdStateMapEquals(
+ sync_handler_->GetLastNotificationIdStateMap(),
+ syncer::ModelTypeStateMapToObjectIdStateMap(expected_states)) &&
+ (sync_handler_->GetLastNotificationSource() == expected_source);
+ bridge_->UnregisterHandler(sync_handler_.get());
} else {
- sync_handler_notification_failure_ =
- !sync_handler_->ReceivedProperNotification();
- delete sync_handler_;
- sync_handler_ = NULL;
+ sync_handler_notification_success_ = false;
}
+ sync_handler_.reset();
}
- void CreateObserverOnSyncThread(
- const syncer::ObjectIdStateMap& expected_states,
- syncer::IncomingNotificationSource expected_source) {
+ void CreateObserverOnSyncThread() {
DCHECK(sync_thread_.message_loop_proxy()->RunsTasksOnCurrentThread());
- sync_handler_ = new FakeInvalidationHandler(
- sync_thread_.message_loop_proxy(),
- bridge_.get(),
- expected_states,
- expected_source);
+ sync_handler_.reset(new syncer::FakeInvalidationHandler());
+ bridge_->RegisterHandler(sync_handler_.get());
}
- void UpdateBridgeEnabledTypesOnSyncThread(
+ void UpdateEnabledTypesOnSyncThread(
syncer::ModelTypeSet enabled_types) {
DCHECK(sync_thread_.message_loop_proxy()->RunsTasksOnCurrentThread());
- bridge_->UpdateEnabledTypes(enabled_types);
- }
-
- void SignalOnSyncThread() {
- DCHECK(sync_thread_.message_loop_proxy()->RunsTasksOnCurrentThread());
- done_.Signal();
+ bridge_->UpdateRegisteredIds(
+ sync_handler_.get(), ModelTypeSetToObjectIdSet(enabled_types));
}
void BlockForSyncThread() {
- done_.Reset();
- ASSERT_TRUE(sync_thread_.message_loop_proxy()->PostTask(
+ // Post a task to the sync thread's message loop and block until
+ // it runs.
+ base::RunLoop run_loop;
+ ASSERT_TRUE(sync_thread_.message_loop_proxy()->PostTaskAndReply(
FROM_HERE,
- base::Bind(&ChromeSyncNotificationBridgeTest::SignalOnSyncThread,
- base::Unretained(this))));
- done_.TimedWait(TestTimeouts::action_timeout());
- if (!done_.IsSignaled())
- ADD_FAILURE() << "Timed out waiting for sync thread.";
+ base::Bind(&DoNothing),
+ run_loop.QuitClosure()));
+ run_loop.Run();
}
+ MessageLoop ui_loop_;
content::TestBrowserThread ui_thread_;
base::Thread sync_thread_;
NiceMock<ProfileMock> mock_profile_;
// Created/used/destroyed on sync thread.
- FakeInvalidationHandler* sync_handler_;
- bool sync_handler_notification_failure_;
+ scoped_ptr<syncer::FakeInvalidationHandler> sync_handler_;
+ bool sync_handler_notification_success_;
scoped_ptr<ChromeSyncNotificationBridge> bridge_;
- base::WaitableEvent done_;
};
// Adds an observer on the sync thread, triggers a local refresh
@@ -240,10 +170,11 @@ TEST_F(ChromeSyncNotificationBridgeTest, LocalNotification) {
syncer::ModelTypeStateMap state_map;
state_map.insert(
std::make_pair(syncer::SESSIONS, syncer::InvalidationState()));
- CreateObserverWithExpectations(state_map, syncer::LOCAL_NOTIFICATION);
+ CreateObserver();
+ UpdateEnabledTypes(syncer::ModelTypeSet(syncer::SESSIONS));
TriggerRefreshNotification(chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
state_map);
- VerifyAndDestroyObserver();
+ VerifyAndDestroyObserver(state_map, syncer::LOCAL_NOTIFICATION);
}
// Adds an observer on the sync thread, triggers a remote refresh
@@ -253,10 +184,11 @@ TEST_F(ChromeSyncNotificationBridgeTest, RemoteNotification) {
syncer::ModelTypeStateMap state_map;
state_map.insert(
std::make_pair(syncer::SESSIONS, syncer::InvalidationState()));
- CreateObserverWithExpectations(state_map, syncer::REMOTE_NOTIFICATION);
+ CreateObserver();
+ UpdateEnabledTypes(syncer::ModelTypeSet(syncer::SESSIONS));
TriggerRefreshNotification(chrome::NOTIFICATION_SYNC_REFRESH_REMOTE,
state_map);
- VerifyAndDestroyObserver();
+ VerifyAndDestroyObserver(state_map, syncer::REMOTE_NOTIFICATION);
}
// Adds an observer on the sync thread, triggers a local refresh
@@ -267,12 +199,12 @@ TEST_F(ChromeSyncNotificationBridgeTest, LocalNotificationEmptyPayloadMap) {
syncer::BOOKMARKS, syncer::PASSWORDS);
const syncer::ModelTypeStateMap enabled_types_state_map =
syncer::ModelTypeSetToStateMap(enabled_types, std::string());
- CreateObserverWithExpectations(
- enabled_types_state_map, syncer::LOCAL_NOTIFICATION);
- UpdateBridgeEnabledTypes(enabled_types);
+ CreateObserver();
+ UpdateEnabledTypes(enabled_types);
TriggerRefreshNotification(chrome::NOTIFICATION_SYNC_REFRESH_LOCAL,
syncer::ModelTypeStateMap());
- VerifyAndDestroyObserver();
+ VerifyAndDestroyObserver(
+ enabled_types_state_map, syncer::LOCAL_NOTIFICATION);
}
// Adds an observer on the sync thread, triggers a remote refresh
@@ -283,12 +215,12 @@ TEST_F(ChromeSyncNotificationBridgeTest, RemoteNotificationEmptyPayloadMap) {
syncer::BOOKMARKS, syncer::TYPED_URLS);
const syncer::ModelTypeStateMap enabled_types_state_map =
syncer::ModelTypeSetToStateMap(enabled_types, std::string());
- CreateObserverWithExpectations(
- enabled_types_state_map, syncer::REMOTE_NOTIFICATION);
- UpdateBridgeEnabledTypes(enabled_types);
+ CreateObserver();
+ UpdateEnabledTypes(enabled_types);
TriggerRefreshNotification(chrome::NOTIFICATION_SYNC_REFRESH_REMOTE,
syncer::ModelTypeStateMap());
- VerifyAndDestroyObserver();
+ VerifyAndDestroyObserver(
+ enabled_types_state_map, syncer::REMOTE_NOTIFICATION);
}
} // namespace
diff --git a/chrome/browser/sync/glue/sync_backend_host.cc b/chrome/browser/sync/glue/sync_backend_host.cc
index 7d1711d..b842272 100644
--- a/chrome/browser/sync/glue/sync_backend_host.cc
+++ b/chrome/browser/sync/glue/sync_backend_host.cc
@@ -1258,7 +1258,6 @@ void SyncBackendHost::Core::DoFinishConfigureDataTypes(
syncer::ModelSafeRoutingInfo routing_info;
registrar_->GetModelSafeRoutingInfo(&routing_info);
const syncer::ModelTypeSet enabled_types = GetRoutingInfoTypes(routing_info);
- chrome_sync_notification_bridge_->UpdateEnabledTypes(enabled_types);
sync_manager_->UpdateEnabledTypes(enabled_types);
const syncer::ModelTypeSet failed_configuration_types =
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 9fb7eb4..bc28f73 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -651,9 +651,12 @@ void SyncTest::EnableNotifications() {
void SyncTest::TriggerNotification(syncer::ModelTypeSet changed_types) {
ASSERT_TRUE(ServerSupportsNotificationControl());
const std::string& data =
- syncer::P2PNotificationData("from_server",
- syncer::NOTIFY_ALL,
- changed_types).ToString();
+ syncer::P2PNotificationData(
+ "from_server",
+ syncer::NOTIFY_ALL,
+ syncer::ObjectIdSetToStateMap(
+ syncer::ModelTypeSetToObjectIdSet(changed_types), ""),
+ syncer::REMOTE_NOTIFICATION).ToString();
const std::string& path =
std::string("chromiumsync/sendnotification?channel=") +
syncer::kSyncP2PNotificationChannel + "&data=" + data;
diff --git a/sync/internal_api/public/base/invalidation_state.cc b/sync/internal_api/public/base/invalidation_state.cc
new file mode 100644
index 0000000..6f71351
--- /dev/null
+++ b/sync/internal_api/public/base/invalidation_state.cc
@@ -0,0 +1,42 @@
+// 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/internal_api/public/base/invalidation_state.h"
+
+#include "base/values.h"
+
+namespace syncer {
+
+bool AckHandle::Equals(const AckHandle& other) const {
+ return true;
+}
+
+scoped_ptr<base::Value> AckHandle::ToValue() const {
+ return scoped_ptr<base::Value>(new DictionaryValue());
+}
+
+bool AckHandle::ResetFromValue(const base::Value& value) {
+ return true;
+}
+
+bool InvalidationState::Equals(const InvalidationState& other) const {
+ return (payload == other.payload) && ack_handle.Equals(other.ack_handle);
+}
+
+scoped_ptr<base::DictionaryValue> InvalidationState::ToValue() const {
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ value->SetString("payload", payload);
+ value->Set("ackHandle", ack_handle.ToValue().release());
+ return value.Pass();
+}
+
+bool InvalidationState::ResetFromValue(const base::DictionaryValue& value) {
+ const base::Value* ack_handle_value = NULL;
+ return
+ value.GetString("payload", &payload) &&
+ value.Get("ackHandle", &ack_handle_value) &&
+ ack_handle.ResetFromValue(*ack_handle_value);
+}
+
+} // namespace syncer
diff --git a/sync/internal_api/public/base/invalidation_state.h b/sync/internal_api/public/base/invalidation_state.h
index 8b79019..8c811af 100644
--- a/sync/internal_api/public/base/invalidation_state.h
+++ b/sync/internal_api/public/base/invalidation_state.h
@@ -7,17 +7,37 @@
#include <string>
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class DictionaryValue;
+class Value;
+} // namespace
+
namespace syncer {
// Opaque class that represents an ack handle.
// TODO(dcheng): This is just a refactoring change, so the class is empty for
// the moment. It will be filled once we start implementing 'reminders'.
class AckHandle {
+ public:
+ bool Equals(const AckHandle& other) const;
+
+ scoped_ptr<base::Value> ToValue() const;
+
+ bool ResetFromValue(const base::Value& value);
};
struct InvalidationState {
std::string payload;
AckHandle ack_handle;
+
+ bool Equals(const InvalidationState& other) const;
+
+ // Caller owns the returned DictionaryValue.
+ scoped_ptr<base::DictionaryValue> ToValue() const;
+
+ bool ResetFromValue(const base::DictionaryValue& value);
};
} // namespace syncer
diff --git a/sync/internal_api/public/base/model_type_state_map.h b/sync/internal_api/public/base/model_type_state_map.h
index 71b0e65..5a9f84d 100644
--- a/sync/internal_api/public/base/model_type_state_map.h
+++ b/sync/internal_api/public/base/model_type_state_map.h
@@ -35,14 +35,14 @@ SYNC_EXPORT ModelTypeStateMap ModelTypeSetToStateMap(
ModelTypeSet model_types, const std::string& payload);
ModelTypeSet ModelTypeStateMapToSet(
- const ModelTypeStateMap& payload_map);
+ const ModelTypeStateMap& type_state_map);
std::string ModelTypeStateMapToString(
- const ModelTypeStateMap& model_type_payloads);
+ const ModelTypeStateMap& type_state_map);
// Caller takes ownership of the returned dictionary.
base::DictionaryValue* ModelTypeStateMapToValue(
- const ModelTypeStateMap& model_type_payloads);
+ const ModelTypeStateMap& type_state_map);
// Coalesce |update| into |original|, overwriting only when |update| has
// a non-empty payload.
diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc
index a0fa57c..87e6e69 100644
--- a/sync/internal_api/sync_manager_impl.cc
+++ b/sync/internal_api/sync_manager_impl.cc
@@ -1009,9 +1009,9 @@ void SyncManagerImpl::OnSyncEngineEvent(const SyncEngineEvent& event) {
(event.snapshot.model_neutral_state().num_successful_commits > 0);
if (is_notifiable_commit) {
if (invalidator_.get()) {
- const ModelTypeSet changed_types =
- ModelTypeStateMapToSet(event.snapshot.source().types);
- invalidator_->SendNotification(changed_types);
+ const ObjectIdStateMap& id_state_map =
+ ModelTypeStateMapToObjectIdStateMap(event.snapshot.source().types);
+ invalidator_->SendNotification(id_state_map);
} else {
DVLOG(1) << "Not sending notification: invalidator_ is NULL";
}
diff --git a/sync/notifier/fake_invalidator.cc b/sync/notifier/fake_invalidator.cc
index 85696ad..7468dae 100644
--- a/sync/notifier/fake_invalidator.cc
+++ b/sync/notifier/fake_invalidator.cc
@@ -16,11 +16,7 @@ bool FakeInvalidator::IsHandlerRegistered(InvalidationHandler* handler) const {
ObjectIdSet FakeInvalidator::GetRegisteredIds(
InvalidationHandler* handler) const {
- return registrar_.GetRegisteredIdsForTest(handler);
-}
-
-void FakeInvalidator::RegisterHandler(InvalidationHandler* handler) {
- registrar_.RegisterHandler(handler);
+ return registrar_.GetRegisteredIds(handler);
}
const std::string& FakeInvalidator::GetUniqueId() const {
@@ -39,8 +35,27 @@ const std::string& FakeInvalidator::GetCredentialsToken() const {
return token_;
}
-ModelTypeSet FakeInvalidator::GetLastChangedTypes() const {
- return last_changed_types_;
+const ObjectIdStateMap& FakeInvalidator::GetLastSentIdStateMap() const {
+ return last_sent_id_state_map_;
+}
+
+void FakeInvalidator::EmitOnNotificationsEnabled() {
+ registrar_.EmitOnNotificationsEnabled();
+}
+
+void FakeInvalidator::EmitOnIncomingNotification(
+ const ObjectIdStateMap& id_state_map,
+ IncomingNotificationSource source) {
+ registrar_.DispatchInvalidationsToHandlers(id_state_map, source);
+}
+
+void FakeInvalidator::EmitOnNotificationsDisabled(
+ NotificationsDisabledReason reason) {
+ registrar_.EmitOnNotificationsDisabled(reason);
+}
+
+void FakeInvalidator::RegisterHandler(InvalidationHandler* handler) {
+ registrar_.RegisterHandler(handler);
}
void FakeInvalidator::UpdateRegisteredIds(InvalidationHandler* handler,
@@ -66,8 +81,8 @@ void FakeInvalidator::UpdateCredentials(
token_ = token;
}
-void FakeInvalidator::SendNotification(ModelTypeSet changed_types) {
- last_changed_types_ = changed_types;
+void FakeInvalidator::SendNotification(const ObjectIdStateMap& id_state_map) {
+ last_sent_id_state_map_ = id_state_map;
}
} // namespace syncer
diff --git a/sync/notifier/fake_invalidator.h b/sync/notifier/fake_invalidator.h
index 26c5ad8..07690dd 100644
--- a/sync/notifier/fake_invalidator.h
+++ b/sync/notifier/fake_invalidator.h
@@ -25,7 +25,12 @@ class FakeInvalidator : public Invalidator {
const std::string& GetStateDeprecated() const;
const std::string& GetCredentialsEmail() const;
const std::string& GetCredentialsToken() const;
- ModelTypeSet GetLastChangedTypes() const;
+ const ObjectIdStateMap& GetLastSentIdStateMap() const;
+
+ void EmitOnNotificationsEnabled();
+ void EmitOnIncomingNotification(const ObjectIdStateMap& id_state_map,
+ IncomingNotificationSource source);
+ void EmitOnNotificationsDisabled(NotificationsDisabledReason reason);
virtual void RegisterHandler(InvalidationHandler* handler) OVERRIDE;
virtual void UpdateRegisteredIds(InvalidationHandler* handler,
@@ -35,7 +40,7 @@ class FakeInvalidator : public Invalidator {
virtual void SetStateDeprecated(const std::string& state) OVERRIDE;
virtual void UpdateCredentials(
const std::string& email, const std::string& token) OVERRIDE;
- virtual void SendNotification(ModelTypeSet changed_types) OVERRIDE;
+ virtual void SendNotification(const ObjectIdStateMap& id_state_map) OVERRIDE;
private:
InvalidatorRegistrar registrar_;
@@ -43,7 +48,7 @@ class FakeInvalidator : public Invalidator {
std::string state_;
std::string email_;
std::string token_;
- ModelTypeSet last_changed_types_;
+ ObjectIdStateMap last_sent_id_state_map_;
};
} // namespace syncer
diff --git a/sync/notifier/fake_invalidator_unittest.cc b/sync/notifier/fake_invalidator_unittest.cc
new file mode 100644
index 0000000..05b3e0b
--- /dev/null
+++ b/sync/notifier/fake_invalidator_unittest.cc
@@ -0,0 +1,70 @@
+// 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 "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "sync/notifier/fake_invalidator.h"
+#include "sync/notifier/invalidator_test_template.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+namespace {
+
+class FakeInvalidatorTestDelegate {
+ public:
+ FakeInvalidatorTestDelegate() {}
+
+ ~FakeInvalidatorTestDelegate() {
+ DestroyInvalidator();
+ }
+
+ void CreateInvalidator(
+ const std::string& initial_state,
+ const base::WeakPtr<InvalidationStateTracker>&
+ invalidation_state_tracker) {
+ DCHECK(!invalidator_.get());
+ invalidator_.reset(new FakeInvalidator());
+ }
+
+ FakeInvalidator* GetInvalidator() {
+ return invalidator_.get();
+ }
+
+ void DestroyInvalidator() {
+ invalidator_.reset();
+ }
+
+ void WaitForInvalidator() {
+ // Do Nothing.
+ }
+
+ void TriggerOnNotificationsEnabled() {
+ invalidator_->EmitOnNotificationsEnabled();
+ }
+
+ void TriggerOnIncomingNotification(const ObjectIdStateMap& id_state_map,
+ IncomingNotificationSource source) {
+ invalidator_->EmitOnIncomingNotification(id_state_map, source);
+ }
+
+ void TriggerOnNotificationsDisabled(NotificationsDisabledReason reason) {
+ invalidator_->EmitOnNotificationsDisabled(reason);
+ }
+
+ static bool InvalidatorHandlesDeprecatedState() {
+ return false;
+ }
+
+ private:
+ scoped_ptr<FakeInvalidator> invalidator_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+ FakeInvalidatorTest, InvalidatorTest,
+ FakeInvalidatorTestDelegate);
+
+} // namespace
+
+} // namespace syncer
diff --git a/sync/notifier/invalidation_notifier.cc b/sync/notifier/invalidation_notifier.cc
index 0775d74..167b0ba 100644
--- a/sync/notifier/invalidation_notifier.cc
+++ b/sync/notifier/invalidation_notifier.cc
@@ -94,7 +94,8 @@ void InvalidationNotifier::UpdateCredentials(
invalidation_client_.UpdateCredentials(email, token);
}
-void InvalidationNotifier::SendNotification(ModelTypeSet changed_types) {
+void InvalidationNotifier::SendNotification(
+ const ObjectIdStateMap& id_state_map) {
DCHECK(CalledOnValidThread());
// Do nothing.
}
diff --git a/sync/notifier/invalidation_notifier.h b/sync/notifier/invalidation_notifier.h
index 79bc4ae..08b1095 100644
--- a/sync/notifier/invalidation_notifier.h
+++ b/sync/notifier/invalidation_notifier.h
@@ -58,7 +58,7 @@ class InvalidationNotifier
virtual void SetStateDeprecated(const std::string& state) OVERRIDE;
virtual void UpdateCredentials(
const std::string& email, const std::string& token) OVERRIDE;
- virtual void SendNotification(ModelTypeSet changed_types) OVERRIDE;
+ virtual void SendNotification(const ObjectIdStateMap& id_state_map) OVERRIDE;
// ChromeInvalidationClient::Listener implementation.
virtual void OnInvalidate(const ObjectIdStateMap& id_state_map) OVERRIDE;
diff --git a/sync/notifier/invalidation_notifier_unittest.cc b/sync/notifier/invalidation_notifier_unittest.cc
index 563e7ec..4265f7e 100644
--- a/sync/notifier/invalidation_notifier_unittest.cc
+++ b/sync/notifier/invalidation_notifier_unittest.cc
@@ -16,127 +16,80 @@
#include "sync/notifier/fake_invalidation_handler.h"
#include "sync/notifier/fake_invalidation_state_tracker.h"
#include "sync/notifier/invalidation_state_tracker.h"
+#include "sync/notifier/invalidator_test_template.h"
#include "sync/notifier/object_id_state_map_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace syncer {
namespace {
-using ::testing::InSequence;
-using ::testing::StrictMock;
+class InvalidationNotifierTestDelegate {
+ public:
+ InvalidationNotifierTestDelegate() {}
-class InvalidationNotifierTest : public testing::Test {
- protected:
- virtual void TearDown() {
- if (invalidation_notifier_.get())
- ResetNotifier();
+ ~InvalidationNotifierTestDelegate() {
+ DestroyInvalidator();
}
- // Constructs an InvalidationNotifier, places it in |invalidation_notifier_|,
- // and registers |fake_handler_| as a handler. This remains in place until
- // either TearDown (automatic) or ResetNotifier (manual) is called.
- void CreateNotifier(
- const std::string& initial_invalidation_state) {
- notifier::NotifierOptions notifier_options;
- // Note: URLRequestContextGetters are ref-counted.
- notifier_options.request_context_getter =
- new TestURLRequestContextGetter(message_loop_.message_loop_proxy());
- invalidation_notifier_.reset(
+ void CreateInvalidator(
+ const std::string& initial_state,
+ const base::WeakPtr<InvalidationStateTracker>&
+ invalidation_state_tracker) {
+ DCHECK(!invalidator_.get());
+ invalidator_.reset(
new InvalidationNotifier(
scoped_ptr<notifier::PushClient>(new notifier::FakePushClient()),
InvalidationVersionMap(),
- initial_invalidation_state,
- MakeWeakHandle(fake_tracker_.AsWeakPtr()),
+ initial_state,
+ MakeWeakHandle(invalidation_state_tracker),
"fake_client_info"));
- invalidation_notifier_->RegisterHandler(&fake_handler_);
}
- void ResetNotifier() {
- invalidation_notifier_->UnregisterHandler(&fake_handler_);
- // Stopping the invalidation notifier stops its scheduler, which deletes any
- // pending tasks without running them. Some tasks "run and delete" another
- // task, so they must be run in order to avoid leaking the inner task.
- // Stopping does not schedule any tasks, so it's both necessary and
+ Invalidator* GetInvalidator() {
+ return invalidator_.get();
+ }
+
+ void DestroyInvalidator() {
+ // Stopping the invalidation notifier stops its scheduler, which deletes
+ // any pending tasks without running them. Some tasks "run and delete"
+ // another task, so they must be run in order to avoid leaking the inner
+ // task. Stopping does not schedule any tasks, so it's both necessary and
// sufficient to drain the task queue before stopping the notifier.
message_loop_.RunAllPending();
- invalidation_notifier_.reset();
+ invalidator_.reset();
}
- void SetStateDeprecated(const std::string& new_state) {
- invalidation_notifier_->SetStateDeprecated(new_state);
+ void WaitForInvalidator() {
message_loop_.RunAllPending();
}
- private:
- MessageLoopForIO message_loop_;
- notifier::FakeBaseTask fake_base_task_;
+ void TriggerOnNotificationsEnabled() {
+ invalidator_->OnNotificationsEnabled();
+ }
+
+ void TriggerOnIncomingNotification(const ObjectIdStateMap& id_state_map,
+ IncomingNotificationSource source) {
+ // None of the tests actually care about |source|.
+ invalidator_->OnInvalidate(id_state_map);
+ }
- protected:
- scoped_ptr<InvalidationNotifier> invalidation_notifier_;
- FakeInvalidationStateTracker fake_tracker_;
- FakeInvalidationHandler fake_handler_;
+ void TriggerOnNotificationsDisabled(NotificationsDisabledReason reason) {
+ invalidator_->OnNotificationsDisabled(reason);
+ }
+
+ static bool InvalidatorHandlesDeprecatedState() {
+ return true;
+ }
+
+ private:
+ MessageLoop message_loop_;
+ scoped_ptr<InvalidationNotifier> invalidator_;
};
-TEST_F(InvalidationNotifierTest, Basic) {
- CreateNotifier("fake_state");
-
- const ModelTypeSet models(PREFERENCES, BOOKMARKS, AUTOFILL);
- const ObjectIdStateMap& id_state_map =
- ModelTypeStateMapToObjectIdStateMap(
- ModelTypeSetToStateMap(models, "payload"));
-
- invalidation_notifier_->UpdateRegisteredIds(
- &fake_handler_, ModelTypeSetToObjectIdSet(models));
-
- // TODO(tim): This call should be a no-op, Remove once bug 124140 and
- // associated issues are fixed.
- invalidation_notifier_->SetStateDeprecated("fake_state");
- // We don't expect |fake_tracker_|'s state to change, as we
- // initialized with non-empty initial_invalidation_state above.
- EXPECT_TRUE(fake_tracker_.GetInvalidationState().empty());
- invalidation_notifier_->SetUniqueId("fake_id");
- invalidation_notifier_->UpdateCredentials("foo@bar.com", "fake_token");
-
- invalidation_notifier_->OnNotificationsEnabled();
- EXPECT_EQ(NO_NOTIFICATION_ERROR,
- fake_handler_.GetNotificationsDisabledReason());
-
- invalidation_notifier_->OnInvalidate(id_state_map);
- EXPECT_THAT(id_state_map,
- Eq(fake_handler_.GetLastNotificationIdStateMap()));
- EXPECT_EQ(REMOTE_NOTIFICATION, fake_handler_.GetLastNotificationSource());
-
- invalidation_notifier_->OnNotificationsDisabled(
- TRANSIENT_NOTIFICATION_ERROR);
- EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
- fake_handler_.GetNotificationsDisabledReason());
-
- invalidation_notifier_->OnNotificationsDisabled(
- NOTIFICATION_CREDENTIALS_REJECTED);
- EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED,
- fake_handler_.GetNotificationsDisabledReason());
-}
-
-TEST_F(InvalidationNotifierTest, MigrateState) {
- CreateNotifier(std::string());
-
- SetStateDeprecated("fake_state");
- EXPECT_EQ("fake_state", fake_tracker_.GetInvalidationState());
-
- // Should do nothing.
- SetStateDeprecated("spurious_fake_state");
- EXPECT_EQ("fake_state", fake_tracker_.GetInvalidationState());
-
- // Pretend Chrome shut down.
- ResetNotifier();
-
- CreateNotifier("fake_state");
- // Should do nothing.
- SetStateDeprecated("more_spurious_fake_state");
- EXPECT_EQ("fake_state", fake_tracker_.GetInvalidationState());
-}
+INSTANTIATE_TYPED_TEST_CASE_P(
+ InvalidationNotifierTest, InvalidatorTest,
+ InvalidationNotifierTestDelegate);
} // namespace
diff --git a/sync/notifier/invalidation_util.cc b/sync/notifier/invalidation_util.cc
index 7307292..1c6b931 100644
--- a/sync/notifier/invalidation_util.cc
+++ b/sync/notifier/invalidation_util.cc
@@ -7,6 +7,9 @@
#include <ostream>
#include <sstream>
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
#include "google/cacheinvalidation/include/types.h"
#include "google/cacheinvalidation/types.pb.h"
@@ -40,6 +43,35 @@ bool ObjectIdToRealModelType(const invalidation::ObjectId& object_id,
return NotificationTypeToRealModelType(object_id.name(), model_type);
}
+scoped_ptr<base::DictionaryValue> ObjectIdToValue(
+ const invalidation::ObjectId& object_id) {
+ scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue());
+ value->SetInteger("source", object_id.source());
+ value->SetString("name", object_id.name());
+ return value.Pass();
+}
+
+bool ObjectIdFromValue(const base::DictionaryValue& value,
+ invalidation::ObjectId* out) {
+ *out = invalidation::ObjectId();
+ std::string name;
+ int source = 0;
+ if (!value.GetInteger("source", &source) ||
+ !value.GetString("name", &name)) {
+ return false;
+ }
+ *out = invalidation::ObjectId(source, name);
+ return true;
+}
+
+std::string ObjectIdToString(
+ const invalidation::ObjectId& object_id) {
+ scoped_ptr<base::DictionaryValue> value(ObjectIdToValue(object_id));
+ std::string str;
+ base::JSONWriter::Write(value.get(), &str);
+ return str;
+}
+
ObjectIdSet ModelTypeSetToObjectIdSet(const ModelTypeSet& model_types) {
ObjectIdSet ids;
for (ModelTypeSet::Iterator it = model_types.First(); it.Good(); it.Inc()) {
@@ -66,16 +98,6 @@ ModelTypeSet ObjectIdSetToModelTypeSet(const ObjectIdSet& ids) {
return model_types;
}
-std::string ObjectIdToString(
- const invalidation::ObjectId& object_id) {
- std::stringstream ss;
- ss << "{ ";
- ss << "name: " << object_id.name() << ", ";
- ss << "source: " << object_id.source();
- ss << " }";
- return ss.str();
-}
-
std::string InvalidationToString(
const invalidation::Invalidation& invalidation) {
std::stringstream ss;
diff --git a/sync/notifier/invalidation_util.h b/sync/notifier/invalidation_util.h
index 2f3198b..61bd317 100644
--- a/sync/notifier/invalidation_util.h
+++ b/sync/notifier/invalidation_util.h
@@ -11,8 +11,13 @@
#include <set>
#include <string>
+#include "base/memory/scoped_ptr.h"
#include "sync/internal_api/public/base/model_type.h"
+namespace base {
+class DictionaryValue;
+} // namespace
+
namespace invalidation {
class Invalidation;
@@ -38,11 +43,18 @@ bool RealModelTypeToObjectId(ModelType model_type,
bool ObjectIdToRealModelType(const invalidation::ObjectId& object_id,
ModelType* model_type);
-ObjectIdSet ModelTypeSetToObjectIdSet(const ModelTypeSet& models);
-ModelTypeSet ObjectIdSetToModelTypeSet(const ObjectIdSet& ids);
+// Caller owns the returned DictionaryValue.
+scoped_ptr<base::DictionaryValue> ObjectIdToValue(
+ const invalidation::ObjectId& object_id);
+
+bool ObjectIdFromValue(const base::DictionaryValue& value,
+ invalidation::ObjectId* out);
std::string ObjectIdToString(const invalidation::ObjectId& object_id);
+ObjectIdSet ModelTypeSetToObjectIdSet(const ModelTypeSet& models);
+ModelTypeSet ObjectIdSetToModelTypeSet(const ObjectIdSet& ids);
+
std::string InvalidationToString(
const invalidation::Invalidation& invalidation);
diff --git a/sync/notifier/invalidator.h b/sync/notifier/invalidator.h
index 2765a67..de33f19 100644
--- a/sync/notifier/invalidator.h
+++ b/sync/notifier/invalidator.h
@@ -13,6 +13,7 @@
#include "sync/internal_api/public/base/model_type.h"
#include "sync/notifier/invalidation_util.h"
+#include "sync/notifier/object_id_state_map.h"
namespace syncer {
class InvalidationHandler;
@@ -82,7 +83,7 @@ class Invalidator {
// which is still used by sync integration tests.
// TODO(akalin): Remove this once we move the integration tests off p2p
// notifications.
- virtual void SendNotification(ModelTypeSet changed_types) = 0;
+ virtual void SendNotification(const ObjectIdStateMap& id_state_map) = 0;
};
} // namespace syncer
diff --git a/sync/notifier/invalidator_registrar.cc b/sync/notifier/invalidator_registrar.cc
index a7ac5b0..03b401a 100644
--- a/sync/notifier/invalidator_registrar.cc
+++ b/sync/notifier/invalidator_registrar.cc
@@ -63,6 +63,19 @@ void InvalidatorRegistrar::UnregisterHandler(InvalidationHandler* handler) {
handlers_.RemoveObserver(handler);
}
+ObjectIdSet InvalidatorRegistrar::GetRegisteredIds(
+ InvalidationHandler* handler) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ObjectIdSet registered_ids;
+ for (IdHandlerMap::const_iterator it = id_to_handler_map_.begin();
+ it != id_to_handler_map_.end(); ++it) {
+ if (it->second == handler) {
+ registered_ids.insert(it->first);
+ }
+ }
+ return registered_ids;
+}
+
ObjectIdSet InvalidatorRegistrar::GetAllRegisteredIds() const {
DCHECK(thread_checker_.CalledOnValidThread());
ObjectIdSet registered_ids;
@@ -120,19 +133,6 @@ bool InvalidatorRegistrar::IsHandlerRegisteredForTest(
return handlers_.HasObserver(handler);
}
-ObjectIdSet InvalidatorRegistrar::GetRegisteredIdsForTest(
- InvalidationHandler* handler) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- ObjectIdSet registered_ids;
- for (IdHandlerMap::const_iterator it = id_to_handler_map_.begin();
- it != id_to_handler_map_.end(); ++it) {
- if (it->second == handler) {
- registered_ids.insert(it->first);
- }
- }
- return registered_ids;
-}
-
void InvalidatorRegistrar::DetachFromThreadForTest() {
DCHECK(thread_checker_.CalledOnValidThread());
thread_checker_.DetachFromThread();
diff --git a/sync/notifier/invalidator_registrar.h b/sync/notifier/invalidator_registrar.h
index 6bb481b..485b73e 100644
--- a/sync/notifier/invalidator_registrar.h
+++ b/sync/notifier/invalidator_registrar.h
@@ -44,6 +44,8 @@ class InvalidatorRegistrar {
// associated with |handler|.
void UnregisterHandler(InvalidationHandler* handler);
+ ObjectIdSet GetRegisteredIds(InvalidationHandler* handler) const;
+
// Returns the set of all IDs that are registered to some handler (even
// handlers that have been unregistered).
ObjectIdSet GetAllRegisteredIds() const;
@@ -60,7 +62,6 @@ class InvalidatorRegistrar {
void EmitOnNotificationsDisabled(NotificationsDisabledReason reason);
bool IsHandlerRegisteredForTest(InvalidationHandler* handler) const;
- ObjectIdSet GetRegisteredIdsForTest(InvalidationHandler* handler) const;
// Needed for death tests.
void DetachFromThreadForTest();
diff --git a/sync/notifier/invalidator_registrar_unittest.cc b/sync/notifier/invalidator_registrar_unittest.cc
index f79a720..90ac22d 100644
--- a/sync/notifier/invalidator_registrar_unittest.cc
+++ b/sync/notifier/invalidator_registrar_unittest.cc
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
#include "google/cacheinvalidation/types.pb.h"
#include "sync/notifier/fake_invalidation_handler.h"
#include "sync/notifier/invalidator_registrar.h"
+#include "sync/notifier/invalidator_test_template.h"
#include "sync/notifier/object_id_state_map_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -12,174 +15,119 @@ namespace syncer {
namespace {
-class InvalidatorRegistrarTest : public testing::Test {
- protected:
- InvalidatorRegistrarTest()
- : kObjectId1(ipc::invalidation::ObjectSource::TEST, "a"),
- kObjectId2(ipc::invalidation::ObjectSource::TEST, "b"),
- kObjectId3(ipc::invalidation::ObjectSource::TEST, "c"),
- kObjectId4(ipc::invalidation::ObjectSource::TEST, "d") {
+// We test InvalidatorRegistrar by wrapping it in an Invalidator and
+// running the usual Invalidator tests.
+
+// Thin Invalidator wrapper around InvalidatorRegistrar.
+class RegistrarInvalidator : public Invalidator {
+ public:
+ virtual ~RegistrarInvalidator() {}
+
+ InvalidatorRegistrar* GetRegistrar() {
+ return &registrar_;
}
- const invalidation::ObjectId kObjectId1;
- const invalidation::ObjectId kObjectId2;
- const invalidation::ObjectId kObjectId3;
- const invalidation::ObjectId kObjectId4;
-};
+ // Invalidator implementation.
+ virtual void RegisterHandler(InvalidationHandler* handler) OVERRIDE {
+ registrar_.RegisterHandler(handler);
+ }
-// Register a handler, register some IDs for that handler, and then unregister
-// the handler, dispatching invalidations in between. The handler should only
-// see invalidations when its registered and its IDs are registered.
-TEST_F(InvalidatorRegistrarTest, Basic) {
- FakeInvalidationHandler handler;
+ virtual void UpdateRegisteredIds(InvalidationHandler* handler,
+ const ObjectIdSet& ids) OVERRIDE {
+ registrar_.UpdateRegisteredIds(handler, ids);
+ }
- InvalidatorRegistrar registrar;
+ virtual void UnregisterHandler(InvalidationHandler* handler) OVERRIDE {
+ registrar_.UnregisterHandler(handler);
+ }
- registrar.RegisterHandler(&handler);
+ virtual void SetUniqueId(const std::string& unique_id) OVERRIDE {
+ // Do nothing.
+ }
- ObjectIdStateMap states;
- states[kObjectId1].payload = "1";
- states[kObjectId2].payload = "2";
- states[kObjectId3].payload = "3";
+ virtual void SetStateDeprecated(const std::string& state) OVERRIDE {
+ // Do nothing.
+ }
- // Should be ignored since no IDs are registered to |handler|.
- registrar.DispatchInvalidationsToHandlers(states, REMOTE_NOTIFICATION);
- EXPECT_EQ(0, handler.GetNotificationCount());
+ virtual void UpdateCredentials(
+ const std::string& email, const std::string& token) OVERRIDE {
+ // Do nothing.
+ }
- ObjectIdSet ids;
- ids.insert(kObjectId1);
- ids.insert(kObjectId2);
- registrar.UpdateRegisteredIds(&handler, ids);
-
- ObjectIdStateMap expected_states;
- expected_states[kObjectId1].payload = "1";
- expected_states[kObjectId2].payload = "2";
-
- registrar.DispatchInvalidationsToHandlers(states, REMOTE_NOTIFICATION);
- EXPECT_EQ(1, handler.GetNotificationCount());
- EXPECT_THAT(
- expected_states,
- Eq(handler.GetLastNotificationIdStateMap()));
- EXPECT_EQ(REMOTE_NOTIFICATION, handler.GetLastNotificationSource());
-
- ids.erase(kObjectId1);
- ids.insert(kObjectId3);
- registrar.UpdateRegisteredIds(&handler, ids);
-
- expected_states.erase(kObjectId1);
- expected_states[kObjectId3].payload = "3";
-
- // Removed object IDs should not be notified, newly-added ones should.
- registrar.DispatchInvalidationsToHandlers(states, REMOTE_NOTIFICATION);
- EXPECT_EQ(2, handler.GetNotificationCount());
- EXPECT_THAT(
- expected_states,
- Eq(handler.GetLastNotificationIdStateMap()));
- EXPECT_EQ(REMOTE_NOTIFICATION, handler.GetLastNotificationSource());
-
- registrar.UnregisterHandler(&handler);
-
- // Should be ignored since |handler| isn't registered anymore.
- registrar.DispatchInvalidationsToHandlers(states, REMOTE_NOTIFICATION);
- EXPECT_EQ(2, handler.GetNotificationCount());
-}
+ virtual void SendNotification(
+ const ObjectIdStateMap& id_state_map) OVERRIDE {
+ // Do nothing.
+ }
-// Register handlers and some IDs for those handlers, register a handler with
-// no IDs, and register a handler with some IDs but unregister it. Then,
-// dispatch some notifications and invalidations. Handlers that are registered
-// should get notifications, and the ones that have registered IDs should
-// receive invalidations for those IDs.
-TEST_F(InvalidatorRegistrarTest, MultipleHandlers) {
- FakeInvalidationHandler handler1;
- FakeInvalidationHandler handler2;
- FakeInvalidationHandler handler3;
- FakeInvalidationHandler handler4;
+ private:
+ InvalidatorRegistrar registrar_;
+};
- InvalidatorRegistrar registrar;
+class RegistrarInvalidatorTestDelegate {
+ public:
+ RegistrarInvalidatorTestDelegate() {}
- registrar.RegisterHandler(&handler1);
- registrar.RegisterHandler(&handler2);
- registrar.RegisterHandler(&handler3);
- registrar.RegisterHandler(&handler4);
-
- {
- ObjectIdSet ids;
- ids.insert(kObjectId1);
- ids.insert(kObjectId2);
- registrar.UpdateRegisteredIds(&handler1, ids);
+ ~RegistrarInvalidatorTestDelegate() {
+ DestroyInvalidator();
}
- {
- ObjectIdSet ids;
- ids.insert(kObjectId3);
- registrar.UpdateRegisteredIds(&handler2, ids);
+ void CreateInvalidator(
+ const std::string& initial_state,
+ const base::WeakPtr<InvalidationStateTracker>&
+ invalidation_state_tracker) {
+ DCHECK(!invalidator_.get());
+ invalidator_.reset(new RegistrarInvalidator());
}
- // Don't register any IDs for handler3.
+ RegistrarInvalidator* GetInvalidator() {
+ return invalidator_.get();
+ }
- {
- ObjectIdSet ids;
- ids.insert(kObjectId4);
- registrar.UpdateRegisteredIds(&handler4, ids);
+ void DestroyInvalidator() {
+ invalidator_.reset();
}
- registrar.UnregisterHandler(&handler4);
-
- registrar.EmitOnNotificationsEnabled();
- EXPECT_EQ(NO_NOTIFICATION_ERROR,
- handler1.GetNotificationsDisabledReason());
- EXPECT_EQ(NO_NOTIFICATION_ERROR,
- handler2.GetNotificationsDisabledReason());
- EXPECT_EQ(NO_NOTIFICATION_ERROR,
- handler3.GetNotificationsDisabledReason());
- EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
- handler4.GetNotificationsDisabledReason());
-
- {
- ObjectIdStateMap states;
- states[kObjectId1].payload = "1";
- states[kObjectId2].payload = "2";
- states[kObjectId3].payload = "3";
- states[kObjectId4].payload = "4";
- registrar.DispatchInvalidationsToHandlers(states, REMOTE_NOTIFICATION);
-
- ObjectIdStateMap expected_states;
- expected_states[kObjectId1].payload = "1";
- expected_states[kObjectId2].payload = "2";
-
- EXPECT_EQ(1, handler1.GetNotificationCount());
- EXPECT_THAT(
- expected_states,
- Eq(handler1.GetLastNotificationIdStateMap()));
- EXPECT_EQ(REMOTE_NOTIFICATION, handler1.GetLastNotificationSource());
-
- expected_states.clear();
- expected_states[kObjectId3].payload = "3";
-
- EXPECT_EQ(1, handler2.GetNotificationCount());
- EXPECT_THAT(
- expected_states,
- Eq(handler2.GetLastNotificationIdStateMap()));
- EXPECT_EQ(REMOTE_NOTIFICATION, handler2.GetLastNotificationSource());
-
- EXPECT_EQ(0, handler3.GetNotificationCount());
- EXPECT_EQ(0, handler4.GetNotificationCount());
+ void WaitForInvalidator() {
+ // Do nothing.
}
- registrar.EmitOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR);
- EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
- handler1.GetNotificationsDisabledReason());
- EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
- handler2.GetNotificationsDisabledReason());
- EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
- handler3.GetNotificationsDisabledReason());
- EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
- handler4.GetNotificationsDisabledReason());
-}
+ void TriggerOnNotificationsEnabled() {
+ invalidator_->GetRegistrar()->EmitOnNotificationsEnabled();
+ }
+
+ void TriggerOnIncomingNotification(const ObjectIdStateMap& id_state_map,
+ IncomingNotificationSource source) {
+ invalidator_->GetRegistrar()->DispatchInvalidationsToHandlers(
+ id_state_map, source);
+ }
+
+ void TriggerOnNotificationsDisabled(NotificationsDisabledReason reason) {
+ invalidator_->GetRegistrar()->EmitOnNotificationsDisabled(reason);
+ }
+
+ static bool InvalidatorHandlesDeprecatedState() {
+ return false;
+ }
+
+ private:
+ scoped_ptr<RegistrarInvalidator> invalidator_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+ RegistrarInvalidatorTest, InvalidatorTest,
+ RegistrarInvalidatorTestDelegate);
+
+class InvalidatorRegistrarTest : public testing::Test {};
// Multiple registrations by different handlers on the same object ID should
// cause a CHECK.
+//
+// Technically this can be part of InvalidatorTest, but we want to keep the
+// number of death tests down.
TEST_F(InvalidatorRegistrarTest, MultipleRegistration) {
+ const invalidation::ObjectId id1(ipc::invalidation::ObjectSource::TEST, "a");
+ const invalidation::ObjectId id2(ipc::invalidation::ObjectSource::TEST, "a");
+
InvalidatorRegistrar registrar;
FakeInvalidationHandler handler1;
@@ -189,8 +137,8 @@ TEST_F(InvalidatorRegistrarTest, MultipleRegistration) {
registrar.RegisterHandler(&handler2);
ObjectIdSet ids;
- ids.insert(kObjectId1);
- ids.insert(kObjectId2);
+ ids.insert(id1);
+ ids.insert(id2);
registrar.UpdateRegisteredIds(&handler1, ids);
registrar.DetachFromThreadForTest();
@@ -199,60 +147,6 @@ TEST_F(InvalidatorRegistrarTest, MultipleRegistration) {
EXPECT_DEATH({ registrar.UpdateRegisteredIds(&handler2, ids); }, "");
}
-// Make sure that passing an empty set to UpdateRegisteredIds clears the
-// corresponding entries for the handler.
-TEST_F(InvalidatorRegistrarTest, EmptySetUnregisters) {
- FakeInvalidationHandler handler1;
-
- // Control observer.
- FakeInvalidationHandler handler2;
-
- InvalidatorRegistrar registrar;
-
- registrar.RegisterHandler(&handler1);
- registrar.RegisterHandler(&handler2);
-
- {
- ObjectIdSet ids;
- ids.insert(kObjectId1);
- ids.insert(kObjectId2);
- registrar.UpdateRegisteredIds(&handler1, ids);
- }
-
- {
- ObjectIdSet ids;
- ids.insert(kObjectId3);
- registrar.UpdateRegisteredIds(&handler2, ids);
- }
-
- // Unregister the IDs for the first observer. It should not receive any
- // further invalidations.
- registrar.UpdateRegisteredIds(&handler1, ObjectIdSet());
-
- registrar.EmitOnNotificationsEnabled();
- EXPECT_EQ(NO_NOTIFICATION_ERROR,
- handler1.GetNotificationsDisabledReason());
- EXPECT_EQ(NO_NOTIFICATION_ERROR,
- handler2.GetNotificationsDisabledReason());
-
- {
- ObjectIdStateMap states;
- states[kObjectId1].payload = "1";
- states[kObjectId2].payload = "2";
- states[kObjectId3].payload = "3";
- registrar.DispatchInvalidationsToHandlers(states,
- REMOTE_NOTIFICATION);
- EXPECT_EQ(0, handler1.GetNotificationCount());
- EXPECT_EQ(1, handler2.GetNotificationCount());
- }
-
- registrar.EmitOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR);
- EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
- handler1.GetNotificationsDisabledReason());
- EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
- handler2.GetNotificationsDisabledReason());
-}
-
} // namespace
} // namespace syncer
diff --git a/sync/notifier/invalidator_test_template.h b/sync/notifier/invalidator_test_template.h
new file mode 100644
index 0000000..df25107
--- /dev/null
+++ b/sync/notifier/invalidator_test_template.h
@@ -0,0 +1,404 @@
+// 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.
+
+// This class defines tests that implementations of Invalidator should pass in
+// order to be conformant. Here's how you use it to test your implementation.
+//
+// Say your class is called MyInvalidator. Then you need to define a class
+// called MyInvalidatorTestDelegate in my_sync_notifier_unittest.cc like this:
+//
+// class MyInvalidatorTestDelegate {
+// public:
+// MyInvalidatorTestDelegate() ...
+//
+// ~MyInvalidatorTestDelegate() {
+// // DestroyInvalidator() may not be explicitly called by tests.
+// DestroyInvalidator();
+// }
+//
+// // Create the Invalidator implementation with the given parameters.
+// void CreateInvalidator(
+// const std::string& initial_state,
+// const base::WeakPtr<InvalidationStateTracker>&
+// invalidation_state_tracker) {
+// ...
+// }
+//
+// // Should return the Invalidator implementation. Only called after
+// // CreateInvalidator and before DestroyInvalidator.
+// MyInvalidator* GetInvalidator() {
+// ...
+// }
+//
+// // Destroy the Invalidator implementation.
+// void DestroyInvalidator() {
+// ...
+// }
+//
+// // Called after a call to SetStateDeprecated(), SetUniqueId(), or
+// // UpdateCredentials() on the Invalidator implementation. Should block
+// // until the effects of the call are visible on the current thread.
+// void WaitForInvalidator() {
+// ...
+// }
+//
+// // The Trigger* functions below should block until the effects of
+// // the call are visible on the current thread.
+//
+// // Should cause OnNotificationsEnabled() to be called on all
+// // observers of the Invalidator implementation.
+// void TriggerOnNotificationsEnabled() {
+// ...
+// }
+//
+// // Should cause OnIncomingNotification() to be called on all
+// // observers of the Invalidator implementation with the given
+// // parameters.
+// void TriggerOnIncomingNotification(const ObjectIdStateMap& id_state_map,
+// IncomingNotificationSource source) {
+// ...
+// }
+//
+// // Should cause OnNotificationsDisabled() to be called on all
+// // observers of the Invalidator implementation with the given
+// // parameters.
+// void TriggerOnNotificationsDisabled(
+// NotificationsDisabledReason reason) {
+// ...
+// }
+//
+// // Returns whether or not the notifier handles storing the old
+// // (deprecated) notifier state.
+// static bool InvalidatorHandlesDeprecatedState() {
+// return false;
+// }
+// };
+//
+// The InvalidatorTest test harness will have a member variable of
+// this delegate type and will call its functions in the various
+// tests.
+//
+// Then you simply #include this file as well as gtest.h and add the
+// following statement to my_sync_notifier_unittest.cc:
+//
+// INSTANTIATE_TYPED_TEST_CASE_P(
+// MyInvalidator, InvalidatorTest, MyInvalidatorTestDelegate);
+//
+// Easy!
+
+#ifndef SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
+#define SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
+
+#include "google/cacheinvalidation/include/types.h"
+#include "google/cacheinvalidation/types.pb.h"
+#include "sync/notifier/fake_invalidation_handler.h"
+#include "sync/notifier/fake_invalidation_state_tracker.h"
+#include "sync/notifier/invalidator.h"
+#include "sync/notifier/object_id_state_map.h"
+#include "sync/notifier/object_id_state_map_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+template <typename InvalidatorTestDelegate>
+class InvalidatorTest : public testing::Test {
+ protected:
+ InvalidatorTest()
+ : id1(ipc::invalidation::ObjectSource::TEST, "a"),
+ id2(ipc::invalidation::ObjectSource::TEST, "b"),
+ id3(ipc::invalidation::ObjectSource::TEST, "c"),
+ id4(ipc::invalidation::ObjectSource::TEST, "d") {
+ }
+
+ Invalidator* CreateAndInitializeInvalidator() {
+ this->delegate_.CreateInvalidator("fake_initial_state",
+ this->fake_tracker_.AsWeakPtr());
+ Invalidator* const invalidator = this->delegate_.GetInvalidator();
+
+ // TODO(tim): This call should be a no-op. Remove once bug 124140 and
+ // associated issues are fixed.
+ invalidator->SetStateDeprecated("fake_state");
+ this->delegate_.WaitForInvalidator();
+ // We don't expect |fake_tracker_|'s state to change, as we
+ // initialized with non-empty initial_invalidation_state above.
+ EXPECT_TRUE(this->fake_tracker_.GetInvalidationState().empty());
+ invalidator->SetUniqueId("fake_id");
+ this->delegate_.WaitForInvalidator();
+ invalidator->UpdateCredentials("foo@bar.com", "fake_token");
+ this->delegate_.WaitForInvalidator();
+
+ return invalidator;
+ }
+
+ FakeInvalidationStateTracker fake_tracker_;
+ InvalidatorTestDelegate delegate_;
+
+ const invalidation::ObjectId id1;
+ const invalidation::ObjectId id2;
+ const invalidation::ObjectId id3;
+ const invalidation::ObjectId id4;
+};
+
+TYPED_TEST_CASE_P(InvalidatorTest);
+
+// Initialize the invalidator, register a handler, register some IDs for that
+// handler, and then unregister the handler, dispatching invalidations in
+// between. The handler should only see invalidations when its registered and
+// its IDs are registered.
+TYPED_TEST_P(InvalidatorTest, Basic) {
+ Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
+
+ FakeInvalidationHandler handler;
+
+ invalidator->RegisterHandler(&handler);
+
+ ObjectIdStateMap states;
+ states[this->id1].payload = "1";
+ states[this->id2].payload = "2";
+ states[this->id3].payload = "3";
+
+ // Should be ignored since no IDs are registered to |handler|.
+ this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
+ EXPECT_EQ(0, handler.GetNotificationCount());
+
+ ObjectIdSet ids;
+ ids.insert(this->id1);
+ ids.insert(this->id2);
+ invalidator->UpdateRegisteredIds(&handler, ids);
+
+ this->delegate_.TriggerOnNotificationsEnabled();
+ EXPECT_EQ(NO_NOTIFICATION_ERROR,
+ handler.GetNotificationsDisabledReason());
+
+ ObjectIdStateMap expected_states;
+ expected_states[this->id1].payload = "1";
+ expected_states[this->id2].payload = "2";
+
+ this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
+ EXPECT_EQ(1, handler.GetNotificationCount());
+ EXPECT_THAT(
+ expected_states,
+ Eq(handler.GetLastNotificationIdStateMap()));
+ EXPECT_EQ(REMOTE_NOTIFICATION, handler.GetLastNotificationSource());
+
+ ids.erase(this->id1);
+ ids.insert(this->id3);
+ invalidator->UpdateRegisteredIds(&handler, ids);
+
+ expected_states.erase(this->id1);
+ expected_states[this->id3].payload = "3";
+
+ // Removed object IDs should not be notified, newly-added ones should.
+ this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
+ EXPECT_EQ(2, handler.GetNotificationCount());
+ EXPECT_THAT(
+ expected_states,
+ Eq(handler.GetLastNotificationIdStateMap()));
+ EXPECT_EQ(REMOTE_NOTIFICATION, handler.GetLastNotificationSource());
+
+ this->delegate_.TriggerOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR);
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
+ handler.GetNotificationsDisabledReason());
+
+ this->delegate_.TriggerOnNotificationsDisabled(
+ NOTIFICATION_CREDENTIALS_REJECTED);
+ EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED,
+ handler.GetNotificationsDisabledReason());
+
+ invalidator->UnregisterHandler(&handler);
+
+ // Should be ignored since |handler| isn't registered anymore.
+ this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
+ EXPECT_EQ(2, handler.GetNotificationCount());
+}
+
+// Register handlers and some IDs for those handlers, register a handler with
+// no IDs, and register a handler with some IDs but unregister it. Then,
+// dispatch some notifications and invalidations. Handlers that are registered
+// should get notifications, and the ones that have registered IDs should
+// receive invalidations for those IDs.
+TYPED_TEST_P(InvalidatorTest, MultipleHandlers) {
+ Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
+
+ FakeInvalidationHandler handler1;
+ FakeInvalidationHandler handler2;
+ FakeInvalidationHandler handler3;
+ FakeInvalidationHandler handler4;
+
+ invalidator->RegisterHandler(&handler1);
+ invalidator->RegisterHandler(&handler2);
+ invalidator->RegisterHandler(&handler3);
+ invalidator->RegisterHandler(&handler4);
+
+ {
+ ObjectIdSet ids;
+ ids.insert(this->id1);
+ ids.insert(this->id2);
+ invalidator->UpdateRegisteredIds(&handler1, ids);
+ }
+
+ {
+ ObjectIdSet ids;
+ ids.insert(this->id3);
+ invalidator->UpdateRegisteredIds(&handler2, ids);
+ }
+
+ // Don't register any IDs for handler3.
+
+ {
+ ObjectIdSet ids;
+ ids.insert(this->id4);
+ invalidator->UpdateRegisteredIds(&handler4, ids);
+ }
+
+ invalidator->UnregisterHandler(&handler4);
+
+ this->delegate_.TriggerOnNotificationsEnabled();
+ EXPECT_EQ(NO_NOTIFICATION_ERROR,
+ handler1.GetNotificationsDisabledReason());
+ EXPECT_EQ(NO_NOTIFICATION_ERROR,
+ handler2.GetNotificationsDisabledReason());
+ EXPECT_EQ(NO_NOTIFICATION_ERROR,
+ handler3.GetNotificationsDisabledReason());
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
+ handler4.GetNotificationsDisabledReason());
+
+ {
+ ObjectIdStateMap states;
+ states[this->id1].payload = "1";
+ states[this->id2].payload = "2";
+ states[this->id3].payload = "3";
+ states[this->id4].payload = "4";
+ this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
+
+ ObjectIdStateMap expected_states;
+ expected_states[this->id1].payload = "1";
+ expected_states[this->id2].payload = "2";
+
+ EXPECT_EQ(1, handler1.GetNotificationCount());
+ EXPECT_THAT(
+ expected_states,
+ Eq(handler1.GetLastNotificationIdStateMap()));
+ EXPECT_EQ(REMOTE_NOTIFICATION, handler1.GetLastNotificationSource());
+
+ expected_states.clear();
+ expected_states[this->id3].payload = "3";
+
+ EXPECT_EQ(1, handler2.GetNotificationCount());
+ EXPECT_THAT(
+ expected_states,
+ Eq(handler2.GetLastNotificationIdStateMap()));
+ EXPECT_EQ(REMOTE_NOTIFICATION, handler2.GetLastNotificationSource());
+
+ EXPECT_EQ(0, handler3.GetNotificationCount());
+ EXPECT_EQ(0, handler4.GetNotificationCount());
+ }
+
+ this->delegate_.TriggerOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR);
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
+ handler1.GetNotificationsDisabledReason());
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
+ handler2.GetNotificationsDisabledReason());
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
+ handler3.GetNotificationsDisabledReason());
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
+ handler4.GetNotificationsDisabledReason());
+}
+
+// Make sure that passing an empty set to UpdateRegisteredIds clears the
+// corresponding entries for the handler.
+TYPED_TEST_P(InvalidatorTest, EmptySetUnregisters) {
+ Invalidator* const invalidator = this->CreateAndInitializeInvalidator();
+
+ FakeInvalidationHandler handler1;
+
+ // Control observer.
+ FakeInvalidationHandler handler2;
+
+ invalidator->RegisterHandler(&handler1);
+ invalidator->RegisterHandler(&handler2);
+
+ {
+ ObjectIdSet ids;
+ ids.insert(this->id1);
+ ids.insert(this->id2);
+ invalidator->UpdateRegisteredIds(&handler1, ids);
+ }
+
+ {
+ ObjectIdSet ids;
+ ids.insert(this->id3);
+ invalidator->UpdateRegisteredIds(&handler2, ids);
+ }
+
+ // Unregister the IDs for the first observer. It should not receive any
+ // further invalidations.
+ invalidator->UpdateRegisteredIds(&handler1, ObjectIdSet());
+
+ this->delegate_.TriggerOnNotificationsEnabled();
+ EXPECT_EQ(NO_NOTIFICATION_ERROR,
+ handler1.GetNotificationsDisabledReason());
+ EXPECT_EQ(NO_NOTIFICATION_ERROR,
+ handler2.GetNotificationsDisabledReason());
+
+ {
+ ObjectIdStateMap states;
+ states[this->id1].payload = "1";
+ states[this->id2].payload = "2";
+ states[this->id3].payload = "3";
+ this->delegate_.TriggerOnIncomingNotification(states, REMOTE_NOTIFICATION);
+ EXPECT_EQ(0, handler1.GetNotificationCount());
+ EXPECT_EQ(1, handler2.GetNotificationCount());
+ }
+
+ this->delegate_.TriggerOnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR);
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
+ handler1.GetNotificationsDisabledReason());
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
+ handler2.GetNotificationsDisabledReason());
+}
+
+// Initialize the invalidator with an empty initial state. Call the deprecated
+// state setter function a number of times, destroying and re-creating the
+// invalidator in between. Only the first one should take effect (i.e., state
+// migration should only happen once).
+TYPED_TEST_P(InvalidatorTest, MigrateState) {
+ if (!this->delegate_.InvalidatorHandlesDeprecatedState()) {
+ DLOG(INFO) << "This Invalidator doesn't handle deprecated state; "
+ << "skipping";
+ return;
+ }
+
+ this->delegate_.CreateInvalidator(std::string(),
+ this->fake_tracker_.AsWeakPtr());
+ Invalidator* invalidator = this->delegate_.GetInvalidator();
+
+ invalidator->SetStateDeprecated("fake_state");
+ this->delegate_.WaitForInvalidator();
+ EXPECT_EQ("fake_state", this->fake_tracker_.GetInvalidationState());
+
+ // Should do nothing.
+ invalidator->SetStateDeprecated("spurious_fake_state");
+ this->delegate_.WaitForInvalidator();
+ EXPECT_EQ("fake_state", this->fake_tracker_.GetInvalidationState());
+
+ // Pretend that Chrome has shut down.
+ this->delegate_.DestroyInvalidator();
+ this->delegate_.CreateInvalidator("fake_state",
+ this->fake_tracker_.AsWeakPtr());
+ invalidator = this->delegate_.GetInvalidator();
+
+ // Should do nothing.
+ invalidator->SetStateDeprecated("more_spurious_fake_state");
+ this->delegate_.WaitForInvalidator();
+ EXPECT_EQ("fake_state", this->fake_tracker_.GetInvalidationState());
+}
+
+REGISTER_TYPED_TEST_CASE_P(InvalidatorTest,
+ Basic, MultipleHandlers, EmptySetUnregisters,
+ MigrateState);
+
+} // namespace syncer
+
+#endif // SYNC_NOTIFIER_INVALIDATOR_TEST_TEMPLATE_H_
diff --git a/sync/notifier/non_blocking_invalidator.cc b/sync/notifier/non_blocking_invalidator.cc
index ab4f166..1f68cb3 100644
--- a/sync/notifier/non_blocking_invalidator.cc
+++ b/sync/notifier/non_blocking_invalidator.cc
@@ -239,7 +239,8 @@ void NonBlockingInvalidator::UpdateCredentials(const std::string& email,
}
}
-void NonBlockingInvalidator::SendNotification(ModelTypeSet changed_types) {
+void NonBlockingInvalidator::SendNotification(
+ const ObjectIdStateMap& id_state_map) {
DCHECK(parent_task_runner_->BelongsToCurrentThread());
// InvalidationClient doesn't implement SendNotification(), so no
// need to forward on the call.
diff --git a/sync/notifier/non_blocking_invalidator.h b/sync/notifier/non_blocking_invalidator.h
index cd98fe5..8e93219 100644
--- a/sync/notifier/non_blocking_invalidator.h
+++ b/sync/notifier/non_blocking_invalidator.h
@@ -54,7 +54,7 @@ class NonBlockingInvalidator
virtual void SetStateDeprecated(const std::string& state) OVERRIDE;
virtual void UpdateCredentials(
const std::string& email, const std::string& token) OVERRIDE;
- virtual void SendNotification(ModelTypeSet changed_types) OVERRIDE;
+ virtual void SendNotification(const ObjectIdStateMap& id_state_map) OVERRIDE;
// InvalidationHandler implementation.
virtual void OnNotificationsEnabled() OVERRIDE;
diff --git a/sync/notifier/non_blocking_invalidator_unittest.cc b/sync/notifier/non_blocking_invalidator_unittest.cc
index 8704cd2..ed7e6bf 100644
--- a/sync/notifier/non_blocking_invalidator_unittest.cc
+++ b/sync/notifier/non_blocking_invalidator_unittest.cc
@@ -7,102 +7,102 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
+#include "base/run_loop.h"
#include "base/threading/thread.h"
#include "google/cacheinvalidation/types.pb.h"
#include "jingle/notifier/base/fake_base_task.h"
#include "net/url_request/url_request_test_util.h"
-#include "sync/internal_api/public/base/model_type.h"
-#include "sync/internal_api/public/base/model_type_state_map.h"
#include "sync/internal_api/public/util/weak_handle.h"
#include "sync/notifier/fake_invalidation_handler.h"
#include "sync/notifier/invalidation_state_tracker.h"
+#include "sync/notifier/invalidator_test_template.h"
#include "sync/notifier/object_id_state_map_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace syncer {
namespace {
-using ::testing::InSequence;
-using ::testing::StrictMock;
+// Needed by WaitForInvalidator().
+void DoNothing() {}
-class NonBlockingInvalidatorTest : public testing::Test {
+class NonBlockingInvalidatorTestDelegate {
public:
- NonBlockingInvalidatorTest() : io_thread_("Test IO thread") {}
+ NonBlockingInvalidatorTestDelegate() : io_thread_("IO thread") {}
- protected:
- virtual void SetUp() {
+ ~NonBlockingInvalidatorTestDelegate() {
+ DestroyInvalidator();
+ }
+
+ void CreateInvalidator(
+ const std::string& initial_state,
+ const base::WeakPtr<InvalidationStateTracker>&
+ invalidation_state_tracker) {
+ DCHECK(!invalidator_.get());
base::Thread::Options options;
options.message_loop_type = MessageLoop::TYPE_IO;
io_thread_.StartWithOptions(options);
request_context_getter_ =
new TestURLRequestContextGetter(io_thread_.message_loop_proxy());
- notifier::NotifierOptions notifier_options;
- notifier_options.request_context_getter = request_context_getter_;
- invalidation_notifier_.reset(
+ notifier::NotifierOptions invalidator_options;
+ invalidator_options.request_context_getter = request_context_getter_;
+ invalidator_.reset(
new NonBlockingInvalidator(
- notifier_options,
+ invalidator_options,
InvalidationVersionMap(),
- std::string(), // initial_invalidation_state
- MakeWeakHandle(base::WeakPtr<InvalidationStateTracker>()),
+ initial_state,
+ MakeWeakHandle(invalidation_state_tracker),
"fake_client_info"));
- invalidation_notifier_->RegisterHandler(&fake_handler_);
}
- virtual void TearDown() {
- invalidation_notifier_->UnregisterHandler(&fake_handler_);
- invalidation_notifier_.reset();
+ Invalidator* GetInvalidator() {
+ return invalidator_.get();
+ }
+
+ void DestroyInvalidator() {
+ invalidator_.reset();
request_context_getter_ = NULL;
io_thread_.Stop();
- ui_loop_.RunAllPending();
+ message_loop_.RunAllPending();
}
- MessageLoop ui_loop_;
- base::Thread io_thread_;
- scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
- scoped_ptr<NonBlockingInvalidator> invalidation_notifier_;
- FakeInvalidationHandler fake_handler_;
- notifier::FakeBaseTask fake_base_task_;
-};
-
-// TODO(akalin): Add real unit tests (http://crbug.com/140410).
-
-TEST_F(NonBlockingInvalidatorTest, Basic) {
- const ModelTypeSet models(PREFERENCES, BOOKMARKS, AUTOFILL);
- const ObjectIdStateMap& id_state_map =
- ModelTypeStateMapToObjectIdStateMap(
- ModelTypeSetToStateMap(models, "payload"));
-
- invalidation_notifier_->UpdateRegisteredIds(
- &fake_handler_, ModelTypeSetToObjectIdSet(models));
+ void WaitForInvalidator() {
+ base::RunLoop run_loop;
+ ASSERT_TRUE(
+ io_thread_.message_loop_proxy()->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&DoNothing),
+ run_loop.QuitClosure()));
+ run_loop.Run();
+ }
- invalidation_notifier_->SetStateDeprecated("fake_state");
- invalidation_notifier_->SetUniqueId("fake_id");
- invalidation_notifier_->UpdateCredentials("foo@bar.com", "fake_token");
+ void TriggerOnNotificationsEnabled() {
+ invalidator_->OnNotificationsEnabled();
+ }
- invalidation_notifier_->OnNotificationsEnabled();
- EXPECT_EQ(NO_NOTIFICATION_ERROR,
- fake_handler_.GetNotificationsDisabledReason());
+ void TriggerOnIncomingNotification(const ObjectIdStateMap& id_state_map,
+ IncomingNotificationSource source) {
+ invalidator_->OnIncomingNotification(id_state_map, source);
+ }
- invalidation_notifier_->OnIncomingNotification(
- id_state_map, REMOTE_NOTIFICATION);
- EXPECT_THAT(id_state_map,
- Eq(fake_handler_.GetLastNotificationIdStateMap()));
- EXPECT_EQ(REMOTE_NOTIFICATION, fake_handler_.GetLastNotificationSource());
+ void TriggerOnNotificationsDisabled(NotificationsDisabledReason reason) {
+ invalidator_->OnNotificationsDisabled(reason);
+ }
- invalidation_notifier_->OnNotificationsDisabled(
- TRANSIENT_NOTIFICATION_ERROR);
- EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR,
- fake_handler_.GetNotificationsDisabledReason());
+ static bool InvalidatorHandlesDeprecatedState() {
+ return true;
+ }
- invalidation_notifier_->OnNotificationsDisabled(
- NOTIFICATION_CREDENTIALS_REJECTED);
- EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED,
- fake_handler_.GetNotificationsDisabledReason());
+ private:
+ MessageLoop message_loop_;
+ base::Thread io_thread_;
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ scoped_ptr<NonBlockingInvalidator> invalidator_;
+};
- ui_loop_.RunAllPending();
-}
+INSTANTIATE_TYPED_TEST_CASE_P(
+ NonBlockingInvalidatorTest, InvalidatorTest,
+ NonBlockingInvalidatorTestDelegate);
} // namespace
diff --git a/sync/notifier/notifications_disabled_reason.cc b/sync/notifier/notifications_disabled_reason.cc
index 89c0a03..8c1a1aa 100644
--- a/sync/notifier/notifications_disabled_reason.cc
+++ b/sync/notifier/notifications_disabled_reason.cc
@@ -38,4 +38,19 @@ NotificationsDisabledReason FromNotifierReason(
}
}
+notifier::NotificationsDisabledReason ToNotifierReasonForTest(
+ NotificationsDisabledReason reason) {
+ switch (reason) {
+ case NO_NOTIFICATION_ERROR:
+ return notifier::NO_NOTIFICATION_ERROR;
+ case TRANSIENT_NOTIFICATION_ERROR:
+ return notifier::TRANSIENT_NOTIFICATION_ERROR;
+ case NOTIFICATION_CREDENTIALS_REJECTED:
+ return notifier::NOTIFICATION_CREDENTIALS_REJECTED;
+ default:
+ NOTREACHED();
+ return notifier::TRANSIENT_NOTIFICATION_ERROR;
+ }
+}
+
} // namespace syncer
diff --git a/sync/notifier/notifications_disabled_reason.h b/sync/notifier/notifications_disabled_reason.h
index b30573b..40805aa 100644
--- a/sync/notifier/notifications_disabled_reason.h
+++ b/sync/notifier/notifications_disabled_reason.h
@@ -27,6 +27,9 @@ const char* NotificationsDisabledReasonToString(
NotificationsDisabledReason FromNotifierReason(
notifier::NotificationsDisabledReason reason);
+notifier::NotificationsDisabledReason ToNotifierReasonForTest(
+ NotificationsDisabledReason reason);
+
} // namespace syncer
#endif // SYNC_NOTIFIER_NOTIFICATIONS_DISABLED_REASON_H_
diff --git a/sync/notifier/object_id_state_map.cc b/sync/notifier/object_id_state_map.cc
index 2d3b7f7..c673ed8 100644
--- a/sync/notifier/object_id_state_map.cc
+++ b/sync/notifier/object_id_state_map.cc
@@ -4,6 +4,11 @@
#include "sync/notifier/object_id_state_map.h"
+#include <algorithm>
+
+#include "base/compiler_specific.h"
+#include "base/values.h"
+
namespace syncer {
ObjectIdSet ObjectIdStateMapToSet(const ObjectIdStateMap& id_state_map) {
@@ -25,6 +30,62 @@ ObjectIdStateMap ObjectIdSetToStateMap(const ObjectIdSet& ids,
return id_state_map;
}
+namespace {
+
+struct ObjectIdStateMapValueEquals {
+ bool operator()(const ObjectIdStateMap::value_type& value1,
+ const ObjectIdStateMap::value_type& value2) const {
+ return
+ (value1.first == value2.first) &&
+ value1.second.Equals(value2.second);
+ }
+};
+
+} // namespace
+
+bool ObjectIdStateMapEquals(const ObjectIdStateMap& id_state_map1,
+ const ObjectIdStateMap& id_state_map2) {
+ return
+ (id_state_map1.size() == id_state_map2.size()) &&
+ std::equal(id_state_map1.begin(), id_state_map1.end(),
+ id_state_map2.begin(), ObjectIdStateMapValueEquals());
+}
+
+scoped_ptr<base::ListValue> ObjectIdStateMapToValue(
+ const ObjectIdStateMap& id_state_map) {
+ scoped_ptr<ListValue> value(new ListValue());
+ for (ObjectIdStateMap::const_iterator it = id_state_map.begin();
+ it != id_state_map.end(); ++it) {
+ DictionaryValue* entry = new DictionaryValue();
+ entry->Set("objectId", ObjectIdToValue(it->first).release());
+ entry->Set("state", it->second.ToValue().release());
+ value->Append(entry);
+ }
+ return value.Pass();
+}
+
+bool ObjectIdStateMapFromValue(const base::ListValue& value,
+ ObjectIdStateMap* out) {
+ out->clear();
+ for (base::ListValue::const_iterator it = value.begin();
+ it != value.end(); ++it) {
+ const base::DictionaryValue* entry = NULL;
+ const base::DictionaryValue* id_value = NULL;
+ const base::DictionaryValue* state_value = NULL;
+ invalidation::ObjectId id;
+ InvalidationState state;
+ if (!(*it)->GetAsDictionary(&entry) ||
+ !entry->GetDictionary("objectId", &id_value) ||
+ !entry->GetDictionary("state", &state_value) ||
+ !ObjectIdFromValue(*id_value, &id) ||
+ !state.ResetFromValue(*state_value)) {
+ return false;
+ }
+ ignore_result(out->insert(std::make_pair(id, state)));
+ }
+ return true;
+}
+
ModelTypeStateMap ObjectIdStateMapToModelTypeStateMap(
const ObjectIdStateMap& id_state_map) {
ModelTypeStateMap type_state_map;
diff --git a/sync/notifier/object_id_state_map.h b/sync/notifier/object_id_state_map.h
index 17f8ceb..1e9513e 100644
--- a/sync/notifier/object_id_state_map.h
+++ b/sync/notifier/object_id_state_map.h
@@ -8,11 +8,16 @@
#include <map>
#include <string>
+#include "base/memory/scoped_ptr.h"
#include "google/cacheinvalidation/include/types.h"
#include "sync/internal_api/public/base/invalidation_state.h"
#include "sync/internal_api/public/base/model_type_state_map.h"
#include "sync/notifier/invalidation_util.h"
+namespace base {
+class ListValue;
+} // namespace base
+
namespace syncer {
typedef std::map<invalidation::ObjectId,
@@ -24,6 +29,15 @@ ObjectIdSet ObjectIdStateMapToSet(const ObjectIdStateMap& id_payloads);
ObjectIdStateMap ObjectIdSetToStateMap(const ObjectIdSet& ids,
const std::string& payload);
+bool ObjectIdStateMapEquals(const ObjectIdStateMap& id_state_map1,
+ const ObjectIdStateMap& id_state_map2);
+
+scoped_ptr<base::ListValue> ObjectIdStateMapToValue(
+ const ObjectIdStateMap& model_type_payloads);
+
+bool ObjectIdStateMapFromValue(const base::ListValue& value,
+ ObjectIdStateMap* out);
+
// Converts between ObjectIdStateMaps and ModelTypeStateMaps.
ModelTypeStateMap ObjectIdStateMapToModelTypeStateMap(
const ObjectIdStateMap& id_payloads);
diff --git a/sync/notifier/p2p_invalidator.cc b/sync/notifier/p2p_invalidator.cc
index 34822ff..38c81fb 100644
--- a/sync/notifier/p2p_invalidator.cc
+++ b/sync/notifier/p2p_invalidator.cc
@@ -17,7 +17,7 @@
namespace syncer {
-const char* kSyncP2PNotificationChannel = "http://www.google.com/chrome/sync";
+const char kSyncP2PNotificationChannel[] = "http://www.google.com/chrome/sync";
namespace {
@@ -27,7 +27,8 @@ const char kNotifyAll[] = "notifyAll";
const char kSenderIdKey[] = "senderId";
const char kNotificationTypeKey[] = "notificationType";
-const char kChangedTypesKey[] = "changedTypes";
+const char kIdStateMapKey[] = "idStateMap";
+const char kSourceKey[] = "source";
} // namespace
@@ -60,15 +61,25 @@ P2PNotificationTarget P2PNotificationTargetFromString(
return NOTIFY_SELF;
}
-P2PNotificationData::P2PNotificationData() : target_(NOTIFY_SELF) {}
+IncomingNotificationSource P2PNotificationSourceFromInteger(int source_num) {
+ if (source_num == LOCAL_NOTIFICATION) {
+ return LOCAL_NOTIFICATION;
+ }
+ return REMOTE_NOTIFICATION;
+}
+
+P2PNotificationData::P2PNotificationData()
+ : target_(NOTIFY_SELF), source_(REMOTE_NOTIFICATION) {}
P2PNotificationData::P2PNotificationData(
const std::string& sender_id,
P2PNotificationTarget target,
- ModelTypeSet changed_types)
+ const ObjectIdStateMap& id_state_map,
+ IncomingNotificationSource source)
: sender_id_(sender_id),
target_(target),
- changed_types_(changed_types) {}
+ id_state_map_(id_state_map),
+ source_(source) {}
P2PNotificationData::~P2PNotificationData() {}
@@ -86,15 +97,20 @@ bool P2PNotificationData::IsTargeted(const std::string& id) const {
}
}
-ModelTypeSet P2PNotificationData::GetChangedTypes() const {
- return changed_types_;
+const ObjectIdStateMap& P2PNotificationData::GetIdStateMap() const {
+ return id_state_map_;
+}
+
+IncomingNotificationSource P2PNotificationData::GetSource() const {
+ return source_;
}
bool P2PNotificationData::Equals(const P2PNotificationData& other) const {
return
(sender_id_ == other.sender_id_) &&
(target_ == other.target_) &&
- changed_types_.Equals(other.changed_types_);
+ ObjectIdStateMapEquals(id_state_map_, other.id_state_map_) &&
+ (source_ == other.source_);
}
std::string P2PNotificationData::ToString() const {
@@ -102,7 +118,8 @@ std::string P2PNotificationData::ToString() const {
dict->SetString(kSenderIdKey, sender_id_);
dict->SetString(kNotificationTypeKey,
P2PNotificationTargetToString(target_));
- dict->Set(kChangedTypesKey, ModelTypeSetToValue(changed_types_));
+ dict->Set(kIdStateMapKey, ObjectIdStateMapToValue(id_state_map_).release());
+ dict->SetInteger(kSourceKey, source_);
std::string json;
base::JSONWriter::Write(dict.get(), &json);
return json;
@@ -110,18 +127,11 @@ std::string P2PNotificationData::ToString() const {
bool P2PNotificationData::ResetFromString(const std::string& str) {
scoped_ptr<Value> data_value(base::JSONReader::Read(str));
- if (!data_value.get()) {
- LOG(WARNING) << "Could not parse " << str;
- return false;
- }
- if (!data_value->IsType(Value::TYPE_DICTIONARY)) {
+ const base::DictionaryValue* data_dict = NULL;
+ if (!data_value.get() || !data_value->GetAsDictionary(&data_dict)) {
LOG(WARNING) << "Could not parse " << str << " as a dictionary";
return false;
}
- // TODO(akalin): Use Values::AsDictionary() when it becomes
- // available.
- DictionaryValue* data_dict =
- static_cast<DictionaryValue*>(data_value.get());
if (!data_dict->GetString(kSenderIdKey, &sender_id_)) {
LOG(WARNING) << "Could not find string value for " << kSenderIdKey;
}
@@ -131,13 +141,16 @@ bool P2PNotificationData::ResetFromString(const std::string& str) {
<< kNotificationTypeKey;
}
target_ = P2PNotificationTargetFromString(target_str);
- ListValue* changed_types_list = NULL;
- if (!data_dict->GetList(kChangedTypesKey, &changed_types_list)) {
- LOG(WARNING) << "Could not find list value for "
- << kChangedTypesKey;
- return false;
+ const base::ListValue* id_state_map_list = NULL;
+ if (!data_dict->GetList(kIdStateMapKey, &id_state_map_list) ||
+ !ObjectIdStateMapFromValue(*id_state_map_list, &id_state_map_)) {
+ LOG(WARNING) << "Could not parse " << kIdStateMapKey;
+ }
+ int source_num = 0;
+ if (!data_dict->GetInteger(kSourceKey, &source_num)) {
+ LOG(WARNING) << "Could not find integer value for " << kSourceKey;
}
- changed_types_ = ModelTypeSetFromValue(*changed_types_list);
+ source_ = P2PNotificationSourceFromInteger(source_num);
return true;
}
@@ -166,15 +179,17 @@ void P2PInvalidator::UpdateRegisteredIds(InvalidationHandler* handler,
const ObjectIdSet& ids) {
// TODO(akalin): Handle arbitrary object IDs (http://crbug.com/140411).
DCHECK(thread_checker_.CalledOnValidThread());
+ ObjectIdSet new_ids;
+ const ObjectIdSet& old_ids = registrar_.GetRegisteredIds(handler);
+ std::set_difference(ids.begin(), ids.end(),
+ old_ids.begin(), old_ids.end(),
+ std::inserter(new_ids, new_ids.end()),
+ ObjectIdLessThan());
registrar_.UpdateRegisteredIds(handler, ids);
- const ModelTypeSet enabled_types =
- ObjectIdSetToModelTypeSet(registrar_.GetAllRegisteredIds());
- const ModelTypeSet new_enabled_types =
- Difference(enabled_types, enabled_types_);
const P2PNotificationData notification_data(
- unique_id_, NOTIFY_SELF, new_enabled_types);
+ unique_id_, NOTIFY_SELF, ObjectIdSetToStateMap(new_ids, ""),
+ REMOTE_NOTIFICATION);
SendNotificationData(notification_data);
- enabled_types_ = enabled_types;
}
void P2PInvalidator::UnregisterHandler(InvalidationHandler* handler) {
@@ -209,10 +224,11 @@ void P2PInvalidator::UpdateCredentials(
logged_in_ = true;
}
-void P2PInvalidator::SendNotification(ModelTypeSet changed_types) {
+void P2PInvalidator::SendNotification(const ObjectIdStateMap& id_state_map) {
DCHECK(thread_checker_.CalledOnValidThread());
const P2PNotificationData notification_data(
- unique_id_, send_notification_target_, changed_types);
+ unique_id_, send_notification_target_, id_state_map,
+ REMOTE_NOTIFICATION);
SendNotificationData(notification_data);
}
@@ -223,7 +239,9 @@ void P2PInvalidator::OnNotificationsEnabled() {
registrar_.EmitOnNotificationsEnabled();
if (just_turned_on) {
const P2PNotificationData notification_data(
- unique_id_, NOTIFY_SELF, enabled_types_);
+ unique_id_, NOTIFY_SELF,
+ ObjectIdSetToStateMap(registrar_.GetAllRegisteredIds(), ""),
+ REMOTE_NOTIFICATION);
SendNotificationData(notification_data);
}
}
@@ -255,23 +273,18 @@ void P2PInvalidator::OnIncomingNotification(
LOG(WARNING) << "Could not parse notification data from "
<< notification.data;
notification_data =
- P2PNotificationData(unique_id_, NOTIFY_ALL, enabled_types_);
+ P2PNotificationData(
+ unique_id_, NOTIFY_ALL,
+ ObjectIdSetToStateMap(registrar_.GetAllRegisteredIds(), ""),
+ REMOTE_NOTIFICATION);
}
if (!notification_data.IsTargeted(unique_id_)) {
DVLOG(1) << "Not a target of the notification -- "
<< "not emitting notification";
return;
}
- const ModelTypeSet types_to_notify =
- Intersection(enabled_types_, notification_data.GetChangedTypes());
- if (types_to_notify.Empty()) {
- DVLOG(1) << "No enabled and changed types -- not emitting notification";
- return;
- }
- const ModelTypeStateMap& type_state_map = ModelTypeSetToStateMap(
- notification_data.GetChangedTypes(), std::string());
registrar_.DispatchInvalidationsToHandlers(
- ModelTypeStateMapToObjectIdStateMap(type_state_map),
+ notification_data.GetIdStateMap(),
REMOTE_NOTIFICATION);
}
@@ -284,8 +297,8 @@ void P2PInvalidator::SendNotificationDataForTest(
void P2PInvalidator::SendNotificationData(
const P2PNotificationData& notification_data) {
DCHECK(thread_checker_.CalledOnValidThread());
- if (notification_data.GetChangedTypes().Empty()) {
- DVLOG(1) << "Not sending XMPP notification with no changed types: "
+ if (notification_data.GetIdStateMap().empty()) {
+ DVLOG(1) << "Not sending XMPP notification with empty state map: "
<< notification_data.ToString();
return;
}
diff --git a/sync/notifier/p2p_invalidator.h b/sync/notifier/p2p_invalidator.h
index ce486ac..99d7fb81 100644
--- a/sync/notifier/p2p_invalidator.h
+++ b/sync/notifier/p2p_invalidator.h
@@ -29,7 +29,7 @@ class PushClient;
namespace syncer {
// The channel to use for sync notifications.
-extern const char* kSyncP2PNotificationChannel;
+extern const char kSyncP2PNotificationChannel[];
// The intended recipient(s) of a P2P notification.
enum P2PNotificationTarget {
@@ -56,14 +56,17 @@ class P2PNotificationData {
P2PNotificationData();
P2PNotificationData(const std::string& sender_id,
P2PNotificationTarget target,
- ModelTypeSet changed_types);
+ const ObjectIdStateMap& id_state_map,
+ IncomingNotificationSource source);
~P2PNotificationData();
// Returns true if the given ID is targeted by this notification.
bool IsTargeted(const std::string& id) const;
- ModelTypeSet GetChangedTypes() const;
+ const ObjectIdStateMap& GetIdStateMap() const;
+
+ IncomingNotificationSource GetSource() const;
bool Equals(const P2PNotificationData& other) const;
@@ -78,8 +81,10 @@ class P2PNotificationData {
std::string sender_id_;
// The intendent recipient(s) of the notification.
P2PNotificationTarget target_;
- // The types the notification is for.
- ModelTypeSet changed_types_;
+ // The state map for the notification.
+ ObjectIdStateMap id_state_map_;
+ // The source of the notification.
+ IncomingNotificationSource source_;
};
class P2PInvalidator : public Invalidator,
@@ -104,7 +109,7 @@ class P2PInvalidator : public Invalidator,
virtual void SetStateDeprecated(const std::string& state) OVERRIDE;
virtual void UpdateCredentials(
const std::string& email, const std::string& token) OVERRIDE;
- virtual void SendNotification(ModelTypeSet changed_types) OVERRIDE;
+ virtual void SendNotification(const ObjectIdStateMap& id_state_map) OVERRIDE;
// PushClientObserver implementation.
virtual void OnNotificationsEnabled() OVERRIDE;
@@ -133,8 +138,6 @@ class P2PInvalidator : public Invalidator,
// Which set of clients should be sent notifications.
P2PNotificationTarget send_notification_target_;
- ModelTypeSet enabled_types_;
-
DISALLOW_COPY_AND_ASSIGN(P2PInvalidator);
};
diff --git a/sync/notifier/p2p_invalidator_unittest.cc b/sync/notifier/p2p_invalidator_unittest.cc
index c169cdf..21abdf2 100644
--- a/sync/notifier/p2p_invalidator_unittest.cc
+++ b/sync/notifier/p2p_invalidator_unittest.cc
@@ -10,6 +10,7 @@
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/base/model_type_state_map.h"
#include "sync/notifier/fake_invalidation_handler.h"
+#include "sync/notifier/invalidator_test_template.h"
#include "sync/notifier/object_id_state_map_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -17,19 +18,83 @@ namespace syncer {
namespace {
+class P2PInvalidatorTestDelegate {
+ public:
+ P2PInvalidatorTestDelegate() : fake_push_client_(NULL) {}
+
+ ~P2PInvalidatorTestDelegate() {
+ DestroyInvalidator();
+ }
+
+ void CreateInvalidator(
+ const std::string& initial_state,
+ const base::WeakPtr<InvalidationStateTracker>&
+ invalidation_state_tracker) {
+ DCHECK(!fake_push_client_);
+ DCHECK(!invalidator_.get());
+ fake_push_client_ = new notifier::FakePushClient();
+ invalidator_.reset(
+ new P2PInvalidator(
+ scoped_ptr<notifier::PushClient>(fake_push_client_),
+ NOTIFY_OTHERS));
+ }
+
+ P2PInvalidator* GetInvalidator() {
+ return invalidator_.get();
+ }
+
+ notifier::FakePushClient* GetPushClient() {
+ return fake_push_client_;
+ }
+
+ void DestroyInvalidator() {
+ invalidator_.reset();
+ fake_push_client_ = NULL;
+ }
+
+ void WaitForInvalidator() {
+ // Do Nothing.
+ }
+
+ void TriggerOnNotificationsEnabled() {
+ fake_push_client_->EnableNotifications();
+ }
+
+ void TriggerOnIncomingNotification(const ObjectIdStateMap& id_state_map,
+ IncomingNotificationSource source) {
+ const P2PNotificationData notification_data(
+ "", NOTIFY_ALL, id_state_map, source);
+ notifier::Notification notification;
+ notification.channel = kSyncP2PNotificationChannel;
+ notification.data = notification_data.ToString();
+ fake_push_client_->SimulateIncomingNotification(notification);
+ }
+
+ void TriggerOnNotificationsDisabled(NotificationsDisabledReason reason) {
+ fake_push_client_->DisableNotifications(ToNotifierReasonForTest(reason));
+ }
+
+ static bool InvalidatorHandlesDeprecatedState() {
+ return false;
+ }
+
+ private:
+ // Owned by |invalidator_|.
+ notifier::FakePushClient* fake_push_client_;
+ scoped_ptr<P2PInvalidator> invalidator_;
+};
+
class P2PInvalidatorTest : public testing::Test {
protected:
P2PInvalidatorTest()
- : fake_push_client_(new notifier::FakePushClient()),
- p2p_notifier_(
- scoped_ptr<notifier::PushClient>(fake_push_client_),
- NOTIFY_OTHERS),
- next_sent_notification_to_reflect_(0) {
- p2p_notifier_.RegisterHandler(&fake_handler_);
+ : next_sent_notification_to_reflect_(0) {
+ delegate_.CreateInvalidator("fake_state",
+ base::WeakPtr<InvalidationStateTracker>());
+ delegate_.GetInvalidator()->RegisterHandler(&fake_handler_);
}
virtual ~P2PInvalidatorTest() {
- p2p_notifier_.UnregisterHandler(&fake_handler_);
+ delegate_.GetInvalidator()->UnregisterHandler(&fake_handler_);
}
ModelTypeStateMap MakeStateMap(ModelTypeSet types) {
@@ -40,18 +105,16 @@ class P2PInvalidatorTest : public testing::Test {
// time this was called.
void ReflectSentNotifications() {
const std::vector<notifier::Notification>& sent_notifications =
- fake_push_client_->sent_notifications();
+ delegate_.GetPushClient()->sent_notifications();
for(size_t i = next_sent_notification_to_reflect_;
i < sent_notifications.size(); ++i) {
- p2p_notifier_.OnIncomingNotification(sent_notifications[i]);
+ delegate_.GetInvalidator()->OnIncomingNotification(sent_notifications[i]);
}
next_sent_notification_to_reflect_ = sent_notifications.size();
}
- // Owned by |p2p_notifier_|.
- notifier::FakePushClient* fake_push_client_;
- P2PInvalidator p2p_notifier_;
FakeInvalidationHandler fake_handler_;
+ P2PInvalidatorTestDelegate delegate_;
private:
size_t next_sent_notification_to_reflect_;
@@ -73,21 +136,21 @@ TEST_F(P2PInvalidatorTest, P2PNotificationTarget) {
TEST_F(P2PInvalidatorTest, P2PNotificationDataIsTargeted) {
{
const P2PNotificationData notification_data(
- "sender", NOTIFY_SELF, ModelTypeSet());
+ "sender", NOTIFY_SELF, ObjectIdStateMap(), REMOTE_NOTIFICATION);
EXPECT_TRUE(notification_data.IsTargeted("sender"));
EXPECT_FALSE(notification_data.IsTargeted("other1"));
EXPECT_FALSE(notification_data.IsTargeted("other2"));
}
{
const P2PNotificationData notification_data(
- "sender", NOTIFY_OTHERS, ModelTypeSet());
+ "sender", NOTIFY_OTHERS, ObjectIdStateMap(), REMOTE_NOTIFICATION);
EXPECT_FALSE(notification_data.IsTargeted("sender"));
EXPECT_TRUE(notification_data.IsTargeted("other1"));
EXPECT_TRUE(notification_data.IsTargeted("other2"));
}
{
const P2PNotificationData notification_data(
- "sender", NOTIFY_ALL, ModelTypeSet());
+ "sender", NOTIFY_ALL, ObjectIdStateMap(), REMOTE_NOTIFICATION);
EXPECT_TRUE(notification_data.IsTargeted("sender"));
EXPECT_TRUE(notification_data.IsTargeted("other1"));
EXPECT_TRUE(notification_data.IsTargeted("other2"));
@@ -101,11 +164,11 @@ TEST_F(P2PInvalidatorTest, P2PNotificationDataDefault) {
EXPECT_TRUE(notification_data.IsTargeted(""));
EXPECT_FALSE(notification_data.IsTargeted("other1"));
EXPECT_FALSE(notification_data.IsTargeted("other2"));
- EXPECT_TRUE(notification_data.GetChangedTypes().Empty());
+ EXPECT_TRUE(notification_data.GetIdStateMap().empty());
const std::string& notification_data_str = notification_data.ToString();
EXPECT_EQ(
- "{\"changedTypes\":[],\"notificationType\":\"notifySelf\","
- "\"senderId\":\"\"}", notification_data_str);
+ "{\"idStateMap\":[],\"notificationType\":\"notifySelf\",\"senderId\":"
+ "\"\",\"source\":0}", notification_data_str);
P2PNotificationData notification_data_parsed;
EXPECT_TRUE(notification_data_parsed.ResetFromString(notification_data_str));
@@ -115,18 +178,24 @@ TEST_F(P2PInvalidatorTest, P2PNotificationDataDefault) {
// Make sure the P2PNotificationData <-> string conversions work for a
// non-default-constructed P2PNotificationData.
TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) {
- const ModelTypeSet changed_types(BOOKMARKS, THEMES);
+ const ObjectIdStateMap& id_state_map =
+ ObjectIdSetToStateMap(
+ ModelTypeSetToObjectIdSet(ModelTypeSet(BOOKMARKS, THEMES)), "");
const P2PNotificationData notification_data(
- "sender", NOTIFY_ALL, changed_types);
+ "sender", NOTIFY_ALL, id_state_map, LOCAL_NOTIFICATION);
EXPECT_TRUE(notification_data.IsTargeted("sender"));
EXPECT_TRUE(notification_data.IsTargeted("other1"));
EXPECT_TRUE(notification_data.IsTargeted("other2"));
- EXPECT_TRUE(notification_data.GetChangedTypes().Equals(changed_types));
+ EXPECT_THAT(id_state_map, Eq(notification_data.GetIdStateMap()));
const std::string& notification_data_str = notification_data.ToString();
EXPECT_EQ(
- "{\"changedTypes\":[\"Bookmarks\",\"Themes\"],"
- "\"notificationType\":\"notifyAll\","
- "\"senderId\":\"sender\"}", notification_data_str);
+ "{\"idStateMap\":["
+ "{\"objectId\":{\"name\":\"BOOKMARK\",\"source\":1004},"
+ "\"state\":{\"ackHandle\":{},\"payload\":\"\"}},"
+ "{\"objectId\":{\"name\":\"THEME\",\"source\":1004},"
+ "\"state\":{\"ackHandle\":{},\"payload\":\"\"}}"
+ "],\"notificationType\":\"notifyAll\","
+ "\"senderId\":\"sender\",\"source\":1}", notification_data_str);
P2PNotificationData notification_data_parsed;
EXPECT_TRUE(notification_data_parsed.ResetFromString(notification_data_str));
@@ -140,27 +209,30 @@ TEST_F(P2PInvalidatorTest, P2PNotificationDataNonDefault) {
TEST_F(P2PInvalidatorTest, NotificationsBasic) {
const ModelTypeSet enabled_types(BOOKMARKS, PREFERENCES);
- p2p_notifier_.UpdateRegisteredIds(&fake_handler_,
- ModelTypeSetToObjectIdSet(enabled_types));
+ P2PInvalidator* const invalidator = delegate_.GetInvalidator();
+ notifier::FakePushClient* const push_client = delegate_.GetPushClient();
- p2p_notifier_.SetUniqueId("sender");
+ invalidator->UpdateRegisteredIds(&fake_handler_,
+ ModelTypeSetToObjectIdSet(enabled_types));
+
+ invalidator->SetUniqueId("sender");
const char kEmail[] = "foo@bar.com";
const char kToken[] = "token";
- p2p_notifier_.UpdateCredentials(kEmail, kToken);
+ invalidator->UpdateCredentials(kEmail, kToken);
{
notifier::Subscription expected_subscription;
expected_subscription.channel = kSyncP2PNotificationChannel;
expected_subscription.from = kEmail;
EXPECT_TRUE(notifier::SubscriptionListsEqual(
- fake_push_client_->subscriptions(),
+ push_client->subscriptions(),
notifier::SubscriptionList(1, expected_subscription)));
}
- EXPECT_EQ(kEmail, fake_push_client_->email());
- EXPECT_EQ(kToken, fake_push_client_->token());
+ EXPECT_EQ(kEmail, push_client->email());
+ EXPECT_EQ(kToken, push_client->token());
ReflectSentNotifications();
- fake_push_client_->EnableNotifications();
+ push_client->EnableNotifications();
EXPECT_EQ(NO_NOTIFICATION_ERROR,
fake_handler_.GetNotificationsDisabledReason());
@@ -174,8 +246,10 @@ TEST_F(P2PInvalidatorTest, NotificationsBasic) {
// Sent with target NOTIFY_OTHERS so should not be propagated to
// |fake_handler_|.
{
- ModelTypeSet changed_types(THEMES, APPS);
- p2p_notifier_.SendNotification(changed_types);
+ const ObjectIdStateMap& id_state_map =
+ ObjectIdSetToStateMap(
+ ModelTypeSetToObjectIdSet(ModelTypeSet(THEMES, APPS)), "");
+ invalidator->SendNotification(id_state_map);
}
ReflectSentNotifications();
@@ -190,14 +264,21 @@ TEST_F(P2PInvalidatorTest, SendNotificationData) {
const ModelTypeSet changed_types(THEMES, APPS);
const ModelTypeSet expected_types(THEMES);
- p2p_notifier_.UpdateRegisteredIds(&fake_handler_,
- ModelTypeSetToObjectIdSet(enabled_types));
+ const ObjectIdStateMap& id_state_map =
+ ObjectIdSetToStateMap(
+ ModelTypeSetToObjectIdSet(changed_types), "");
+
+ P2PInvalidator* const invalidator = delegate_.GetInvalidator();
+ notifier::FakePushClient* const push_client = delegate_.GetPushClient();
- p2p_notifier_.SetUniqueId("sender");
- p2p_notifier_.UpdateCredentials("foo@bar.com", "fake_token");
+ invalidator->UpdateRegisteredIds(&fake_handler_,
+ ModelTypeSetToObjectIdSet(enabled_types));
+
+ invalidator->SetUniqueId("sender");
+ invalidator->UpdateCredentials("foo@bar.com", "fake_token");
ReflectSentNotifications();
- fake_push_client_->EnableNotifications();
+ push_client->EnableNotifications();
EXPECT_EQ(NO_NOTIFICATION_ERROR,
fake_handler_.GetNotificationsDisabledReason());
@@ -209,7 +290,7 @@ TEST_F(P2PInvalidatorTest, SendNotificationData) {
EXPECT_EQ(REMOTE_NOTIFICATION, fake_handler_.GetLastNotificationSource());
// Should be dropped.
- p2p_notifier_.SendNotificationDataForTest(P2PNotificationData());
+ invalidator->SendNotificationDataForTest(P2PNotificationData());
ReflectSentNotifications();
EXPECT_EQ(1, fake_handler_.GetNotificationCount());
@@ -217,8 +298,9 @@ TEST_F(P2PInvalidatorTest, SendNotificationData) {
ModelTypeStateMapToObjectIdStateMap(MakeStateMap(expected_types));
// Should be propagated.
- p2p_notifier_.SendNotificationDataForTest(
- P2PNotificationData("sender", NOTIFY_SELF, changed_types));
+ invalidator->SendNotificationDataForTest(
+ P2PNotificationData("sender", NOTIFY_SELF,
+ id_state_map, REMOTE_NOTIFICATION));
ReflectSentNotifications();
EXPECT_EQ(2, fake_handler_.GetNotificationCount());
EXPECT_THAT(
@@ -226,26 +308,30 @@ TEST_F(P2PInvalidatorTest, SendNotificationData) {
Eq(fake_handler_.GetLastNotificationIdStateMap()));
// Should be dropped.
- p2p_notifier_.SendNotificationDataForTest(
- P2PNotificationData("sender2", NOTIFY_SELF, changed_types));
+ invalidator->SendNotificationDataForTest(
+ P2PNotificationData("sender2", NOTIFY_SELF,
+ id_state_map, REMOTE_NOTIFICATION));
ReflectSentNotifications();
EXPECT_EQ(2, fake_handler_.GetNotificationCount());
// Should be dropped.
- p2p_notifier_.SendNotificationDataForTest(
- P2PNotificationData("sender", NOTIFY_SELF, ModelTypeSet()));
+ invalidator->SendNotificationDataForTest(
+ P2PNotificationData("sender", NOTIFY_SELF,
+ ObjectIdStateMap(), REMOTE_NOTIFICATION));
ReflectSentNotifications();
EXPECT_EQ(2, fake_handler_.GetNotificationCount());
// Should be dropped.
- p2p_notifier_.SendNotificationDataForTest(
- P2PNotificationData("sender", NOTIFY_OTHERS, changed_types));
+ invalidator->SendNotificationDataForTest(
+ P2PNotificationData("sender", NOTIFY_OTHERS,
+ id_state_map, REMOTE_NOTIFICATION));
ReflectSentNotifications();
EXPECT_EQ(2, fake_handler_.GetNotificationCount());
// Should be propagated.
- p2p_notifier_.SendNotificationDataForTest(
- P2PNotificationData("sender2", NOTIFY_OTHERS, changed_types));
+ invalidator->SendNotificationDataForTest(
+ P2PNotificationData("sender2", NOTIFY_OTHERS,
+ id_state_map, REMOTE_NOTIFICATION));
ReflectSentNotifications();
EXPECT_EQ(3, fake_handler_.GetNotificationCount());
EXPECT_THAT(
@@ -253,14 +339,16 @@ TEST_F(P2PInvalidatorTest, SendNotificationData) {
Eq(fake_handler_.GetLastNotificationIdStateMap()));
// Should be dropped.
- p2p_notifier_.SendNotificationDataForTest(
- P2PNotificationData("sender2", NOTIFY_OTHERS, ModelTypeSet()));
+ invalidator->SendNotificationDataForTest(
+ P2PNotificationData("sender2", NOTIFY_OTHERS,
+ ObjectIdStateMap(), REMOTE_NOTIFICATION));
ReflectSentNotifications();
EXPECT_EQ(3, fake_handler_.GetNotificationCount());
// Should be propagated.
- p2p_notifier_.SendNotificationDataForTest(
- P2PNotificationData("sender", NOTIFY_ALL, changed_types));
+ invalidator->SendNotificationDataForTest(
+ P2PNotificationData("sender", NOTIFY_ALL,
+ id_state_map, REMOTE_NOTIFICATION));
ReflectSentNotifications();
EXPECT_EQ(4, fake_handler_.GetNotificationCount());
EXPECT_THAT(
@@ -268,8 +356,9 @@ TEST_F(P2PInvalidatorTest, SendNotificationData) {
Eq(fake_handler_.GetLastNotificationIdStateMap()));
// Should be propagated.
- p2p_notifier_.SendNotificationDataForTest(
- P2PNotificationData("sender2", NOTIFY_ALL, changed_types));
+ invalidator->SendNotificationDataForTest(
+ P2PNotificationData("sender2", NOTIFY_ALL,
+ id_state_map, REMOTE_NOTIFICATION));
ReflectSentNotifications();
EXPECT_EQ(5, fake_handler_.GetNotificationCount());
EXPECT_THAT(
@@ -277,12 +366,17 @@ TEST_F(P2PInvalidatorTest, SendNotificationData) {
Eq(fake_handler_.GetLastNotificationIdStateMap()));
// Should be dropped.
- p2p_notifier_.SendNotificationDataForTest(
- P2PNotificationData("sender2", NOTIFY_ALL, ModelTypeSet()));
+ invalidator->SendNotificationDataForTest(
+ P2PNotificationData("sender2", NOTIFY_ALL,
+ ObjectIdStateMap(), REMOTE_NOTIFICATION));
ReflectSentNotifications();
EXPECT_EQ(5, fake_handler_.GetNotificationCount());
}
+INSTANTIATE_TYPED_TEST_CASE_P(
+ P2PInvalidatorTest, InvalidatorTest,
+ P2PInvalidatorTestDelegate);
+
} // namespace
} // namespace syncer
diff --git a/sync/sync.gyp b/sync/sync.gyp
index a5a9e80..9d68359 100644
--- a/sync/sync.gyp
+++ b/sync/sync.gyp
@@ -41,6 +41,7 @@
'sources': [
'base/sync_export.h',
'internal_api/public/base/enum_set.h',
+ 'internal_api/public/base/invalidation_state.cc',
'internal_api/public/base/invalidation_state.h',
'internal_api/public/base/model_type.h',
'internal_api/public/base/model_type_state_map.cc',
@@ -488,6 +489,7 @@
'notifier/fake_invalidator.h',
'notifier/fake_invalidation_handler.cc',
'notifier/fake_invalidation_handler.h',
+ 'notifier/invalidator_test_template.h',
'notifier/object_id_state_map_test_util.cc',
'notifier/object_id_state_map_test_util.h',
],
@@ -577,7 +579,6 @@
'test_support_sync',
],
'direct_dependent_settings': {
- 'variables': { 'enable_wexit_time_destructors': 1, },
'include_dirs': [
'..',
],
@@ -664,7 +665,6 @@
'test_support_sync_notifier',
],
'direct_dependent_settings': {
- 'variables': { 'enable_wexit_time_destructors': 1, },
'include_dirs': [
'..',
],
@@ -676,6 +676,7 @@
'sources': [
'notifier/chrome_invalidation_client_unittest.cc',
'notifier/chrome_system_resources_unittest.cc',
+ 'notifier/fake_invalidator_unittest.cc',
'notifier/invalidation_notifier_unittest.cc',
'notifier/invalidator_registrar_unittest.cc',
'notifier/non_blocking_invalidator_unittest.cc',
@@ -724,7 +725,6 @@
'test_support_syncapi_core',
],
'direct_dependent_settings': {
- 'variables': { 'enable_wexit_time_destructors': 1, },
'include_dirs': [
'..',
],
@@ -770,7 +770,6 @@
'test_support_syncapi_service',
],
'direct_dependent_settings': {
- 'variables': { 'enable_wexit_time_destructors': 1, },
'include_dirs': [
'..',
],
@@ -785,6 +784,8 @@
{
'target_name': 'sync_unit_tests',
'type': '<(gtest_target_type)',
+ # Typed-parametrized tests generate exit-time destructors.
+ 'variables': { 'enable_wexit_time_destructors': 0, },
'dependencies': [
'../base/base.gyp:run_all_unittests',
'sync_tests',