Vectorize sad tab image.
[chromium-blink-merge.git] / chrome / browser / notifications / platform_notification_service_unittest.cc
blob1429d6de61fbc7b76b2bc09cbd1f0927a6289dd9
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.
5 #include "base/strings/utf_string_conversions.h"
6 #include "base/threading/platform_thread.h"
7 #include "base/time/time.h"
8 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
9 #include "chrome/browser/notifications/notification_delegate.h"
10 #include "chrome/browser/notifications/notification_test_util.h"
11 #include "chrome/browser/notifications/platform_notification_service_impl.h"
12 #include "chrome/test/base/testing_profile.h"
13 #include "components/content_settings/core/browser/host_content_settings_map.h"
14 #include "content/public/browser/desktop_notification_delegate.h"
15 #include "content/public/common/platform_notification_data.h"
16 #include "content/public/test/test_browser_thread_bundle.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/skia/include/core/SkBitmap.h"
21 #if defined(ENABLE_EXTENSIONS)
22 #include "base/command_line.h"
23 #include "chrome/browser/extensions/extension_service.h"
24 #include "chrome/browser/extensions/test_extension_system.h"
25 #include "extensions/browser/extension_registry.h"
26 #include "extensions/browser/process_map.h"
27 #include "extensions/common/extension.h"
28 #include "extensions/common/extension_builder.h"
29 #include "extensions/common/permissions/api_permission.h"
30 #include "extensions/common/value_builder.h"
31 #endif
33 #if defined(ENABLE_EXTENSIONS) && defined(OS_CHROMEOS)
34 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
35 #include "chrome/browser/chromeos/settings/cros_settings.h"
36 #include "chrome/browser/chromeos/settings/device_settings_service.h"
37 #endif
39 namespace {
41 const int kNotificationVibrationPattern[] = { 100, 200, 300 };
43 #if !defined(OS_ANDROID)
44 const int64_t kPersistentNotificationId = 42;
45 #endif
47 class MockDesktopNotificationDelegate
48 : public content::DesktopNotificationDelegate {
49 public:
50 MockDesktopNotificationDelegate()
51 : displayed_(false),
52 clicked_(false) {}
54 ~MockDesktopNotificationDelegate() override {}
56 // content::DesktopNotificationDelegate implementation.
57 void NotificationDisplayed() override { displayed_ = true; }
58 void NotificationClosed() override {}
59 void NotificationClick() override { clicked_ = true; }
61 bool displayed() const { return displayed_; }
62 bool clicked() const { return clicked_; }
64 private:
65 bool displayed_;
66 bool clicked_;
69 } // namespace
71 class PlatformNotificationServiceTest : public testing::Test {
72 public:
73 void SetUp() override {
74 ui_manager_.reset(new StubNotificationUIManager);
75 profile_.reset(new TestingProfile());
77 service()->SetNotificationUIManagerForTesting(ui_manager_.get());
80 void TearDown() override {
81 service()->SetNotificationUIManagerForTesting(nullptr);
83 profile_.reset();
84 ui_manager_.reset();
87 protected:
88 // Displays a simple, fake notifications and returns a weak pointer to the
89 // delegate receiving events for it (ownership is transferred to the service).
90 MockDesktopNotificationDelegate* CreateSimplePageNotification() const {
91 return CreateSimplePageNotificationWithCloseClosure(nullptr);
94 // Displays a simple, fake notification and returns a weak pointer to the
95 // delegate receiving events for it (ownership is transferred to the service).
96 // The close closure may be specified if so desired.
97 MockDesktopNotificationDelegate* CreateSimplePageNotificationWithCloseClosure(
98 base::Closure* close_closure) const {
99 content::PlatformNotificationData notification_data;
100 notification_data.title = base::ASCIIToUTF16("My Notification");
101 notification_data.body = base::ASCIIToUTF16("Hello, world!");
103 MockDesktopNotificationDelegate* delegate =
104 new MockDesktopNotificationDelegate();
106 service()->DisplayNotification(profile(),
107 GURL("https://chrome.com/"),
108 SkBitmap(),
109 notification_data,
110 make_scoped_ptr(delegate),
111 close_closure);
113 return delegate;
116 // Returns the Platform Notification Service these unit tests are for.
117 PlatformNotificationServiceImpl* service() const {
118 return PlatformNotificationServiceImpl::GetInstance();
121 // Returns the Profile to be used for these tests.
122 Profile* profile() const { return profile_.get(); }
124 // Returns the UI Manager on which notifications will be displayed.
125 StubNotificationUIManager* ui_manager() const { return ui_manager_.get(); }
127 private:
128 scoped_ptr<StubNotificationUIManager> ui_manager_;
129 scoped_ptr<TestingProfile> profile_;
131 content::TestBrowserThreadBundle thread_bundle_;
134 TEST_F(PlatformNotificationServiceTest, DisplayPageDisplayedEvent) {
135 auto* delegate = CreateSimplePageNotification();
137 EXPECT_EQ(1u, ui_manager()->GetNotificationCount());
138 EXPECT_TRUE(delegate->displayed());
141 TEST_F(PlatformNotificationServiceTest, DisplayPageCloseClosure) {
142 base::Closure close_closure;
143 CreateSimplePageNotificationWithCloseClosure(&close_closure);
145 EXPECT_EQ(1u, ui_manager()->GetNotificationCount());
147 ASSERT_FALSE(close_closure.is_null());
148 close_closure.Run();
150 EXPECT_EQ(0u, ui_manager()->GetNotificationCount());
152 // Note that we cannot verify whether the closed event was called on the
153 // delegate given that it'd result in a use-after-free.
156 // TODO(peter): Re-enable this test when //content is responsible for creating
157 // the notification delegate ids.
158 #if !defined(OS_ANDROID)
159 TEST_F(PlatformNotificationServiceTest, PersistentNotificationDisplay) {
160 content::PlatformNotificationData notification_data;
161 notification_data.title = base::ASCIIToUTF16("My notification's title");
162 notification_data.body = base::ASCIIToUTF16("Hello, world!");
164 service()->DisplayPersistentNotification(
165 profile(), kPersistentNotificationId, GURL("https://chrome.com/"),
166 SkBitmap(), notification_data);
168 ASSERT_EQ(1u, ui_manager()->GetNotificationCount());
170 const Notification& notification = ui_manager()->GetNotificationAt(0);
171 EXPECT_EQ("https://chrome.com/", notification.origin_url().spec());
172 EXPECT_EQ("My notification's title",
173 base::UTF16ToUTF8(notification.title()));
174 EXPECT_EQ("Hello, world!",
175 base::UTF16ToUTF8(notification.message()));
177 service()->ClosePersistentNotification(profile(), kPersistentNotificationId);
178 EXPECT_EQ(0u, ui_manager()->GetNotificationCount());
180 #endif // !defined(OS_ANDROID)
182 TEST_F(PlatformNotificationServiceTest, DisplayPageNotificationMatches) {
183 std::vector<int> vibration_pattern(
184 kNotificationVibrationPattern,
185 kNotificationVibrationPattern + arraysize(kNotificationVibrationPattern));
187 content::PlatformNotificationData notification_data;
188 notification_data.title = base::ASCIIToUTF16("My notification's title");
189 notification_data.body = base::ASCIIToUTF16("Hello, world!");
190 notification_data.vibration_pattern = vibration_pattern;
191 notification_data.silent = true;
193 MockDesktopNotificationDelegate* delegate
194 = new MockDesktopNotificationDelegate();
195 service()->DisplayNotification(profile(),
196 GURL("https://chrome.com/"),
197 SkBitmap(),
198 notification_data,
199 make_scoped_ptr(delegate),
200 nullptr);
202 ASSERT_EQ(1u, ui_manager()->GetNotificationCount());
204 const Notification& notification = ui_manager()->GetNotificationAt(0);
205 EXPECT_EQ("https://chrome.com/", notification.origin_url().spec());
206 EXPECT_EQ("My notification's title",
207 base::UTF16ToUTF8(notification.title()));
208 EXPECT_EQ("Hello, world!",
209 base::UTF16ToUTF8(notification.message()));
211 EXPECT_THAT(notification.vibration_pattern(),
212 testing::ElementsAreArray(kNotificationVibrationPattern));
214 EXPECT_TRUE(notification.silent());
217 TEST_F(PlatformNotificationServiceTest, DisplayPersistentNotificationMatches) {
218 std::vector<int> vibration_pattern(
219 kNotificationVibrationPattern,
220 kNotificationVibrationPattern + arraysize(kNotificationVibrationPattern));
222 content::PlatformNotificationData notification_data;
223 notification_data.title = base::ASCIIToUTF16("My notification's title");
224 notification_data.body = base::ASCIIToUTF16("Hello, world!");
225 notification_data.vibration_pattern = vibration_pattern;
226 notification_data.silent = true;
227 notification_data.actions.resize(2);
228 notification_data.actions[0].title = base::ASCIIToUTF16("Button 1");
229 notification_data.actions[1].title = base::ASCIIToUTF16("Button 2");
231 service()->DisplayPersistentNotification(
232 profile(), 0u /* persistent notification */, GURL("https://chrome.com/"),
233 SkBitmap(), notification_data);
235 ASSERT_EQ(1u, ui_manager()->GetNotificationCount());
237 const Notification& notification = ui_manager()->GetNotificationAt(0);
238 EXPECT_EQ("https://chrome.com/", notification.origin_url().spec());
239 EXPECT_EQ("My notification's title", base::UTF16ToUTF8(notification.title()));
240 EXPECT_EQ("Hello, world!", base::UTF16ToUTF8(notification.message()));
242 EXPECT_THAT(notification.vibration_pattern(),
243 testing::ElementsAreArray(kNotificationVibrationPattern));
245 EXPECT_TRUE(notification.silent());
247 const auto& buttons = notification.buttons();
248 ASSERT_EQ(2u, buttons.size());
249 EXPECT_EQ("Button 1", base::UTF16ToUTF8(buttons[0].title));
250 EXPECT_EQ("Button 2", base::UTF16ToUTF8(buttons[1].title));
253 TEST_F(PlatformNotificationServiceTest, NotificationPermissionLastUsage) {
254 // Both page and persistent notifications should update the last usage
255 // time of the notification permission for the origin.
256 GURL origin("https://chrome.com/");
257 base::Time begin_time;
259 CreateSimplePageNotification();
261 base::Time after_page_notification =
262 HostContentSettingsMapFactory::GetForProfile(profile())->GetLastUsage(
263 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
264 EXPECT_GT(after_page_notification, begin_time);
266 // Ensure that there is at least some time between the two calls.
267 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
269 service()->DisplayPersistentNotification(
270 profile(), 42 /* sw_registration_id */, origin, SkBitmap(),
271 content::PlatformNotificationData());
273 base::Time after_persistent_notification =
274 HostContentSettingsMapFactory::GetForProfile(profile())->GetLastUsage(
275 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
276 EXPECT_GT(after_persistent_notification, after_page_notification);
279 #if defined(ENABLE_EXTENSIONS)
281 TEST_F(PlatformNotificationServiceTest, DisplayNameForContextMessage) {
282 base::string16 display_name = service()->DisplayNameForContextMessage(
283 profile(), GURL("https://chrome.com/"));
285 EXPECT_TRUE(display_name.empty());
287 // Create a mocked extension.
288 scoped_refptr<extensions::Extension> extension =
289 extensions::ExtensionBuilder()
290 .SetID("honijodknafkokifofgiaalefdiedpko")
291 .SetManifest(extensions::DictionaryBuilder()
292 .Set("name", "NotificationTest")
293 .Set("version", "1.0")
294 .Set("manifest_version", 2)
295 .Set("description", "Test Extension"))
296 .Build();
298 extensions::ExtensionRegistry* registry =
299 extensions::ExtensionRegistry::Get(profile());
300 EXPECT_TRUE(registry->AddEnabled(extension));
302 display_name = service()->DisplayNameForContextMessage(
303 profile(),
304 GURL("chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"));
305 EXPECT_EQ("NotificationTest", base::UTF16ToUTF8(display_name));
308 TEST_F(PlatformNotificationServiceTest, ExtensionPermissionChecks) {
309 #if defined(OS_CHROMEOS)
310 // The ExtensionService on Chrome OS requires these objects to be initialized.
311 chromeos::ScopedTestDeviceSettingsService test_device_settings_service;
312 chromeos::ScopedTestCrosSettings test_cros_settings;
313 chromeos::ScopedTestUserManager test_user_manager;
314 #endif
316 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
317 extensions::TestExtensionSystem* test_extension_system =
318 static_cast<extensions::TestExtensionSystem*>(
319 extensions::ExtensionSystem::Get(profile()));
321 ExtensionService* extension_service =
322 test_extension_system->CreateExtensionService(
323 &command_line, base::FilePath() /* install_directory */,
324 false /* autoupdate_enabled */);
326 // Create a mocked extension that has the notifications API permission.
327 scoped_refptr<extensions::Extension> extension =
328 extensions::ExtensionBuilder()
329 .SetManifest(extensions::DictionaryBuilder()
330 .Set("name", "NotificationTest")
331 .Set("version", "1.0")
332 .Set("manifest_version", 2)
333 .Set("description", "Test Extension")
334 .Set("permissions", extensions::ListBuilder().Append(
335 "notifications")))
336 .Build();
338 // Install the extension on the faked extension service, and verify that it
339 // has been added to the extension registry successfully.
340 extension_service->AddExtension(extension.get());
341 extensions::ExtensionRegistry* registry =
342 extensions::ExtensionRegistry::Get(profile());
344 ASSERT_TRUE(registry->GetExtensionById(
345 extension->id(), extensions::ExtensionRegistry::ENABLED));
347 const int kFakeRenderProcessId = 42;
349 // Mock that the extension is running in a fake render process id.
350 extensions::ProcessMap::Get(profile())->Insert(extension->id(),
351 kFakeRenderProcessId,
352 -1 /* site_instance_id */);
354 // Verify that the service indicates that permission has been granted. We only
355 // check the UI thread-method for now, as that's the one guarding the behavior
356 // in the browser process.
357 EXPECT_EQ(blink::WebNotificationPermissionAllowed,
358 service()->CheckPermissionOnUIThread(profile(),
359 extension->url(),
360 kFakeRenderProcessId));
363 TEST_F(PlatformNotificationServiceTest, CreateNotificationFromData) {
364 content::PlatformNotificationData notification_data;
365 notification_data.title = base::ASCIIToUTF16("My Notification");
366 notification_data.body = base::ASCIIToUTF16("Hello, world!");
368 Notification notification = service()->CreateNotificationFromData(
369 profile(), GURL("https://chrome.com/"), SkBitmap(), notification_data,
370 new MockNotificationDelegate("hello"));
371 EXPECT_TRUE(notification.context_message().empty());
373 // Create a mocked extension.
374 scoped_refptr<extensions::Extension> extension =
375 extensions::ExtensionBuilder()
376 .SetID("honijodknafkokifofgiaalefdiedpko")
377 .SetManifest(extensions::DictionaryBuilder()
378 .Set("name", "NotificationTest")
379 .Set("version", "1.0")
380 .Set("manifest_version", 2)
381 .Set("description", "Test Extension"))
382 .Build();
384 extensions::ExtensionRegistry* registry =
385 extensions::ExtensionRegistry::Get(profile());
386 EXPECT_TRUE(registry->AddEnabled(extension));
388 notification = service()->CreateNotificationFromData(
389 profile(),
390 GURL("chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"),
391 SkBitmap(), notification_data, new MockNotificationDelegate("hello"));
392 EXPECT_EQ("NotificationTest",
393 base::UTF16ToUTF8(notification.context_message()));
396 #endif // defined(ENABLE_EXTENSIONS)