1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h" 6 7#include "base/basictypes.h" 8#include "base/callback.h" 9#include "base/memory/scoped_ptr.h" 10#include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler_delegate.h" 11#include "components/invalidation/invalidation_logger.h" 12#include "components/invalidation/invalidation_service.h" 13#include "components/invalidation/object_id_invalidation_map.h" 14#include "google/cacheinvalidation/types.pb.h" 15#include "testing/gmock/include/gmock/gmock.h" 16#include "testing/gtest/include/gtest/gtest.h" 17 18using ::testing::NotNull; 19using ::testing::SaveArg; 20using ::testing::StrictMock; 21using ::testing::_; 22 23namespace extensions { 24 25namespace { 26 27class MockInvalidationService : public invalidation::InvalidationService { 28 public: 29 MockInvalidationService(); 30 ~MockInvalidationService(); 31 MOCK_METHOD1(RegisterInvalidationHandler, 32 void(syncer::InvalidationHandler*)); 33 MOCK_METHOD2(UpdateRegisteredInvalidationIds, 34 void(syncer::InvalidationHandler*, const syncer::ObjectIdSet&)); 35 MOCK_METHOD1(UnregisterInvalidationHandler, 36 void(syncer::InvalidationHandler*)); 37 MOCK_CONST_METHOD0(GetInvalidatorState, syncer::InvalidatorState()); 38 MOCK_CONST_METHOD0(GetInvalidatorClientId, std::string()); 39 MOCK_METHOD0(GetInvalidationLogger, invalidation::InvalidationLogger*()); 40 MOCK_CONST_METHOD1(RequestDetailedStatus, 41 void(base::Callback<void(const base::DictionaryValue&)>)); 42 MOCK_METHOD0(GetIdentityProvider, IdentityProvider*()); 43 44 private: 45 DISALLOW_COPY_AND_ASSIGN(MockInvalidationService); 46}; 47 48MockInvalidationService::MockInvalidationService() {} 49MockInvalidationService::~MockInvalidationService() {} 50 51class MockInvalidationHandlerDelegate 52 : public PushMessagingInvalidationHandlerDelegate { 53 public: 54 MockInvalidationHandlerDelegate(); 55 ~MockInvalidationHandlerDelegate(); 56 MOCK_METHOD3(OnMessage, 57 void(const std::string&, int, const std::string&)); 58 59 private: 60 DISALLOW_COPY_AND_ASSIGN(MockInvalidationHandlerDelegate); 61}; 62 63MockInvalidationHandlerDelegate::MockInvalidationHandlerDelegate() {} 64MockInvalidationHandlerDelegate::~MockInvalidationHandlerDelegate() {} 65 66} // namespace 67 68class PushMessagingInvalidationHandlerTest : public ::testing::Test { 69 protected: 70 virtual void SetUp() OVERRIDE { 71 syncer::InvalidationHandler* handler = NULL; 72 EXPECT_CALL(service_, RegisterInvalidationHandler(NotNull())) 73 .WillOnce(SaveArg<0>(&handler)); 74 handler_.reset(new PushMessagingInvalidationHandler( 75 &service_, &delegate_)); 76 EXPECT_EQ(handler_.get(), handler); 77 } 78 virtual void TearDown() OVERRIDE { 79 EXPECT_CALL(service_, UnregisterInvalidationHandler(handler_.get())); 80 handler_.reset(); 81 } 82 StrictMock<MockInvalidationService> service_; 83 StrictMock<MockInvalidationHandlerDelegate> delegate_; 84 scoped_ptr<PushMessagingInvalidationHandler> handler_; 85}; 86 87TEST_F(PushMessagingInvalidationHandlerTest, RegisterUnregisterExtension) { 88 syncer::ObjectIdSet expected_ids; 89 expected_ids.insert(invalidation::ObjectId( 90 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 91 "U/cccccccccccccccccccccccccccccccc/0")); 92 expected_ids.insert(invalidation::ObjectId( 93 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 94 "U/cccccccccccccccccccccccccccccccc/1")); 95 expected_ids.insert(invalidation::ObjectId( 96 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 97 "U/cccccccccccccccccccccccccccccccc/2")); 98 expected_ids.insert(invalidation::ObjectId( 99 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 100 "U/cccccccccccccccccccccccccccccccc/3")); 101 EXPECT_CALL(service_, 102 UpdateRegisteredInvalidationIds(handler_.get(), expected_ids)); 103 handler_->RegisterExtension("cccccccccccccccccccccccccccccccc"); 104 EXPECT_CALL(service_, 105 UpdateRegisteredInvalidationIds(handler_.get(), 106 syncer::ObjectIdSet())); 107 handler_->UnregisterExtension("cccccccccccccccccccccccccccccccc"); 108} 109 110TEST_F(PushMessagingInvalidationHandlerTest, Dispatch) { 111 syncer::ObjectIdInvalidationMap invalidation_map; 112 // A normal invalidation. 113 invalidation_map.Insert( 114 syncer::Invalidation::Init( 115 invalidation::ObjectId( 116 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 117 "U/dddddddddddddddddddddddddddddddd/0"), 118 10, 119 "payload")); 120 121 // An unknown version invalidation. 122 invalidation_map.Insert(syncer::Invalidation::InitUnknownVersion( 123 invalidation::ObjectId( 124 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 125 "U/dddddddddddddddddddddddddddddddd/3"))); 126 127 EXPECT_CALL(delegate_, 128 OnMessage("dddddddddddddddddddddddddddddddd", 0, "payload")); 129 EXPECT_CALL(delegate_, 130 OnMessage("dddddddddddddddddddddddddddddddd", 3, "")); 131 handler_->OnIncomingInvalidation(invalidation_map); 132} 133 134// Tests that malformed object IDs don't trigger spurious callbacks. 135TEST_F(PushMessagingInvalidationHandlerTest, DispatchInvalidObjectIds) { 136 syncer::ObjectIdInvalidationMap invalidation_map; 137 // Completely incorrect format. 138 invalidation_map.Insert(syncer::Invalidation::InitUnknownVersion( 139 invalidation::ObjectId( 140 ipc::invalidation::ObjectSource::TEST, 141 "Invalid"))); 142 // Incorrect source. 143 invalidation_map.Insert(syncer::Invalidation::InitUnknownVersion( 144 invalidation::ObjectId( 145 ipc::invalidation::ObjectSource::TEST, 146 "U/dddddddddddddddddddddddddddddddd/3"))); 147 // Incorrect format type. 148 invalidation_map.Insert(syncer::Invalidation::InitUnknownVersion( 149 invalidation::ObjectId( 150 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 151 "V/dddddddddddddddddddddddddddddddd/3"))); 152 // Invalid extension ID length. 153 invalidation_map.Insert(syncer::Invalidation::InitUnknownVersion( 154 invalidation::ObjectId( 155 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 156 "U/ddddddddddddddddddddddddddddddddd/3"))); 157 // Non-numeric subchannel. 158 invalidation_map.Insert(syncer::Invalidation::InitUnknownVersion( 159 invalidation::ObjectId( 160 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 161 "U/dddddddddddddddddddddddddddddddd/z"))); 162 // Subchannel out of range. 163 invalidation_map.Insert(syncer::Invalidation::InitUnknownVersion( 164 invalidation::ObjectId( 165 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 166 "U/dddddddddddddddddddddddddddddddd/4"))); 167 handler_->OnIncomingInvalidation(invalidation_map); 168} 169 170// Test version filtering of incoming invalidations. 171TEST_F(PushMessagingInvalidationHandlerTest, InvalidationVersionsOutOfOrder) { 172 const invalidation::ObjectId id0( 173 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 174 "U/dddddddddddddddddddddddddddddddd/0"); 175 const invalidation::ObjectId id3( 176 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 177 "U/dddddddddddddddddddddddddddddddd/3"); 178 179 // The first received invalidation should get through. 180 syncer::ObjectIdInvalidationMap map1; 181 map1.Insert(syncer::Invalidation::Init(id0, 5, "5")); 182 EXPECT_CALL(delegate_, OnMessage("dddddddddddddddddddddddddddddddd", 0, "5")); 183 handler_->OnIncomingInvalidation(map1); 184 testing::Mock::VerifyAndClearExpectations(&delegate_); 185 186 // Invalid versions are always allowed through. 187 syncer::ObjectIdInvalidationMap map2; 188 map2.Insert(syncer::Invalidation::InitUnknownVersion(id0)); 189 EXPECT_CALL(delegate_, OnMessage("dddddddddddddddddddddddddddddddd", 0, "")); 190 handler_->OnIncomingInvalidation(map2); 191 testing::Mock::VerifyAndClearExpectations(&delegate_); 192 193 // An older version should not make it through. 194 syncer::ObjectIdInvalidationMap map3; 195 map3.Insert(syncer::Invalidation::Init(id0, 4, "4")); 196 handler_->OnIncomingInvalidation(map3); 197 198 // A newer version will make it through. 199 syncer::ObjectIdInvalidationMap map4; 200 map4.Insert(syncer::Invalidation::Init(id0, 6, "6")); 201 EXPECT_CALL(delegate_, OnMessage("dddddddddddddddddddddddddddddddd", 0, "6")); 202 handler_->OnIncomingInvalidation(map4); 203 testing::Mock::VerifyAndClearExpectations(&delegate_); 204 205 // An unrelated object should be unaffected by all the above. 206 syncer::ObjectIdInvalidationMap map5; 207 map5.Insert(syncer::Invalidation::Init(id3, 1, "1")); 208 EXPECT_CALL(delegate_, OnMessage("dddddddddddddddddddddddddddddddd", 3, "1")); 209 handler_->OnIncomingInvalidation(map5); 210 testing::Mock::VerifyAndClearExpectations(&delegate_); 211} 212 213} // namespace extensions 214