Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_gcm_app_handler_unittest.cc
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 "chrome/browser/extensions/extension_gcm_app_handler.h"
6
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/command_line.h"
12 #include "base/files/file_path.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/message_loop/message_loop.h"
17 #include "base/run_loop.h"
18 #include "base/values.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/extensions/test_extension_service.h"
21 #include "chrome/browser/extensions/test_extension_system.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/services/gcm/fake_gcm_client_factory.h"
24 #include "chrome/browser/services/gcm/fake_signin_manager.h"
25 #include "chrome/browser/services/gcm/gcm_client_factory.h"
26 #include "chrome/browser/services/gcm/gcm_client_mock.h"
27 #include "chrome/browser/services/gcm/gcm_profile_service.h"
28 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
29 #include "chrome/browser/signin/signin_manager_factory.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/test/base/testing_profile.h"
32 #include "components/keyed_service/core/keyed_service.h"
33 #include "content/public/browser/browser_context.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/test/test_browser_thread_bundle.h"
36 #include "extensions/browser/extension_system.h"
37 #include "extensions/common/extension.h"
38 #include "extensions/common/manifest.h"
39 #include "extensions/common/manifest_constants.h"
40 #include "extensions/common/permissions/api_permission.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42
43 #if !defined(OS_ANDROID)
44 #include "chrome/browser/extensions/api/gcm/gcm_api.h"
45 #endif
46
47 #if defined(OS_CHROMEOS)
48 #include "chrome/browser/chromeos/login/user_manager.h"
49 #include "chrome/browser/chromeos/settings/cros_settings.h"
50 #include "chrome/browser/chromeos/settings/device_settings_service.h"
51 #endif
52
53 namespace extensions {
54
55 namespace {
56
57 const char kTestExtensionName[] = "FooBar";
58 const char kTestingUsername[] = "user1@example.com";
59
60 }  // namespace
61
62 // Helper class for asynchronous waiting.
63 class Waiter {
64  public:
65   Waiter() {}
66   ~Waiter() {}
67
68   // Waits until the asynchronous operation finishes.
69   void WaitUntilCompleted() {
70     run_loop_.reset(new base::RunLoop);
71     run_loop_->Run();
72   }
73
74   // Signals that the asynchronous operation finishes.
75   void SignalCompleted() {
76     if (run_loop_ && run_loop_->running())
77       run_loop_->Quit();
78   }
79
80   // Runs until UI loop becomes idle.
81   void PumpUILoop() {
82     base::MessageLoop::current()->RunUntilIdle();
83   }
84
85   // Runs until IO loop becomes idle.
86   void PumpIOLoop() {
87     content::BrowserThread::PostTask(
88         content::BrowserThread::IO,
89         FROM_HERE,
90         base::Bind(&Waiter::OnIOLoopPump, base::Unretained(this)));
91
92     WaitUntilCompleted();
93   }
94
95  private:
96   void PumpIOLoopCompleted() {
97     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
98
99     SignalCompleted();
100   }
101
102   void OnIOLoopPump() {
103     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
104
105     content::BrowserThread::PostTask(
106         content::BrowserThread::IO,
107         FROM_HERE,
108         base::Bind(&Waiter::OnIOLoopPumpCompleted, base::Unretained(this)));
109   }
110
111   void OnIOLoopPumpCompleted() {
112     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
113
114     content::BrowserThread::PostTask(
115         content::BrowserThread::UI,
116         FROM_HERE,
117         base::Bind(&Waiter::PumpIOLoopCompleted, base::Unretained(this)));
118   }
119
120   scoped_ptr<base::RunLoop> run_loop_;
121
122   DISALLOW_COPY_AND_ASSIGN(Waiter);
123 };
124
125 class FakeExtensionGCMAppHandler : public ExtensionGCMAppHandler {
126  public:
127   FakeExtensionGCMAppHandler(Profile* profile, Waiter* waiter)
128       : ExtensionGCMAppHandler(profile),
129         waiter_(waiter),
130         unregistration_result_(gcm::GCMClient::UNKNOWN_ERROR) {
131   }
132
133   virtual ~FakeExtensionGCMAppHandler() {
134   }
135
136   virtual void OnMessage(
137       const std::string& app_id,
138       const gcm::GCMClient::IncomingMessage& message) OVERRIDE {
139   }
140
141   virtual void OnMessagesDeleted(const std::string& app_id) OVERRIDE {
142   }
143
144   virtual void OnSendError(
145       const std::string& app_id,
146       const gcm::GCMClient::SendErrorDetails& send_error_details) OVERRIDE {
147   }
148
149   virtual void OnUnregisterCompleted(const std::string& app_id,
150                                      gcm::GCMClient::Result result) OVERRIDE {
151     unregistration_result_ = result;
152     waiter_->SignalCompleted();
153   }
154
155   gcm::GCMClient::Result unregistration_result() const {
156     return unregistration_result_;
157   }
158
159  private:
160   Waiter* waiter_;
161   gcm::GCMClient::Result unregistration_result_;
162
163   DISALLOW_COPY_AND_ASSIGN(FakeExtensionGCMAppHandler);
164 };
165
166 class ExtensionGCMAppHandlerTest : public testing::Test {
167  public:
168   static KeyedService* BuildGCMProfileService(
169       content::BrowserContext* context) {
170     return new gcm::GCMProfileService(static_cast<Profile*>(context));
171   }
172
173   ExtensionGCMAppHandlerTest()
174       : extension_service_(NULL),
175         registration_result_(gcm::GCMClient::UNKNOWN_ERROR),
176         unregistration_result_(gcm::GCMClient::UNKNOWN_ERROR) {
177   }
178
179   virtual ~ExtensionGCMAppHandlerTest() {
180   }
181
182   // Overridden from test::Test:
183   virtual void SetUp() OVERRIDE {
184     // Make BrowserThread work in unittest.
185     thread_bundle_.reset(new content::TestBrowserThreadBundle(
186         content::TestBrowserThreadBundle::REAL_IO_THREAD));
187
188     // This is needed to create extension service under CrOS.
189 #if defined(OS_CHROMEOS)
190     test_user_manager_.reset(new chromeos::ScopedTestUserManager());
191 #endif
192
193     // Create a new profile.
194     TestingProfile::Builder builder;
195     builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
196                               gcm::FakeSigninManager::Build);
197     profile_ = builder.Build();
198     signin_manager_ = static_cast<gcm::FakeSigninManager*>(
199         SigninManagerFactory::GetInstance()->GetForProfile(profile_.get()));
200
201     // Create extension service in order to uninstall the extension.
202     TestExtensionSystem* extension_system(
203         static_cast<TestExtensionSystem*>(ExtensionSystem::Get(profile())));
204     extension_system->CreateExtensionService(
205         CommandLine::ForCurrentProcess(), base::FilePath(), false);
206     extension_service_ = extension_system->Get(profile())->extension_service();
207
208     // Enable GCM such that tests could be run on all channels.
209     profile()->GetPrefs()->SetBoolean(prefs::kGCMChannelEnabled, true);
210
211     // Create GCMProfileService that talks with fake GCMClient.
212     gcm::GCMProfileService* gcm_profile_service =
213         static_cast<gcm::GCMProfileService*>(
214             gcm::GCMProfileServiceFactory::GetInstance()->
215                 SetTestingFactoryAndUse(
216                     profile(),
217                     &ExtensionGCMAppHandlerTest::BuildGCMProfileService));
218     scoped_ptr<gcm::GCMClientFactory> gcm_client_factory(
219         new gcm::FakeGCMClientFactory(gcm::GCMClientMock::NO_DELAY_LOADING));
220     gcm_profile_service->Initialize(gcm_client_factory.Pass());
221
222     // Create a fake version of ExtensionGCMAppHandler.
223     gcm_app_handler_.reset(new FakeExtensionGCMAppHandler(profile(), &waiter_));
224   }
225
226   virtual void TearDown() OVERRIDE {
227 #if defined(OS_CHROMEOS)
228     test_user_manager_.reset();
229 #endif
230
231     waiter_.PumpUILoop();
232   }
233
234   // Returns a barebones test extension.
235   scoped_refptr<Extension> CreateExtension() {
236 #if defined(OS_WIN)
237     base::FilePath path(FILE_PATH_LITERAL("c:\\foo"));
238 #elif defined(OS_POSIX)
239     base::FilePath path(FILE_PATH_LITERAL("/foo"));
240 #endif
241
242     base::DictionaryValue manifest;
243     manifest.SetString(manifest_keys::kVersion, "1.0.0.0");
244     manifest.SetString(manifest_keys::kName, kTestExtensionName);
245     base::ListValue* permission_list = new base::ListValue;
246     permission_list->Append(base::Value::CreateStringValue("gcm"));
247     manifest.Set(manifest_keys::kPermissions, permission_list);
248
249     std::string error;
250     scoped_refptr<Extension> extension = Extension::Create(
251         path.AppendASCII(kTestExtensionName),
252         Manifest::INVALID_LOCATION,
253         manifest,
254         Extension::NO_FLAGS,
255         &error);
256     EXPECT_TRUE(extension.get()) << error;
257     EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kGcm));
258
259     return extension;
260   }
261
262   void LoadExtension(const Extension* extension) {
263     extension_service_->AddExtension(extension);
264   }
265
266   void DisableExtension(const Extension* extension) {
267     extension_service_->DisableExtension(
268         extension->id(), Extension::DISABLE_USER_ACTION);
269   }
270
271   void EnableExtension(const Extension* extension) {
272     extension_service_->EnableExtension(extension->id());
273   }
274
275   void UninstallExtension(const Extension* extension) {
276     extension_service_->UninstallExtension(extension->id(), false, NULL);
277   }
278
279   void SignIn(const std::string& username) {
280     signin_manager_->SignIn(username);
281     waiter_.PumpIOLoop();
282   }
283
284   void SignOut() {
285     signin_manager_->SignOut();
286     waiter_.PumpIOLoop();
287   }
288
289   void Register(const std::string& app_id,
290                 const std::vector<std::string>& sender_ids) {
291     GetGCMProfileService()->Register(
292         app_id,
293         sender_ids,
294         base::Bind(&ExtensionGCMAppHandlerTest::RegisterCompleted,
295                    base::Unretained(this)));
296   }
297
298   void RegisterCompleted(const std::string& registration_id,
299                          gcm::GCMClient::Result result) {
300     registration_result_ = result;
301     waiter_.SignalCompleted();
302   }
303
304   gcm::GCMProfileService* GetGCMProfileService() const {
305     return gcm::GCMProfileServiceFactory::GetForProfile(profile());
306   }
307
308   bool HasAppHandlers(const std::string& app_id) const {
309     return GetGCMProfileService()->app_handlers_.count(app_id);
310   }
311
312   Profile* profile() const { return profile_.get(); }
313   Waiter* waiter() { return &waiter_; }
314   FakeExtensionGCMAppHandler* gcm_app_handler() const {
315     return gcm_app_handler_.get();
316   }
317   gcm::GCMClient::Result registration_result() const {
318     return registration_result_;
319   }
320   gcm::GCMClient::Result unregistration_result() const {
321     return unregistration_result_;
322   }
323
324  private:
325   scoped_ptr<content::TestBrowserThreadBundle> thread_bundle_;
326   scoped_ptr<TestingProfile> profile_;
327   ExtensionService* extension_service_;  // Not owned.
328   gcm::FakeSigninManager* signin_manager_;  // Not owned.
329
330   // This is needed to create extension service under CrOS.
331 #if defined(OS_CHROMEOS)
332   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
333   chromeos::ScopedTestCrosSettings test_cros_settings_;
334   scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
335 #endif
336
337   Waiter waiter_;
338   scoped_ptr<FakeExtensionGCMAppHandler> gcm_app_handler_;
339   gcm::GCMClient::Result registration_result_;
340   gcm::GCMClient::Result unregistration_result_;
341
342   DISALLOW_COPY_AND_ASSIGN(ExtensionGCMAppHandlerTest);
343 };
344
345 TEST_F(ExtensionGCMAppHandlerTest, AddAndRemoveAppHandler) {
346   scoped_refptr<Extension> extension(CreateExtension());
347
348   // App handler is added when extension is loaded.
349   LoadExtension(extension);
350   waiter()->PumpUILoop();
351   EXPECT_TRUE(HasAppHandlers(extension->id()));
352
353   // App handler is removed when extension is unloaded.
354   DisableExtension(extension);
355   waiter()->PumpUILoop();
356   EXPECT_FALSE(HasAppHandlers(extension->id()));
357
358   // App handler is added when extension is reloaded.
359   EnableExtension(extension);
360   waiter()->PumpUILoop();
361   EXPECT_TRUE(HasAppHandlers(extension->id()));
362
363   // App handler is removed when extension is uninstalled.
364   UninstallExtension(extension);
365   waiter()->PumpUILoop();
366   EXPECT_FALSE(HasAppHandlers(extension->id()));
367 }
368
369 TEST_F(ExtensionGCMAppHandlerTest, UnregisterOnExtensionUninstall) {
370   scoped_refptr<Extension> extension(CreateExtension());
371   LoadExtension(extension);
372
373   // Sign-in is needed for registration.
374   SignIn(kTestingUsername);
375
376   // Kick off registration.
377   std::vector<std::string> sender_ids;
378   sender_ids.push_back("sender1");
379   Register(extension->id(), sender_ids);
380   waiter()->WaitUntilCompleted();
381   EXPECT_EQ(gcm::GCMClient::SUCCESS, registration_result());
382
383   // Unregistration should be triggered when the extension is uninstalled.
384   UninstallExtension(extension);
385   waiter()->WaitUntilCompleted();
386   EXPECT_EQ(gcm::GCMClient::SUCCESS,
387             gcm_app_handler()->unregistration_result());
388 }
389
390 }  // namespace extensions