Index: sync/notifier/chrome_invalidation_client_unittest.cc |
diff --git a/sync/notifier/chrome_invalidation_client_unittest.cc b/sync/notifier/chrome_invalidation_client_unittest.cc |
index 98907a31412cbb93f8c2d5b7e85bf2632a3479e6..1cc9bc522630c195b14d8bbdbbd3ec098812797a 100644 |
--- a/sync/notifier/chrome_invalidation_client_unittest.cc |
+++ b/sync/notifier/chrome_invalidation_client_unittest.cc |
@@ -2,364 +2,763 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#include <cstddef> |
+#include <set> |
#include <string> |
+#include "base/compiler_specific.h" |
#include "base/message_loop.h" |
#include "google/cacheinvalidation/include/invalidation-client.h" |
#include "google/cacheinvalidation/include/types.h" |
-#include "google/cacheinvalidation/types.pb.h" |
#include "jingle/notifier/listener/fake_push_client.h" |
#include "sync/internal_api/public/util/weak_handle.h" |
#include "sync/notifier/chrome_invalidation_client.h" |
-#include "sync/notifier/mock_invalidation_state_tracker.h" |
-#include "testing/gmock/include/gmock/gmock.h" |
+#include "sync/notifier/fake_invalidation_state_tracker.h" |
+#include "sync/notifier/invalidation_util.h" |
#include "testing/gtest/include/gtest/gtest.h" |
namespace syncer { |
-using ::testing::_; |
-using ::testing::InSequence; |
-using ::testing::Return; |
-using ::testing::StrictMock; |
- |
namespace { |
+using invalidation::AckHandle; |
+using invalidation::ObjectId; |
+ |
const char kClientId[] = "client_id"; |
const char kClientInfo[] = "client_info"; |
+ |
const char kState[] = "state"; |
const char kNewState[] = "new_state"; |
+const char kPayload1[] = "payload1"; |
+const char kPayload2[] = "payload2"; |
+ |
+const int64 kMinVersion = FakeInvalidationStateTracker::kMinVersion; |
+const int64 kVersion1 = 1LL; |
+const int64 kVersion2 = 2LL; |
+ |
const int kChromeSyncSourceId = 1004; |
-class MockInvalidationClient : public invalidation::InvalidationClient { |
- public: |
- MOCK_METHOD0(Start, void()); |
- MOCK_METHOD0(Stop, void()); |
- MOCK_METHOD1(Register, void(const invalidation::ObjectId&)); |
- MOCK_METHOD1(Register, void(const std::vector<invalidation::ObjectId>&)); |
- MOCK_METHOD1(Unregister, void(const invalidation::ObjectId&)); |
- MOCK_METHOD1(Unregister, void(const std::vector<invalidation::ObjectId>&)); |
- MOCK_METHOD1(Acknowledge, void(const invalidation::AckHandle&)); |
+struct AckHandleLessThan { |
+ bool operator()(const AckHandle& lhs, const AckHandle& rhs) const { |
+ return lhs.handle_data() < rhs.handle_data(); |
+ } |
}; |
-class MockListener : public ChromeInvalidationClient::Listener { |
+typedef std::set<AckHandle, AckHandleLessThan> AckHandleSet; |
+ |
+// Fake invalidation::InvalidationClient implementation that keeps |
+// track of registered IDs and acked handles. |
+class FakeInvalidationClient : public invalidation::InvalidationClient { |
public: |
- MOCK_METHOD1(OnInvalidate, void(const ObjectIdPayloadMap&)); |
- MOCK_METHOD0(OnNotificationsEnabled, void()); |
- MOCK_METHOD1(OnNotificationsDisabled, void(NotificationsDisabledReason)); |
+ FakeInvalidationClient() : started_(false) {} |
+ virtual ~FakeInvalidationClient() {} |
+ |
+ const ObjectIdSet& GetRegisteredIds() const { |
+ return registered_ids_; |
+ } |
+ |
+ void ClearAckedHandles() { |
+ acked_handles_.clear(); |
+ } |
+ |
+ bool IsAckedHandle(const AckHandle& ack_handle) const { |
+ return (acked_handles_.find(ack_handle) != acked_handles_.end()); |
+ } |
+ |
+ // invalidation::InvalidationClient implementation. |
+ |
+ virtual void Start() OVERRIDE { |
+ started_ = true; |
+ } |
+ |
+ virtual void Stop() OVERRIDE { |
+ started_ = false; |
+ } |
+ |
+ virtual void Register(const ObjectId& object_id) OVERRIDE { |
+ if (!started_) { |
+ ADD_FAILURE(); |
+ return; |
+ } |
+ registered_ids_.insert(object_id); |
+ } |
+ |
+ virtual void Register( |
+ const invalidation::vector<ObjectId>& object_ids) OVERRIDE { |
+ if (!started_) { |
+ ADD_FAILURE(); |
+ return; |
+ } |
+ registered_ids_.insert(object_ids.begin(), object_ids.end()); |
+ } |
+ |
+ virtual void Unregister(const ObjectId& object_id) OVERRIDE { |
+ if (!started_) { |
+ ADD_FAILURE(); |
+ return; |
+ } |
+ registered_ids_.erase(object_id); |
+ } |
+ |
+ virtual void Unregister( |
+ const invalidation::vector<ObjectId>& object_ids) OVERRIDE { |
+ if (!started_) { |
+ ADD_FAILURE(); |
+ return; |
+ } |
+ for (invalidation::vector<ObjectId>::const_iterator |
+ it = object_ids.begin(); it != object_ids.end(); ++it) { |
+ registered_ids_.erase(*it); |
+ } |
+ } |
+ |
+ virtual void Acknowledge(const AckHandle& ack_handle) OVERRIDE { |
+ if (!started_) { |
+ ADD_FAILURE(); |
+ return; |
+ } |
+ acked_handles_.insert(ack_handle); |
+ } |
+ |
+ private: |
+ bool started_; |
+ ObjectIdSet registered_ids_; |
+ AckHandleSet acked_handles_; |
}; |
-ObjectIdSet MakeSetFromId(const invalidation::ObjectId& id) { |
- ObjectIdSet ids; |
- ids.insert(id); |
- return ids; |
-} |
+// Fake listener tkat keeps track of invalidation counts, payloads, |
+// and state. |
+class FakeListener : public ChromeInvalidationClient::Listener { |
+ public: |
+ FakeListener() : reason_(TRANSIENT_NOTIFICATION_ERROR) {} |
+ virtual ~FakeListener() {} |
-ObjectIdPayloadMap ObjectIdsAndPayloadToMap(const ObjectIdSet& ids, |
- const std::string& payload) { |
- ObjectIdPayloadMap id_payloads; |
- for (ObjectIdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) { |
- id_payloads[*it] = payload; |
+ int GetInvalidationCount(const ObjectId& id) const { |
+ ObjectIdCountMap::const_iterator it = invalidation_counts_.find(id); |
+ return (it == invalidation_counts_.end()) ? 0 : it->second; |
} |
- return id_payloads; |
-} |
-} // namespace |
+ std::string GetPayload(const ObjectId& id) const { |
+ ObjectIdPayloadMap::const_iterator it = payloads_.find(id); |
+ return (it == payloads_.end()) ? "" : it->second; |
+ } |
+ |
+ // NO_NOTIFICATION_ERROR is the enabled state. |
+ NotificationsDisabledReason GetNotificationsDisabledReason() const { |
+ return reason_; |
+ } |
+ |
+ // ChromeInvalidationClient::Listener implementation. |
+ |
+ virtual void OnInvalidate(const ObjectIdPayloadMap& id_payloads) OVERRIDE { |
+ for (ObjectIdPayloadMap::const_iterator it = id_payloads.begin(); |
+ it != id_payloads.end(); ++it) { |
+ ++invalidation_counts_[it->first]; |
+ payloads_[it->first] = it->second; |
+ } |
+ } |
+ |
+ virtual void OnNotificationsEnabled() { |
+ reason_ = NO_NOTIFICATION_ERROR; |
+ } |
+ |
+ virtual void OnNotificationsDisabled(NotificationsDisabledReason reason) { |
+ reason_ = reason; |
+ } |
+ |
+ private: |
+ typedef std::map<ObjectId, int, ObjectIdLessThan> ObjectIdCountMap; |
+ ObjectIdCountMap invalidation_counts_; |
+ ObjectIdPayloadMap payloads_; |
+ NotificationsDisabledReason reason_; |
+}; |
+ |
+invalidation::InvalidationClient* CreateFakeInvalidationClient( |
+ FakeInvalidationClient** fake_invalidation_client, |
+ invalidation::SystemResources* resources, |
+ int client_type, |
+ const invalidation::string& client_name, |
+ const invalidation::string& application_name, |
+ invalidation::InvalidationListener* listener) { |
+ *fake_invalidation_client = new FakeInvalidationClient(); |
+ return *fake_invalidation_client; |
+} |
class ChromeInvalidationClientTest : public testing::Test { |
protected: |
ChromeInvalidationClientTest() |
- : fake_push_client_(new notifier::FakePushClient()), |
- client_(scoped_ptr<notifier::PushClient>(fake_push_client_)), |
- kBookmarksId_(kChromeSyncSourceId, "BOOKMARK"), |
+ : kBookmarksId_(kChromeSyncSourceId, "BOOKMARK"), |
kPreferencesId_(kChromeSyncSourceId, "PREFERENCE"), |
kExtensionsId_(kChromeSyncSourceId, "EXTENSION"), |
- kAppsId_(kChromeSyncSourceId, "APP") {} |
+ kAppsId_(kChromeSyncSourceId, "APP"), |
+ fake_push_client_(new notifier::FakePushClient()), |
+ fake_invalidation_client_(NULL), |
+ client_(scoped_ptr<notifier::PushClient>(fake_push_client_)) {} |
virtual void SetUp() { |
- client_.Start(kClientId, kClientInfo, kState, |
- InvalidationVersionMap(), |
- MakeWeakHandle(mock_invalidation_state_tracker_.AsWeakPtr()), |
- &mock_listener_); |
+ StartClient(); |
+ |
+ registered_ids_.insert(kBookmarksId_); |
+ registered_ids_.insert(kPreferencesId_); |
+ client_.UpdateRegisteredIds(registered_ids_); |
} |
virtual void TearDown() { |
- // client_.Stop() stops the invalidation 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. |
- // client_.Stop() does not schedule any tasks, so it's both necessary and |
- // sufficient to drain the task queue before calling it. |
- message_loop_.RunAllPending(); |
- client_.Stop(); |
+ StopClient(); |
} |
- // |payload| can be NULL, but not |type_name|. |
- void FireInvalidate(const char* type_name, |
+ // Restart client without re-registering IDs. |
+ void RestartClient() { |
+ StopClient(); |
+ StartClient(); |
+ } |
+ |
+ int GetInvalidationCount(const ObjectId& id) const { |
+ return fake_listener_.GetInvalidationCount(id); |
+ } |
+ |
+ std::string GetPayload(const ObjectId& id) const { |
+ return fake_listener_.GetPayload(id); |
+ } |
+ |
+ NotificationsDisabledReason GetNotificationsDisabledReason() const { |
+ return fake_listener_.GetNotificationsDisabledReason(); |
+ } |
+ |
+ int64 GetMaxVersion(const ObjectId& id) const { |
+ return fake_tracker_.GetMaxVersion(id); |
+ } |
+ |
+ std::string GetInvalidationState() const { |
+ return fake_tracker_.GetInvalidationState(); |
+ } |
+ |
+ ObjectIdSet GetRegisteredIds() const { |
+ return fake_invalidation_client_->GetRegisteredIds(); |
+ } |
+ |
+ // |payload| can be NULL. |
+ void FireInvalidate(const ObjectId& object_id, |
int64 version, const char* payload) { |
- const invalidation::ObjectId object_id( |
- ipc::invalidation::ObjectSource::CHROME_SYNC, type_name); |
- std::string payload_tmp = payload ? payload : ""; |
invalidation::Invalidation inv; |
if (payload) { |
inv = invalidation::Invalidation(object_id, version, payload); |
} else { |
inv = invalidation::Invalidation(object_id, version); |
} |
- invalidation::AckHandle ack_handle("fakedata"); |
- EXPECT_CALL(mock_invalidation_client_, Acknowledge(ack_handle)); |
- client_.Invalidate(&mock_invalidation_client_, inv, ack_handle); |
+ const AckHandle ack_handle("fakedata"); |
+ fake_invalidation_client_->ClearAckedHandles(); |
+ client_.Invalidate(fake_invalidation_client_, inv, ack_handle); |
+ EXPECT_TRUE(fake_invalidation_client_->IsAckedHandle(ack_handle)); |
// Pump message loop to trigger |
// InvalidationStateTracker::SetMaxVersion(). |
message_loop_.RunAllPending(); |
} |
// |payload| can be NULL, but not |type_name|. |
- void FireInvalidateUnknownVersion(const char* type_name) { |
- const invalidation::ObjectId object_id( |
- ipc::invalidation::ObjectSource::CHROME_SYNC, type_name); |
- |
- invalidation::AckHandle ack_handle("fakedata"); |
- EXPECT_CALL(mock_invalidation_client_, Acknowledge(ack_handle)); |
- client_.InvalidateUnknownVersion(&mock_invalidation_client_, object_id, |
+ void FireInvalidateUnknownVersion(const ObjectId& object_id) { |
+ const AckHandle ack_handle("fakedata_unknown"); |
+ fake_invalidation_client_->ClearAckedHandles(); |
+ client_.InvalidateUnknownVersion(fake_invalidation_client_, object_id, |
ack_handle); |
+ EXPECT_TRUE(fake_invalidation_client_->IsAckedHandle(ack_handle)); |
} |
void FireInvalidateAll() { |
- invalidation::AckHandle ack_handle("fakedata"); |
- EXPECT_CALL(mock_invalidation_client_, Acknowledge(ack_handle)); |
- client_.InvalidateAll(&mock_invalidation_client_, ack_handle); |
+ const AckHandle ack_handle("fakedata_all"); |
+ fake_invalidation_client_->ClearAckedHandles(); |
+ client_.InvalidateAll(fake_invalidation_client_, ack_handle); |
+ EXPECT_TRUE(fake_invalidation_client_->IsAckedHandle(ack_handle)); |
+ } |
+ |
+ void WriteState(const std::string& new_state) { |
+ client_.WriteState(new_state); |
+ // Pump message loop to trigger |
+ // InvalidationStateTracker::WriteState(). |
+ message_loop_.RunAllPending(); |
+ } |
+ |
+ void EnableNotifications() { |
+ fake_push_client_->EnableNotifications(); |
+ } |
+ |
+ void DisableNotifications(notifier::NotificationsDisabledReason reason) { |
+ fake_push_client_->DisableNotifications(reason); |
+ } |
+ |
+ const ObjectId kBookmarksId_; |
+ const ObjectId kPreferencesId_; |
+ const ObjectId kExtensionsId_; |
+ const ObjectId kAppsId_; |
+ |
+ ObjectIdSet registered_ids_; |
+ |
+ private: |
+ void StartClient() { |
+ fake_invalidation_client_ = NULL; |
+ client_.Start(base::Bind(&CreateFakeInvalidationClient, |
+ &fake_invalidation_client_), |
+ kClientId, kClientInfo, kState, |
+ InvalidationVersionMap(), |
+ MakeWeakHandle(fake_tracker_.AsWeakPtr()), |
+ &fake_listener_); |
+ DCHECK(fake_invalidation_client_); |
+ } |
+ |
+ void StopClient() { |
+ // client_.StopForTest() stops the invalidation 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. client_.StopForTest() does not |
+ // schedule any tasks, so it's both necessary and sufficient to |
+ // drain the task queue before calling it. |
+ message_loop_.RunAllPending(); |
+ fake_invalidation_client_ = NULL; |
+ client_.StopForTest(); |
} |
MessageLoop message_loop_; |
- StrictMock<MockListener> mock_listener_; |
- StrictMock<MockInvalidationStateTracker> |
- mock_invalidation_state_tracker_; |
- StrictMock<MockInvalidationClient> mock_invalidation_client_; |
+ |
+ FakeListener fake_listener_; |
+ FakeInvalidationStateTracker fake_tracker_; |
notifier::FakePushClient* const fake_push_client_; |
- ChromeInvalidationClient client_; |
- const invalidation::ObjectId kBookmarksId_; |
- const invalidation::ObjectId kPreferencesId_; |
- const invalidation::ObjectId kExtensionsId_; |
- const invalidation::ObjectId kAppsId_; |
+ protected: |
+ // Tests need to access these directly. |
+ FakeInvalidationClient* fake_invalidation_client_; |
+ ChromeInvalidationClient client_; |
}; |
-// Checks that we still dispatch an invalidation for something that's not |
-// currently registered (perhaps it was unregistered while it was still in |
-// flight). |
-TEST_F(ChromeInvalidationClientTest, InvalidateBadObjectId) { |
- ObjectIdSet ids; |
- ids.insert(kBookmarksId_); |
- ids.insert(kAppsId_); |
- client_.RegisterIds(ids); |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap( |
- MakeSetFromId(invalidation::ObjectId(kChromeSyncSourceId, "bad")), |
- std::string()))); |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetMaxVersion(invalidation::ObjectId(kChromeSyncSourceId, "bad"), |
- 1)); |
- FireInvalidate("bad", 1, NULL); |
+// Write a new state to the client. It should propagate to the |
+// tracker. |
+TEST_F(ChromeInvalidationClientTest, WriteState) { |
+ WriteState(kNewState); |
+ |
+ EXPECT_EQ(kNewState, GetInvalidationState()); |
} |
+// Invalidation tests. |
+ |
+// Fire an invalidation without a payload. It should be processed, |
+// the payload should remain empty, and the version should be updated. |
TEST_F(ChromeInvalidationClientTest, InvalidateNoPayload) { |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(MakeSetFromId(kBookmarksId_), std::string()))); |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetMaxVersion(kBookmarksId_, 1)); |
- FireInvalidate("BOOKMARK", 1, NULL); |
+ const ObjectId& id = kBookmarksId_; |
+ |
+ FireInvalidate(id, kVersion1, NULL); |
+ |
+ EXPECT_EQ(1, GetInvalidationCount(id)); |
+ EXPECT_EQ("", GetPayload(id)); |
+ EXPECT_EQ(kVersion1, GetMaxVersion(id)); |
+} |
+ |
+// Fire an invalidation with an empty payload. It should be |
+// processed, the payload should remain empty, and the version should |
+// be updated. |
+TEST_F(ChromeInvalidationClientTest, InvalidateEmptyPayload) { |
+ const ObjectId& id = kBookmarksId_; |
+ |
+ FireInvalidate(id, kVersion1, ""); |
+ |
+ EXPECT_EQ(1, GetInvalidationCount(id)); |
+ EXPECT_EQ("", GetPayload(id)); |
+ EXPECT_EQ(kVersion1, GetMaxVersion(id)); |
} |
+// Fire an invalidation with a payload. It should be processed, and |
+// both the payload and the version should be updated. |
TEST_F(ChromeInvalidationClientTest, InvalidateWithPayload) { |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(MakeSetFromId(kPreferencesId_), "payload"))); |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetMaxVersion(kPreferencesId_, 1)); |
- FireInvalidate("PREFERENCE", 1, "payload"); |
+ const ObjectId& id = kPreferencesId_; |
+ |
+ FireInvalidate(id, kVersion1, kPayload1); |
+ |
+ EXPECT_EQ(1, GetInvalidationCount(id)); |
+ EXPECT_EQ(kPayload1, GetPayload(id)); |
+ EXPECT_EQ(kVersion1, GetMaxVersion(id)); |
+} |
+ |
+// Fire an invalidation with a payload. It should still be processed, |
+// and both the payload and the version should be updated. |
+TEST_F(ChromeInvalidationClientTest, InvalidateUnregistered) { |
+ const ObjectId kUnregisteredId( |
+ kChromeSyncSourceId, "unregistered"); |
+ const ObjectId& id = kUnregisteredId; |
+ |
+ EXPECT_EQ(0, GetInvalidationCount(id)); |
+ EXPECT_EQ("", GetPayload(id)); |
+ EXPECT_EQ(kMinVersion, GetMaxVersion(id)); |
+ |
+ FireInvalidate(id, kVersion1, NULL); |
+ |
+ EXPECT_EQ(1, GetInvalidationCount(id)); |
+ EXPECT_EQ("", GetPayload(id)); |
+ EXPECT_EQ(kVersion1, GetMaxVersion(id)); |
} |
+// Fire an invalidation, then fire another one with a lower version. |
+// The first one should be processed and should update the payload and |
+// version, but the second one shouldn't. |
TEST_F(ChromeInvalidationClientTest, InvalidateVersion) { |
- using ::testing::Mock; |
+ const ObjectId& id = kPreferencesId_; |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(MakeSetFromId(kAppsId_), std::string()))); |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetMaxVersion(kAppsId_, 1)); |
+ FireInvalidate(id, kVersion2, kPayload2); |
- // Should trigger. |
- FireInvalidate("APP", 1, NULL); |
+ EXPECT_EQ(1, GetInvalidationCount(id)); |
+ EXPECT_EQ(kPayload2, GetPayload(id)); |
+ EXPECT_EQ(kVersion2, GetMaxVersion(id)); |
- Mock::VerifyAndClearExpectations(&mock_listener_); |
+ FireInvalidate(id, kVersion1, kPayload1); |
- // Should be dropped. |
- FireInvalidate("APP", 1, NULL); |
+ EXPECT_EQ(1, GetInvalidationCount(id)); |
+ EXPECT_EQ(kPayload2, GetPayload(id)); |
+ EXPECT_EQ(kVersion2, GetMaxVersion(id)); |
} |
+// Fire an invalidation with an unknown version twice. It shouldn't |
+// update the payload or version either time, but it should still be |
+// processed. |
TEST_F(ChromeInvalidationClientTest, InvalidateUnknownVersion) { |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(MakeSetFromId(kExtensionsId_), |
- std::string()))).Times(2); |
+ const ObjectId& id = kBookmarksId_; |
+ |
+ FireInvalidateUnknownVersion(id); |
+ |
+ EXPECT_EQ(1, GetInvalidationCount(id)); |
+ EXPECT_EQ("", GetPayload(id)); |
+ EXPECT_EQ(kMinVersion, GetMaxVersion(id)); |
+ |
+ FireInvalidateUnknownVersion(id); |
+ |
+ EXPECT_EQ(2, GetInvalidationCount(id)); |
+ EXPECT_EQ("", GetPayload(id)); |
+ EXPECT_EQ(kMinVersion, GetMaxVersion(id)); |
+} |
+ |
+// Fire an invalidation for all enabled IDs. It shouldn't update the |
+// payload or version, but it should still invalidate the IDs. |
+TEST_F(ChromeInvalidationClientTest, InvalidateAll) { |
+ FireInvalidateAll(); |
- // Should trigger twice. |
- FireInvalidateUnknownVersion("EXTENSION"); |
- FireInvalidateUnknownVersion("EXTENSION"); |
+ for (ObjectIdSet::const_iterator it = registered_ids_.begin(); |
+ it != registered_ids_.end(); ++it) { |
+ EXPECT_EQ(1, GetInvalidationCount(*it)); |
+ EXPECT_EQ("", GetPayload(*it)); |
+ EXPECT_EQ(kMinVersion, GetMaxVersion(*it)); |
+ } |
} |
-// Comprehensive test of various invalidations that we might receive from Tango |
-// and how they interact. |
-TEST_F(ChromeInvalidationClientTest, InvalidateVersionMultipleTypes) { |
- using ::testing::Mock; |
+// Comprehensive test of various scenarios for multiple IDs. |
+TEST_F(ChromeInvalidationClientTest, InvalidateMultipleIds) { |
+ FireInvalidate(kBookmarksId_, 3, NULL); |
+ |
+ EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_)); |
+ EXPECT_EQ("", GetPayload(kBookmarksId_)); |
+ EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); |
- ObjectIdSet ids; |
- ids.insert(kBookmarksId_); |
- ids.insert(kAppsId_); |
- client_.RegisterIds(ids); |
+ FireInvalidate(kExtensionsId_, 2, NULL); |
- // Initial invalidations to the client should be recorded and dispatched to |
- // the listener. |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(MakeSetFromId(kAppsId_), std::string()))); |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(MakeSetFromId(kExtensionsId_), std::string()))); |
+ EXPECT_EQ(1, GetInvalidationCount(kExtensionsId_)); |
+ EXPECT_EQ("", GetPayload(kExtensionsId_)); |
+ EXPECT_EQ(2, GetMaxVersion(kExtensionsId_)); |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetMaxVersion(kAppsId_, 3)); |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetMaxVersion(kExtensionsId_, 2)); |
+ // Invalidations with lower version numbers should be ignored. |
- FireInvalidate("APP", 3, NULL); |
- FireInvalidate("EXTENSION", 2, NULL); |
+ FireInvalidate(kBookmarksId_, 1, NULL); |
- Mock::VerifyAndClearExpectations(&mock_listener_); |
- Mock::VerifyAndClearExpectations(&mock_invalidation_state_tracker_); |
+ EXPECT_EQ(1, GetInvalidationCount(kBookmarksId_)); |
+ EXPECT_EQ("", GetPayload(kBookmarksId_)); |
+ EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); |
- // Out-of-order invalidations with lower version numbers should be ignored. |
- FireInvalidate("APP", 1, NULL); |
- FireInvalidate("EXTENSION", 1, NULL); |
+ FireInvalidate(kExtensionsId_, 1, NULL); |
- Mock::VerifyAndClearExpectations(&mock_listener_); |
- Mock::VerifyAndClearExpectations(&mock_invalidation_state_tracker_); |
+ EXPECT_EQ(1, GetInvalidationCount(kExtensionsId_)); |
+ EXPECT_EQ("", GetPayload(kExtensionsId_)); |
+ EXPECT_EQ(2, GetMaxVersion(kExtensionsId_)); |
// InvalidateAll shouldn't change any version state. |
- EXPECT_CALL(mock_listener_, |
- OnInvalidate(ObjectIdsAndPayloadToMap(ids, std::string()))); |
+ |
FireInvalidateAll(); |
- Mock::VerifyAndClearExpectations(&mock_listener_); |
- Mock::VerifyAndClearExpectations(&mock_invalidation_state_tracker_); |
- |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(MakeSetFromId(kPreferencesId_), std::string()))); |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(MakeSetFromId(kExtensionsId_), std::string()))); |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(MakeSetFromId(kAppsId_), std::string()))); |
- |
- // Normal invalidations with monotonically increasing version numbers. |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetMaxVersion(kPreferencesId_, 5)); |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetMaxVersion(kExtensionsId_, 3)); |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetMaxVersion(kAppsId_, 4)); |
- |
- // All three should be triggered. |
- FireInvalidate("PREFERENCE", 5, NULL); |
- FireInvalidate("EXTENSION", 3, NULL); |
- FireInvalidate("APP", 4, NULL); |
+ EXPECT_EQ(2, GetInvalidationCount(kBookmarksId_)); |
+ EXPECT_EQ("", GetPayload(kBookmarksId_)); |
+ EXPECT_EQ(3, GetMaxVersion(kBookmarksId_)); |
+ |
+ EXPECT_EQ(1, GetInvalidationCount(kPreferencesId_)); |
+ EXPECT_EQ("", GetPayload(kPreferencesId_)); |
+ EXPECT_EQ(kMinVersion, GetMaxVersion(kPreferencesId_)); |
+ |
+ EXPECT_EQ(1, GetInvalidationCount(kExtensionsId_)); |
+ EXPECT_EQ("", GetPayload(kExtensionsId_)); |
+ EXPECT_EQ(2, GetMaxVersion(kExtensionsId_)); |
+ |
+ // Invalidations with higher version numbers should be processed. |
+ |
+ FireInvalidate(kPreferencesId_, 5, NULL); |
+ EXPECT_EQ(2, GetInvalidationCount(kPreferencesId_)); |
+ EXPECT_EQ("", GetPayload(kPreferencesId_)); |
+ EXPECT_EQ(5, GetMaxVersion(kPreferencesId_)); |
+ |
+ FireInvalidate(kExtensionsId_, 3, NULL); |
+ EXPECT_EQ(2, GetInvalidationCount(kExtensionsId_)); |
+ EXPECT_EQ("", GetPayload(kExtensionsId_)); |
+ EXPECT_EQ(3, GetMaxVersion(kExtensionsId_)); |
+ |
+ FireInvalidate(kBookmarksId_, 4, NULL); |
+ EXPECT_EQ(3, GetInvalidationCount(kBookmarksId_)); |
+ EXPECT_EQ("", GetPayload(kBookmarksId_)); |
+ EXPECT_EQ(4, GetMaxVersion(kBookmarksId_)); |
} |
-TEST_F(ChromeInvalidationClientTest, InvalidateAll) { |
- ObjectIdSet ids; |
- ids.insert(kPreferencesId_); |
- ids.insert(kExtensionsId_); |
- client_.RegisterIds(ids); |
- EXPECT_CALL(mock_listener_, OnInvalidate( |
- ObjectIdsAndPayloadToMap(ids, std::string()))); |
- FireInvalidateAll(); |
+// Registration tests. |
+ |
+// With IDs already registered, enable notifications then ready the |
+// client. The IDs should be registered only after the client is |
+// readied. |
+TEST_F(ChromeInvalidationClientTest, RegisterEnableReady) { |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
} |
-TEST_F(ChromeInvalidationClientTest, RegisterTypes) { |
- ObjectIdSet ids; |
- ids.insert(kPreferencesId_); |
- ids.insert(kExtensionsId_); |
- client_.RegisterIds(ids); |
- // Registered types should be preserved across Stop/Start. |
- TearDown(); |
- SetUp(); |
- EXPECT_CALL(mock_listener_,OnInvalidate( |
- ObjectIdsAndPayloadToMap(ids, std::string()))); |
- FireInvalidateAll(); |
+// With IDs already registered, ready the client then enable |
+// notifications. The IDs should be registered after the client is |
+// readied. |
+TEST_F(ChromeInvalidationClientTest, RegisterReadyEnable) { |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
} |
-TEST_F(ChromeInvalidationClientTest, WriteState) { |
- EXPECT_CALL(mock_invalidation_state_tracker_, |
- SetInvalidationState(kNewState)); |
- client_.WriteState(kNewState); |
+// Unregister the IDs, enable notifications, re-register the IDs, then |
+// ready the client. The IDs should be registered only after the |
+// client is readied. |
+TEST_F(ChromeInvalidationClientTest, EnableRegisterReady) { |
+ client_.UpdateRegisteredIds(ObjectIdSet()); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.UpdateRegisteredIds(registered_ids_); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
} |
-TEST_F(ChromeInvalidationClientTest, StateChangesNotReady) { |
- InSequence dummy; |
- EXPECT_CALL(mock_listener_, |
- OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR)); |
- EXPECT_CALL(mock_listener_, |
- OnNotificationsDisabled(NOTIFICATION_CREDENTIALS_REJECTED)); |
- EXPECT_CALL(mock_listener_, |
- OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR)); |
+// Unregister the IDs, enable notifications, ready the client, then |
+// re-register the IDs. The IDs should be registered only after the |
+// client is readied. |
+TEST_F(ChromeInvalidationClientTest, EnableReadyRegister) { |
+ client_.UpdateRegisteredIds(ObjectIdSet()); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.UpdateRegisteredIds(registered_ids_); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
+} |
+ |
+// Unregister the IDs, ready the client, enable notifications, then |
+// re-register the IDs. The IDs should be registered only after the |
+// client is readied. |
+TEST_F(ChromeInvalidationClientTest, ReadyEnableRegister) { |
+ client_.UpdateRegisteredIds(ObjectIdSet()); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.UpdateRegisteredIds(registered_ids_); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
+} |
- fake_push_client_->DisableNotifications( |
+// Unregister the IDs, ready the client, re-register the IDs, then |
+// enable notifications. The IDs should be registered only after the |
+// client is readied. |
+// |
+// This test is important: see http://crbug.com/139424. |
+TEST_F(ChromeInvalidationClientTest, ReadyRegisterEnable) { |
+ client_.UpdateRegisteredIds(ObjectIdSet()); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.UpdateRegisteredIds(registered_ids_); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
+} |
+ |
+// With IDs already registered, ready the client, restart the client, |
+// then re-ready it. The IDs should still be registered. |
+TEST_F(ChromeInvalidationClientTest, RegisterTypesPreserved) { |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
+ |
+ RestartClient(); |
+ |
+ EXPECT_TRUE(GetRegisteredIds().empty()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_EQ(registered_ids_, GetRegisteredIds()); |
+} |
+ |
+// Without readying the client, disable notifications, then enable |
+// them. The listener should still think notifications are disabled. |
+TEST_F(ChromeInvalidationClientTest, EnableNotificationsNotReady) { |
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, |
+ GetNotificationsDisabledReason()); |
+ |
+ DisableNotifications( |
notifier::TRANSIENT_NOTIFICATION_ERROR); |
- fake_push_client_->DisableNotifications( |
+ |
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, |
+ GetNotificationsDisabledReason()); |
+ |
+ DisableNotifications( |
notifier::NOTIFICATION_CREDENTIALS_REJECTED); |
- fake_push_client_->EnableNotifications(); |
+ |
+ EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED, |
+ GetNotificationsDisabledReason()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, |
+ GetNotificationsDisabledReason()); |
} |
-TEST_F(ChromeInvalidationClientTest, StateChangesReady) { |
- InSequence dummy; |
- EXPECT_CALL(mock_listener_, |
- OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR)); |
- EXPECT_CALL(mock_listener_, OnNotificationsEnabled()); |
- EXPECT_CALL(mock_listener_, |
- OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR)); |
- EXPECT_CALL(mock_listener_, |
- OnNotificationsDisabled(NOTIFICATION_CREDENTIALS_REJECTED)); |
- EXPECT_CALL(mock_listener_, OnNotificationsEnabled()); |
- |
- fake_push_client_->EnableNotifications(); |
- client_.Ready(NULL); |
- fake_push_client_->DisableNotifications( |
- notifier::TRANSIENT_NOTIFICATION_ERROR); |
- fake_push_client_->DisableNotifications( |
+// Enable notifications then Ready the invalidation client. The |
+// listener should then be ready. |
+TEST_F(ChromeInvalidationClientTest, EnableNotificationsThenReady) { |
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_EQ(NO_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
+} |
+ |
+// Ready the invalidation client then enable notifications. The |
+// listener should then be ready. |
+TEST_F(ChromeInvalidationClientTest, ReadyThenEnableNotifications) { |
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_EQ(TRANSIENT_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_EQ(NO_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
+} |
+ |
+// Enable notifications and ready the client. Then disable |
+// notifications with an auth error and re-enable notifications. The |
+// listener should go into an auth error mode and then back out. |
+TEST_F(ChromeInvalidationClientTest, PushClientAuthError) { |
+ EnableNotifications(); |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_EQ(NO_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
+ |
+ DisableNotifications( |
notifier::NOTIFICATION_CREDENTIALS_REJECTED); |
- fake_push_client_->EnableNotifications(); |
+ |
+ EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED, |
+ GetNotificationsDisabledReason()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_EQ(NO_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
} |
-TEST_F(ChromeInvalidationClientTest, StateChangesAuthError) { |
- InSequence dummy; |
- EXPECT_CALL(mock_listener_, |
- OnNotificationsDisabled(TRANSIENT_NOTIFICATION_ERROR)); |
- EXPECT_CALL(mock_listener_, OnNotificationsEnabled()); |
- EXPECT_CALL(mock_listener_, |
- OnNotificationsDisabled(NOTIFICATION_CREDENTIALS_REJECTED)) |
- .Times(4); |
- EXPECT_CALL(mock_listener_, OnNotificationsEnabled()); |
+// Enable notifications and ready the client. Then simulate an auth |
+// error from the invalidation client. Simulate some notification |
+// events, then re-ready the client. The listener should go into an |
+// auth error mode and come out of it only after the client is ready. |
+TEST_F(ChromeInvalidationClientTest, InvalidationClientAuthError) { |
+ EnableNotifications(); |
+ client_.Ready(fake_invalidation_client_); |
- fake_push_client_->EnableNotifications(); |
- client_.Ready(NULL); |
+ EXPECT_EQ(NO_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
client_.InformError( |
- NULL, |
+ fake_invalidation_client_, |
invalidation::ErrorInfo( |
invalidation::ErrorReason::AUTH_FAILURE, |
false /* is_transient */, |
"auth error", |
invalidation::ErrorContext())); |
- fake_push_client_->DisableNotifications( |
+ |
+ EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED, |
+ GetNotificationsDisabledReason()); |
+ |
+ DisableNotifications( |
notifier::TRANSIENT_NOTIFICATION_ERROR); |
- fake_push_client_->DisableNotifications( |
- notifier::NOTIFICATION_CREDENTIALS_REJECTED); |
- fake_push_client_->EnableNotifications(); |
- client_.Ready(NULL); |
+ |
+ EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED, |
+ GetNotificationsDisabledReason()); |
+ |
+ DisableNotifications( |
+ notifier::TRANSIENT_NOTIFICATION_ERROR); |
+ |
+ EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED, |
+ GetNotificationsDisabledReason()); |
+ |
+ EnableNotifications(); |
+ |
+ EXPECT_EQ(NOTIFICATION_CREDENTIALS_REJECTED, |
+ GetNotificationsDisabledReason()); |
+ |
+ client_.Ready(fake_invalidation_client_); |
+ |
+ EXPECT_EQ(NO_NOTIFICATION_ERROR, GetNotificationsDisabledReason()); |
} |
+} // namespace |
+ |
} // namespace syncer |