Home | History | Annotate | Download | only in push_messaging
      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/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"
     27 
     28 using ::testing::SaveArg;
     29 using ::testing::StrictMock;
     30 using ::testing::_;
     31 
     32 namespace content {
     33 class BrowserContext;
     34 }
     35 
     36 namespace extensions {
     37 
     38 namespace {
     39 
     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));
     45 }
     46 
     47 KeyedService* BuildFakeProfileInvalidationProvider(
     48     content::BrowserContext* context) {
     49   return new invalidation::ProfileInvalidationProvider(
     50       scoped_ptr<invalidation::InvalidationService>(
     51           new invalidation::FakeInvalidationService));
     52 }
     53 
     54 class MockInvalidationMapper : public PushMessagingInvalidationMapper {
     55  public:
     56   MockInvalidationMapper();
     57   ~MockInvalidationMapper();
     58 
     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&));
     63 };
     64 
     65 MockInvalidationMapper::MockInvalidationMapper() {}
     66 MockInvalidationMapper::~MockInvalidationMapper() {}
     67 
     68 }  // namespace
     69 
     70 class PushMessagingApiTest : public ExtensionApiTest {
     71  public:
     72   PushMessagingApiTest()
     73       : fake_invalidation_service_(NULL) {
     74   }
     75 
     76   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     77     ExtensionApiTest::SetUpCommandLine(command_line);
     78   }
     79 
     80   virtual void SetUp() OVERRIDE {
     81     invalidation::ProfileInvalidationProviderFactory::GetInstance()->
     82         RegisterTestingFactory(BuildFakeProfileInvalidationProvider);
     83     ExtensionApiTest::SetUp();
     84   }
     85 
     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());
     94   }
     95 
     96   void EmitInvalidation(
     97       const invalidation::ObjectId& object_id,
     98       int64 version,
     99       const std::string& payload) {
    100     fake_invalidation_service_->EmitInvalidationForTest(
    101         syncer::Invalidation::Init(object_id, version, payload));
    102   }
    103 
    104   PushMessagingAPI* GetAPI() {
    105     return PushMessagingAPI::Get(profile());
    106   }
    107 
    108   PushMessagingEventRouter* GetEventRouter() {
    109     return PushMessagingAPI::Get(profile())->GetEventRouterForTest();
    110   }
    111 
    112   invalidation::FakeInvalidationService* fake_invalidation_service_;
    113 };
    114 
    115 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, EventDispatch) {
    116   ResultCatcher catcher;
    117   catcher.RestrictToBrowserContext(profile());
    118 
    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"));
    124 
    125   GetEventRouter()->TriggerMessageForTest(extension->id(), 1, "payload");
    126 
    127   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
    128 }
    129 
    130 // Test that a push introduced into the sync code makes it to the extension
    131 // that we install.
    132 IN_PROC_BROWSER_TEST_F(PushMessagingApiTest, ReceivesPush) {
    133   ResultCatcher catcher;
    134   catcher.RestrictToBrowserContext(profile());
    135 
    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"));
    141 
    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) {
    145     EmitInvalidation(
    146         ExtensionAndSubchannelToObjectId(extension->id(), i), i, std::string());
    147   }
    148 
    149   EmitInvalidation(
    150       ExtensionAndSubchannelToObjectId(extension->id(), 1), 5, "payload");
    151   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
    152 }
    153 
    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>());
    163 
    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());
    177 }
    178 
    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 */));
    188 }
    189 
    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());
    195 }
    196 
    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());
    201 
    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"));
    207 
    208   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
    209 }
    210 
    211 }  // namespace extensions
    212