extension_gcm_app_handler_unittest.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1// Copyright 2014 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 "base/bind.h"
6#include "base/command_line.h"
7#include "base/prefs/pref_service.h"
8#include "chrome/browser/extensions/extension_gcm_app_handler.h"
9#include "chrome/browser/extensions/test_extension_service.h"
10#include "chrome/browser/extensions/test_extension_system.h"
11#include "chrome/browser/services/gcm/gcm_client_mock.h"
12#include "chrome/browser/services/gcm/gcm_profile_service.h"
13#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
14#include "chrome/browser/services/gcm/gcm_profile_service_test_helper.h"
15#include "chrome/browser/signin/signin_manager_factory.h"
16#include "chrome/common/pref_names.h"
17#include "chrome/test/base/testing_profile.h"
18#include "content/public/browser/browser_thread.h"
19#include "content/public/test/test_browser_thread_bundle.h"
20#include "extensions/common/extension.h"
21#include "extensions/common/manifest_constants.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24#if defined(OS_CHROMEOS)
25#include "chrome/browser/chromeos/login/user_manager.h"
26#include "chrome/browser/chromeos/settings/cros_settings.h"
27#include "chrome/browser/chromeos/settings/device_settings_service.h"
28#else
29#include "components/signin/core/browser/signin_manager.h"
30#endif
31
32using namespace gcm;
33
34namespace extensions {
35
36namespace {
37
38const char kTestExtensionName[] = "FooBar";
39const char kTestingUsername[] = "user1@example.com";
40
41}  // namespace
42
43class FakeExtensionGCMAppHandler : public ExtensionGCMAppHandler {
44 public:
45  FakeExtensionGCMAppHandler(Profile* profile, Waiter* waiter)
46      : ExtensionGCMAppHandler(profile),
47        waiter_(waiter),
48        unregistration_result_(GCMClient::UNKNOWN_ERROR) {
49  }
50
51  virtual ~FakeExtensionGCMAppHandler() {
52  }
53
54  virtual void OnMessage(
55      const std::string& app_id,
56      const GCMClient::IncomingMessage& message)OVERRIDE {
57  }
58
59  virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE {
60  }
61
62  virtual void OnSendError(
63      const std::string& app_id,
64      const GCMClient::SendErrorDetails& send_error_details) OVERRIDE {
65  }
66
67  virtual void OnUnregisterCompleted(const std::string& app_id,
68                                     GCMClient::Result result) OVERRIDE {
69    unregistration_result_ = result;
70    waiter_->SignalCompleted();
71  }
72
73  GCMClient::Result unregistration_result() const {
74    return unregistration_result_;
75  }
76
77 private:
78  Waiter* waiter_;
79  GCMClient::Result unregistration_result_;
80
81  DISALLOW_COPY_AND_ASSIGN(FakeExtensionGCMAppHandler);
82};
83
84class ExtensionGCMAppHandlerTest : public testing::Test {
85 public:
86  static KeyedService* BuildGCMProfileService(
87      content::BrowserContext* context) {
88    return new GCMProfileService(static_cast<Profile*>(context));
89  }
90
91  ExtensionGCMAppHandlerTest()
92      : extension_service_(NULL),
93        registration_result_(GCMClient::UNKNOWN_ERROR),
94        unregistration_result_(GCMClient::UNKNOWN_ERROR) {
95  }
96
97  virtual ~ExtensionGCMAppHandlerTest() {
98  }
99
100  // Overridden from test::Test:
101  virtual void SetUp() OVERRIDE {
102    // Make BrowserThread work in unittest.
103    thread_bundle_.reset(new content::TestBrowserThreadBundle(
104        content::TestBrowserThreadBundle::REAL_IO_THREAD));
105
106    // This is needed to create extension service under CrOS.
107#if defined(OS_CHROMEOS)
108    test_user_manager_.reset(new chromeos::ScopedTestUserManager());
109#endif
110
111    // Create a new profile.
112    TestingProfile::Builder builder;
113    builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
114                              gcm::FakeSigninManager::Build);
115    profile_ = builder.Build();
116    signin_manager_ = static_cast<gcm::FakeSigninManager*>(
117        SigninManagerFactory::GetInstance()->GetForProfile(profile_.get()));
118
119    // Create extension service in order to uninstall the extension.
120    TestExtensionSystem* extension_system(
121        static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile())));
122    extension_system->CreateExtensionService(
123        CommandLine::ForCurrentProcess(), base::FilePath(), false);
124    extension_service_ = extension_system->Get(profile())->extension_service();
125
126    // Enable GCM such that tests could be run on all channels.
127    profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, true);
128
129    // Create GCMProfileService that talks with fake GCMClient.
130    GCMProfileService* gcm_profile_service = static_cast<GCMProfileService*>(
131        GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
132            profile(),
133            &ExtensionGCMAppHandlerTest::BuildGCMProfileService));
134    scoped_ptr<GCMClientFactory> gcm_client_factory(
135        new FakeGCMClientFactory(GCMClientMock::NO_DELAY_LOADING));
136    gcm_profile_service->Initialize(gcm_client_factory.Pass());
137
138    // Create a fake version of ExtensionGCMAppHandler.
139    gcm_app_handler_.reset(new FakeExtensionGCMAppHandler(profile(), &waiter_));
140  }
141
142  virtual void TearDown() OVERRIDE {
143#if defined(OS_CHROMEOS)
144    test_user_manager_.reset();
145#endif
146
147    waiter_.PumpUILoop();
148  }
149
150  // Returns a barebones test extension.
151  scoped_refptr<Extension> CreateExtension() {
152#if defined(OS_WIN)
153    base::FilePath path(FILE_PATH_LITERAL("c:\\foo"));
154#elif defined(OS_POSIX)
155    base::FilePath path(FILE_PATH_LITERAL("/foo"));
156#endif
157
158    base::DictionaryValue manifest;
159    manifest.SetString(manifest_keys::kVersion, "1.0.0.0");
160    manifest.SetString(manifest_keys::kName, kTestExtensionName);
161    base::ListValue* permission_list = new base::ListValue;
162    permission_list->Append(base::Value::CreateStringValue("gcm"));
163    manifest.Set(manifest_keys::kPermissions, permission_list);
164
165    std::string error;
166    scoped_refptr<Extension> extension = Extension::Create(
167        path.AppendASCII(kTestExtensionName),
168        Manifest::INVALID_LOCATION,
169        manifest,
170        Extension::NO_FLAGS,
171        &error);
172    EXPECT_TRUE(extension.get()) << error;
173    EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kGcm));
174
175    return extension;
176  }
177
178  void LoadExtension(const Extension* extension) {
179    extension_service_->AddExtension(extension);
180  }
181
182  void DisableExtension(const Extension* extension) {
183    extension_service_->DisableExtension(
184        extension->id(), Extension::DISABLE_USER_ACTION);
185  }
186
187  void EnableExtension(const Extension* extension) {
188    extension_service_->EnableExtension(extension->id());
189  }
190
191  void UninstallExtension(const Extension* extension) {
192    extension_service_->UninstallExtension(extension->id(), false, NULL);
193  }
194
195  void SignIn(const std::string& username) {
196    signin_manager_->SignIn(username);
197    waiter_.PumpIOLoop();
198  }
199
200  void SignOut() {
201    signin_manager_->SignOut();
202    waiter_.PumpIOLoop();
203  }
204
205  void Register(const std::string& app_id,
206                const std::vector<std::string>& sender_ids) {
207    GetGCMProfileService()->Register(
208        app_id,
209        sender_ids,
210        base::Bind(&ExtensionGCMAppHandlerTest::RegisterCompleted,
211                   base::Unretained(this)));
212  }
213
214  void RegisterCompleted(const std::string& registration_id,
215                         GCMClient::Result result) {
216    registration_result_ = result;
217    waiter_.SignalCompleted();
218  }
219
220  GCMProfileService* GetGCMProfileService() const {
221    return GCMProfileServiceFactory::GetForProfile(profile());
222  }
223
224  bool HasAppHandlers(const std::string& app_id) const {
225    return GetGCMProfileService()->app_handlers_.count(app_id);
226  }
227
228  Profile* profile() const { return profile_.get(); }
229  Waiter* waiter() { return &waiter_; }
230  FakeExtensionGCMAppHandler* gcm_app_handler() const {
231    return gcm_app_handler_.get();
232  }
233  GCMClient::Result registration_result() const { return registration_result_; }
234  GCMClient::Result unregistration_result() const {
235    return unregistration_result_;
236  }
237
238 private:
239  scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_;
240  scoped_ptr<TestingProfile> profile_;
241  ExtensionService* extension_service_;  // Not owned.
242  gcm::FakeSigninManager* signin_manager_;  // Not owned.
243
244  // This is needed to create extension service under CrOS.
245#if defined(OS_CHROMEOS)
246  chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
247  chromeos::ScopedTestCrosSettings test_cros_settings_;
248  scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
249#endif
250
251  Waiter waiter_;
252  scoped_ptr<FakeExtensionGCMAppHandler> gcm_app_handler_;
253  GCMClient::Result registration_result_;
254  GCMClient::Result unregistration_result_;
255
256  DISALLOW_COPY_AND_ASSIGN(ExtensionGCMAppHandlerTest);
257};
258
259TEST_F(ExtensionGCMAppHandlerTest, AddAndRemoveAppHandler) {
260  scoped_refptr<Extension> extension(CreateExtension());
261
262  // App handler is added when extension is loaded.
263  LoadExtension(extension);
264  waiter()->PumpUILoop();
265  EXPECT_TRUE(HasAppHandlers(extension->id()));
266
267  // App handler is removed when extension is unloaded.
268  DisableExtension(extension);
269  waiter()->PumpUILoop();
270  EXPECT_FALSE(HasAppHandlers(extension->id()));
271
272  // App handler is added when extension is reloaded.
273  EnableExtension(extension);
274  waiter()->PumpUILoop();
275  EXPECT_TRUE(HasAppHandlers(extension->id()));
276
277  // App handler is removed when extension is uninstalled.
278  UninstallExtension(extension);
279  waiter()->PumpUILoop();
280  EXPECT_FALSE(HasAppHandlers(extension->id()));
281}
282
283TEST_F(ExtensionGCMAppHandlerTest, UnregisterOnExtensionUninstall) {
284  scoped_refptr<Extension> extension(CreateExtension());
285  LoadExtension(extension);
286
287  // Sign-in is needed for registration.
288  SignIn(kTestingUsername);
289
290  // Kick off registration.
291  std::vector<std::string> sender_ids;
292  sender_ids.push_back("sender1");
293  Register(extension->id(), sender_ids);
294  waiter()->WaitUntilCompleted();
295  EXPECT_EQ(GCMClient::SUCCESS, registration_result());
296
297  // Unregistration should be triggered when the extension is uninstalled.
298  UninstallExtension(extension);
299  waiter()->WaitUntilCompleted();
300  EXPECT_EQ(GCMClient::SUCCESS, gcm_app_handler()->unregistration_result());
301}
302
303}  // namespace extensions
304