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.
5 #include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h"
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/invalidation/fake_invalidation_service.h"
13 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/test/base/ui_test_utils.h"
18 #include "components/invalidation/fake_invalidator.h"
19 #include "components/invalidation/invalidation.h"
20 #include "components/invalidation/invalidation_service.h"
21 #include "components/invalidation/profile_invalidation_provider.h"
22 #include "components/keyed_service/core/keyed_service.h"
23 #include "extensions/test/extension_test_message_listener.h"
24 #include "extensions/test/result_catcher.h"
25 #include "google/cacheinvalidation/types.pb.h"
26 #include "testing/gmock/include/gmock/gmock.h"
28 using ::testing::SaveArg;
29 using ::testing::StrictMock;
36 namespace extensions {
40 invalidation::ObjectId ExtensionAndSubchannelToObjectId(
41 const std::string& extension_id, int subchannel_id) {
42 return invalidation::ObjectId(
43 ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING,
44 base::StringPrintf("U/%s/%d", extension_id.c_str(), subchannel_id));
47 KeyedService* BuildFakeProfileInvalidationProvider(
48 content::BrowserContext* context) {
49 return new invalidation::ProfileInvalidationProvider(
50 scoped_ptr<invalidation::InvalidationService>(
51 new invalidation::FakeInvalidationService));
54 class MockInvalidationMapper : public PushMessagingInvalidationMapper {
56 MockInvalidationMapper();
57 ~MockInvalidationMapper();
59 MOCK_METHOD1(SuppressInitialInvalidationsForExtension,
60 void(const std::string&));
61 MOCK_METHOD1(RegisterExtension, void(const std::string&));
62 MOCK_METHOD1(UnregisterExtension, void(const std::string&));
65 MockInvalidationMapper::MockInvalidationMapper() {}
66 MockInvalidationMapper::~MockInvalidationMapper() {}
70 class PushMessagingApiTest : public ExtensionApiTest {
72 PushMessagingApiTest()
73 : fake_invalidation_service_(NULL) {
76 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
77 ExtensionApiTest::SetUpCommandLine(command_line);
80 virtual void SetUp() OVERRIDE {
81 invalidation::ProfileInvalidationProviderFactory::GetInstance()->
82 RegisterTestingFactory(BuildFakeProfileInvalidationProvider);
83 ExtensionApiTest::SetUp();
86 virtual void SetUpOnMainThread() OVERRIDE {
87 ExtensionApiTest::SetUpOnMainThread();
88 fake_invalidation_service_ =
89 static_cast<invalidation::FakeInvalidationService*>(
90 static_cast<invalidation::ProfileInvalidationProvider*>(
91 invalidation::ProfileInvalidationProviderFactory::
92 GetInstance()->GetForProfile(profile()))->
93 GetInvalidationService());
96 void EmitInvalidation(
97 const invalidation::ObjectId& object_id,
99 const std::string& payload) {
100 fake_invalidation_service_->EmitInvalidationForTest(
101 syncer::Invalidation::Init(object_id, version, payload));
104 PushMessagingAPI* GetAPI() {
105 return PushMessagingAPI::Get(profile());
108 PushMessagingEventRouter* GetEventRouter() {
109 return PushMessagingAPI::Get(profile())->GetEventRouterForTest();
112 invalidation::FakeInvalidationService* fake_invalidation_service_;
115 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, EventDispatch) {
116 ResultCatcher catcher;
117 catcher.RestrictToBrowserContext(profile());
119 const extensions::Extension* extension =
120 LoadExtension(test_data_dir_.AppendASCII("push_messaging"));
121 ASSERT_TRUE(extension);
122 ui_test_utils::NavigateToURL(
123 browser(), extension->GetResourceURL("event_dispatch.html"));
125 GetEventRouter()->TriggerMessageForTest(extension->id(), 1, "payload");
127 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
130 // Test that a push introduced into the sync code makes it to the extension
132 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, ReceivesPush) {
133 ResultCatcher catcher;
134 catcher.RestrictToBrowserContext(profile());
136 const extensions::Extension* extension =
137 LoadExtension(test_data_dir_.AppendASCII("push_messaging"));
138 ASSERT_TRUE(extension);
139 ui_test_utils::NavigateToURL(
140 browser(), extension->GetResourceURL("event_dispatch.html"));
142 // PushMessagingInvalidationHandler suppresses the initial invalidation on
143 // each subchannel at install, so trigger the suppressions first.
144 for (int i = 0; i < 3; ++i) {
146 ExtensionAndSubchannelToObjectId(extension->id(), i), i, std::string());
150 ExtensionAndSubchannelToObjectId(extension->id(), 1), 5, "payload");
151 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
154 // Checks that an extension with the pushMessaging permission gets automatically
155 // registered for invalidations when it is loaded.
156 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, AutoRegistration) {
157 scoped_ptr<StrictMock<MockInvalidationMapper> > mapper(
158 new StrictMock<MockInvalidationMapper>);
159 StrictMock<MockInvalidationMapper>* unsafe_mapper = mapper.get();
160 // PushMessagingEventRouter owns the mapper now.
161 GetAPI()->SetMapperForTest(
162 mapper.PassAs<PushMessagingInvalidationMapper>());
164 std::string extension_id1;
165 std::string extension_id2;
166 EXPECT_CALL(*unsafe_mapper, SuppressInitialInvalidationsForExtension(_))
167 .WillOnce(SaveArg<0>(&extension_id1));
168 EXPECT_CALL(*unsafe_mapper, RegisterExtension(_))
169 .WillOnce(SaveArg<0>(&extension_id2));
170 const extensions::Extension* extension =
171 LoadExtension(test_data_dir_.AppendASCII("push_messaging"));
172 ASSERT_TRUE(extension);
173 EXPECT_EQ(extension->id(), extension_id1);
174 EXPECT_EQ(extension->id(), extension_id2);
175 EXPECT_CALL(*unsafe_mapper, UnregisterExtension(extension->id()));
176 UnloadExtension(extension->id());
179 // Tests that we re-register for invalidations on restart for extensions that
180 // are already installed.
181 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, PRE_Restart) {
182 PushMessagingInvalidationHandler* handler =
183 static_cast<PushMessagingInvalidationHandler*>(
184 GetAPI()->GetMapperForTest());
185 EXPECT_TRUE(handler->GetRegisteredExtensionsForTest().empty());
186 ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("push_messaging"),
187 1 /* new install */));
190 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, Restart) {
191 PushMessagingInvalidationHandler* handler =
192 static_cast<PushMessagingInvalidationHandler*>(
193 GetAPI()->GetMapperForTest());
194 EXPECT_EQ(1U, handler->GetRegisteredExtensionsForTest().size());
197 // Test that GetChannelId fails if no user is signed in.
198 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, GetChannelId) {
199 ResultCatcher catcher;
200 catcher.RestrictToBrowserContext(profile());
202 const extensions::Extension* extension =
203 LoadExtension(test_data_dir_.AppendASCII("push_messaging"));
204 ASSERT_TRUE(extension);
205 ui_test_utils::NavigateToURL(
206 browser(), extension->GetResourceURL("get_channel_id.html"));
208 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
211 } // namespace extensions