| // 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 "chrome/browser/extensions/api/push_messaging/push_messaging_api.h" |
| |
| #include "apps/launcher.h" |
| #include "base/strings/stringprintf.h" |
| #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h" |
| #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_mapper.h" |
| #include "chrome/browser/extensions/extension_apitest.h" |
| #include "chrome/browser/extensions/extension_test_message_listener.h" |
| #include "chrome/browser/invalidation/fake_invalidation_service.h" |
| #include "chrome/browser/invalidation/invalidation_service.h" |
| #include "chrome/browser/invalidation/invalidation_service_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "google/cacheinvalidation/types.pb.h" |
| #include "sync/notifier/fake_invalidator.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| |
| using ::testing::_; |
| using ::testing::SaveArg; |
| using ::testing::StrictMock; |
| |
| using invalidation::InvalidationServiceFactory; |
| |
| namespace extensions { |
| |
| namespace { |
| |
| invalidation::ObjectId ExtensionAndSubchannelToObjectId( |
| const std::string& extension_id, int subchannel_id) { |
| return invalidation::ObjectId( |
| ipc::invalidation::ObjectSource::CHROME_PUSH_MESSAGING, |
| base::StringPrintf("U/%s/%d", extension_id.c_str(), subchannel_id)); |
| } |
| |
| class MockInvalidationMapper : public PushMessagingInvalidationMapper { |
| public: |
| MockInvalidationMapper(); |
| ~MockInvalidationMapper(); |
| |
| MOCK_METHOD1(SuppressInitialInvalidationsForExtension, |
| void(const std::string&)); |
| MOCK_METHOD1(RegisterExtension, void(const std::string&)); |
| MOCK_METHOD1(UnregisterExtension, void(const std::string&)); |
| }; |
| |
| MockInvalidationMapper::MockInvalidationMapper() {} |
| MockInvalidationMapper::~MockInvalidationMapper() {} |
| |
| } // namespace |
| |
| class PushMessagingApiTest : public ExtensionApiTest { |
| public: |
| PushMessagingApiTest() |
| : fake_invalidation_service_(NULL) { |
| } |
| |
| virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
| ExtensionApiTest::SetUpCommandLine(command_line); |
| } |
| |
| virtual void SetUp() OVERRIDE { |
| InvalidationServiceFactory::GetInstance()-> |
| SetBuildOnlyFakeInvalidatorsForTest(true); |
| ExtensionApiTest::SetUp(); |
| } |
| |
| virtual void SetUpOnMainThread() OVERRIDE { |
| ExtensionApiTest::SetUpOnMainThread(); |
| fake_invalidation_service_ = |
| static_cast<invalidation::FakeInvalidationService*>( |
| InvalidationServiceFactory::GetInstance()->GetForProfile( |
| profile())); |
| } |
| |
| void EmitInvalidation( |
| const invalidation::ObjectId& object_id, |
| const std::string& payload) { |
| fake_invalidation_service_->EmitInvalidationForTest( |
| object_id, |
| syncer::Invalidation::kUnknownVersion, |
| payload); |
| } |
| |
| PushMessagingAPI* GetAPI() { |
| return PushMessagingAPI::Get(profile()); |
| } |
| |
| PushMessagingEventRouter* GetEventRouter() { |
| return PushMessagingAPI::Get(profile())->GetEventRouterForTest(); |
| } |
| |
| invalidation::FakeInvalidationService* fake_invalidation_service_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, EventDispatch) { |
| ResultCatcher catcher; |
| catcher.RestrictToProfile(profile()); |
| |
| const extensions::Extension* extension = |
| LoadExtension(test_data_dir_.AppendASCII("push_messaging")); |
| ASSERT_TRUE(extension); |
| ui_test_utils::NavigateToURL( |
| browser(), extension->GetResourceURL("event_dispatch.html")); |
| |
| GetEventRouter()->TriggerMessageForTest(extension->id(), 1, "payload"); |
| |
| EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); |
| } |
| |
| // Test that a push introduced into the sync code makes it to the extension |
| // that we install. |
| IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, ReceivesPush) { |
| ResultCatcher catcher; |
| catcher.RestrictToProfile(profile()); |
| |
| const extensions::Extension* extension = |
| LoadExtension(test_data_dir_.AppendASCII("push_messaging")); |
| ASSERT_TRUE(extension); |
| ui_test_utils::NavigateToURL( |
| browser(), extension->GetResourceURL("event_dispatch.html")); |
| |
| // PushMessagingInvalidationHandler suppresses the initial invalidation on |
| // each subchannel at install, so trigger the suppressions first. |
| for (int i = 0; i < 3; ++i) { |
| EmitInvalidation( |
| ExtensionAndSubchannelToObjectId(extension->id(), i), std::string()); |
| } |
| |
| EmitInvalidation( |
| ExtensionAndSubchannelToObjectId(extension->id(), 1), "payload"); |
| EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); |
| } |
| |
| // Checks that an extension with the pushMessaging permission gets automatically |
| // registered for invalidations when it is loaded. |
| IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, AutoRegistration) { |
| scoped_ptr<StrictMock<MockInvalidationMapper> > mapper( |
| new StrictMock<MockInvalidationMapper>); |
| StrictMock<MockInvalidationMapper>* unsafe_mapper = mapper.get(); |
| // PushMessagingEventRouter owns the mapper now. |
| GetAPI()->SetMapperForTest( |
| mapper.PassAs<PushMessagingInvalidationMapper>()); |
| |
| std::string extension_id1; |
| std::string extension_id2; |
| EXPECT_CALL(*unsafe_mapper, SuppressInitialInvalidationsForExtension(_)) |
| .WillOnce(SaveArg<0>(&extension_id1)); |
| EXPECT_CALL(*unsafe_mapper, RegisterExtension(_)) |
| .WillOnce(SaveArg<0>(&extension_id2)); |
| const extensions::Extension* extension = |
| LoadExtension(test_data_dir_.AppendASCII("push_messaging")); |
| ASSERT_TRUE(extension); |
| EXPECT_EQ(extension->id(), extension_id1); |
| EXPECT_EQ(extension->id(), extension_id2); |
| EXPECT_CALL(*unsafe_mapper, UnregisterExtension(extension->id())); |
| UnloadExtension(extension->id()); |
| } |
| |
| // Tests that we re-register for invalidations on restart for extensions that |
| // are already installed. |
| IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, PRE_Restart) { |
| PushMessagingInvalidationHandler* handler = |
| static_cast<PushMessagingInvalidationHandler*>( |
| GetAPI()->GetMapperForTest()); |
| EXPECT_TRUE(handler->GetRegisteredExtensionsForTest().empty()); |
| ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("push_messaging"), |
| 1 /* new install */)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, Restart) { |
| PushMessagingInvalidationHandler* handler = |
| static_cast<PushMessagingInvalidationHandler*>( |
| GetAPI()->GetMapperForTest()); |
| EXPECT_EQ(1U, handler->GetRegisteredExtensionsForTest().size()); |
| } |
| |
| // Test that GetChannelId fails if no user is signed in. |
| IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, GetChannelId) { |
| ResultCatcher catcher; |
| catcher.RestrictToProfile(profile()); |
| |
| const extensions::Extension* extension = |
| LoadExtension(test_data_dir_.AppendASCII("push_messaging")); |
| ASSERT_TRUE(extension); |
| ui_test_utils::NavigateToURL( |
| browser(), extension->GetResourceURL("get_channel_id.html")); |
| |
| EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); |
| } |
| |
| } // namespace extensions |