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_api.h" 6 7 #include "apps/launcher.h" 8 #include "base/strings/stringprintf.h" 9 #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h" 10 #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_mapper.h" 11 #include "chrome/browser/extensions/extension_apitest.h" 12 #include "chrome/browser/extensions/extension_test_message_listener.h" 13 #include "chrome/browser/invalidation/fake_invalidation_service.h" 14 #include "chrome/browser/invalidation/invalidation_service.h" 15 #include "chrome/browser/invalidation/invalidation_service_factory.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/ui/browser.h" 18 #include "chrome/common/chrome_switches.h" 19 #include "chrome/test/base/ui_test_utils.h" 20 #include "google/cacheinvalidation/types.pb.h" 21 #include "sync/notifier/fake_invalidator.h" 22 #include "testing/gmock/include/gmock/gmock.h" 23 24 using ::testing::_; 25 using ::testing::SaveArg; 26 using ::testing::StrictMock; 27 28 using invalidation::InvalidationServiceFactory; 29 30 namespace extensions { 31 32 namespace { 33 34 invalidation::ObjectId ExtensionAndSubchannelToObjectId( 35 const std::string& extension_id, int subchannel_id) { 36 return invalidation::ObjectId( 37 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, 38 base::StringPrintf("U/%s/%d", extension_id.c_str(), subchannel_id)); 39 } 40 41 class MockInvalidationMapper : public PushMessagingInvalidationMapper { 42 public: 43 MockInvalidationMapper(); 44 ~MockInvalidationMapper(); 45 46 MOCK_METHOD1(SuppressInitialInvalidationsForExtension, 47 void(const std::string&)); 48 MOCK_METHOD1(RegisterExtension, void(const std::string&)); 49 MOCK_METHOD1(UnregisterExtension, void(const std::string&)); 50 }; 51 52 MockInvalidationMapper::MockInvalidationMapper() {} 53 MockInvalidationMapper::~MockInvalidationMapper() {} 54 55 } // namespace 56 57 class PushMessagingApiTest : public ExtensionApiTest { 58 public: 59 PushMessagingApiTest() 60 : fake_invalidation_service_(NULL) { 61 } 62 63 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 64 ExtensionApiTest::SetUpCommandLine(command_line); 65 } 66 67 virtual void SetUp() OVERRIDE { 68 InvalidationServiceFactory::GetInstance()-> 69 SetBuildOnlyFakeInvalidatorsForTest(true); 70 ExtensionApiTest::SetUp(); 71 } 72 73 virtual void SetUpOnMainThread() OVERRIDE { 74 ExtensionApiTest::SetUpOnMainThread(); 75 fake_invalidation_service_ = 76 static_cast<invalidation::FakeInvalidationService*>( 77 InvalidationServiceFactory::GetInstance()->GetForProfile( 78 profile())); 79 } 80 81 void EmitInvalidation( 82 const invalidation::ObjectId& object_id, 83 const std::string& payload) { 84 fake_invalidation_service_->EmitInvalidationForTest( 85 object_id, 86 syncer::Invalidation::kUnknownVersion, 87 payload); 88 } 89 90 PushMessagingAPI* GetAPI() { 91 return PushMessagingAPI::Get(profile()); 92 } 93 94 PushMessagingEventRouter* GetEventRouter() { 95 return PushMessagingAPI::Get(profile())->GetEventRouterForTest(); 96 } 97 98 invalidation::FakeInvalidationService* fake_invalidation_service_; 99 }; 100 101 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, EventDispatch) { 102 ResultCatcher catcher; 103 catcher.RestrictToProfile(profile()); 104 105 const extensions::Extension* extension = 106 LoadExtension(test_data_dir_.AppendASCII("push_messaging")); 107 ASSERT_TRUE(extension); 108 ui_test_utils::NavigateToURL( 109 browser(), extension->GetResourceURL("event_dispatch.html")); 110 111 GetEventRouter()->TriggerMessageForTest(extension->id(), 1, "payload"); 112 113 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 114 } 115 116 // Test that a push introduced into the sync code makes it to the extension 117 // that we install. 118 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, ReceivesPush) { 119 ResultCatcher catcher; 120 catcher.RestrictToProfile(profile()); 121 122 const extensions::Extension* extension = 123 LoadExtension(test_data_dir_.AppendASCII("push_messaging")); 124 ASSERT_TRUE(extension); 125 ui_test_utils::NavigateToURL( 126 browser(), extension->GetResourceURL("event_dispatch.html")); 127 128 // PushMessagingInvalidationHandler suppresses the initial invalidation on 129 // each subchannel at install, so trigger the suppressions first. 130 for (int i = 0; i < 3; ++i) { 131 EmitInvalidation( 132 ExtensionAndSubchannelToObjectId(extension->id(), i), std::string()); 133 } 134 135 EmitInvalidation( 136 ExtensionAndSubchannelToObjectId(extension->id(), 1), "payload"); 137 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 138 } 139 140 // Checks that an extension with the pushMessaging permission gets automatically 141 // registered for invalidations when it is loaded. 142 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, AutoRegistration) { 143 scoped_ptr<StrictMock<MockInvalidationMapper> > mapper( 144 new StrictMock<MockInvalidationMapper>); 145 StrictMock<MockInvalidationMapper>* unsafe_mapper = mapper.get(); 146 // PushMessagingEventRouter owns the mapper now. 147 GetAPI()->SetMapperForTest( 148 mapper.PassAs<PushMessagingInvalidationMapper>()); 149 150 std::string extension_id1; 151 std::string extension_id2; 152 EXPECT_CALL(*unsafe_mapper, SuppressInitialInvalidationsForExtension(_)) 153 .WillOnce(SaveArg<0>(&extension_id1)); 154 EXPECT_CALL(*unsafe_mapper, RegisterExtension(_)) 155 .WillOnce(SaveArg<0>(&extension_id2)); 156 const extensions::Extension* extension = 157 LoadExtension(test_data_dir_.AppendASCII("push_messaging")); 158 ASSERT_TRUE(extension); 159 EXPECT_EQ(extension->id(), extension_id1); 160 EXPECT_EQ(extension->id(), extension_id2); 161 EXPECT_CALL(*unsafe_mapper, UnregisterExtension(extension->id())); 162 UnloadExtension(extension->id()); 163 } 164 165 // Tests that we re-register for invalidations on restart for extensions that 166 // are already installed. 167 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, PRE_Restart) { 168 PushMessagingInvalidationHandler* handler = 169 static_cast<PushMessagingInvalidationHandler*>( 170 GetAPI()->GetMapperForTest()); 171 EXPECT_TRUE(handler->GetRegisteredExtensionsForTest().empty()); 172 ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("push_messaging"), 173 1 /* new install */)); 174 } 175 176 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, Restart) { 177 PushMessagingInvalidationHandler* handler = 178 static_cast<PushMessagingInvalidationHandler*>( 179 GetAPI()->GetMapperForTest()); 180 EXPECT_EQ(1U, handler->GetRegisteredExtensionsForTest().size()); 181 } 182 183 // Test that GetChannelId fails if no user is signed in. 184 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, GetChannelId) { 185 ResultCatcher catcher; 186 catcher.RestrictToProfile(profile()); 187 188 const extensions::Extension* extension = 189 LoadExtension(test_data_dir_.AppendASCII("push_messaging")); 190 ASSERT_TRUE(extension); 191 ui_test_utils::NavigateToURL( 192 browser(), extension->GetResourceURL("get_channel_id.html")); 193 194 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 195 } 196 197 } // namespace extensions 198