Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / notifications / platform_notification_service_unittest.cc
blobb4eb2a78528a4e2627148b446c131a4be1125ca2
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/notifications/notification_delegate.h"
9 #include "chrome/browser/notifications/notification_test_util.h"
10 #include "chrome/browser/notifications/platform_notification_service_impl.h"
11 #include "chrome/test/base/testing_profile.h"
12 #include "components/content_settings/core/browser/host_content_settings_map.h"
13 #include "content/public/browser/desktop_notification_delegate.h"
14 #include "content/public/common/platform_notification_data.h"
15 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/skia/include/core/SkBitmap.h"
20 #if defined(ENABLE_EXTENSIONS)
21 #include "base/command_line.h"
22 #include "chrome/browser/extensions/extension_service.h"
23 #include "chrome/browser/extensions/test_extension_system.h"
24 #include "extensions/browser/extension_registry.h"
25 #include "extensions/browser/process_map.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/extension_builder.h"
28 #include "extensions/common/permissions/api_permission.h"
29 #include "extensions/common/value_builder.h"
30 #endif
32 #if defined(ENABLE_EXTENSIONS) && defined(OS_CHROMEOS)
33 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
34 #include "chrome/browser/chromeos/settings/cros_settings.h"
35 #include "chrome/browser/chromeos/settings/device_settings_service.h"
36 #endif
38 namespace {
40 const int kNotificationVibrationPattern[] = { 100, 200, 300 };
42 #if !defined(OS_ANDROID)
43 const int64_t kPersistentNotificationId = 42;
44 #endif
46 class MockDesktopNotificationDelegate
47 : public content::DesktopNotificationDelegate {
48 public:
49 MockDesktopNotificationDelegate()
50 : displayed_(false),
51 clicked_(false) {}
53 ~MockDesktopNotificationDelegate() override {}
55 // content::DesktopNotificationDelegate implementation.
56 void NotificationDisplayed() override { displayed_ = true; }
57 void NotificationClosed() override {}
58 void NotificationClick() override { clicked_ = true; }
60 bool displayed() const { return displayed_; }
61 bool clicked() const { return clicked_; }
63 private:
64 bool displayed_;
65 bool clicked_;
68 } // namespace
70 class PlatformNotificationServiceTest : public testing::Test {
71 public:
72 void SetUp() override {
73 ui_manager_.reset(new StubNotificationUIManager);
74 profile_.reset(new TestingProfile());
76 service()->SetNotificationUIManagerForTesting(ui_manager_.get());
79 void TearDown() override {
80 service()->SetNotificationUIManagerForTesting(nullptr);
82 profile_.reset();
83 ui_manager_.reset();
86 protected:
87 // Displays a simple, fake notifications and returns a weak pointer to the
88 // delegate receiving events for it (ownership is transferred to the service).
89 MockDesktopNotificationDelegate* CreateSimplePageNotification() const {
90 return CreateSimplePageNotificationWithCloseClosure(nullptr);
93 // Displays a simple, fake notification and returns a weak pointer to the
94 // delegate receiving events for it (ownership is transferred to the service).
95 // The close closure may be specified if so desired.
96 MockDesktopNotificationDelegate* CreateSimplePageNotificationWithCloseClosure(
97 base::Closure* close_closure) const {
98 content::PlatformNotificationData notification_data;
99 notification_data.title = base::ASCIIToUTF16("My Notification");
100 notification_data.body = base::ASCIIToUTF16("Hello, world!");
102 MockDesktopNotificationDelegate* delegate =
103 new MockDesktopNotificationDelegate();
105 service()->DisplayNotification(profile(),
106 GURL("https://chrome.com/"),
107 SkBitmap(),
108 notification_data,
109 make_scoped_ptr(delegate),
110 close_closure);
112 return delegate;
115 // Returns the Platform Notification Service these unit tests are for.
116 PlatformNotificationServiceImpl* service() const {
117 return PlatformNotificationServiceImpl::GetInstance();
120 // Returns the Profile to be used for these tests.
121 Profile* profile() const { return profile_.get(); }
123 // Returns the UI Manager on which notifications will be displayed.
124 StubNotificationUIManager* ui_manager() const { return ui_manager_.get(); }
126 private:
127 scoped_ptr<StubNotificationUIManager> ui_manager_;
128 scoped_ptr<TestingProfile> profile_;
130 content::TestBrowserThreadBundle thread_bundle_;
133 TEST_F(PlatformNotificationServiceTest, DisplayPageDisplayedEvent) {
134 auto* delegate = CreateSimplePageNotification();
136 EXPECT_EQ(1u, ui_manager()->GetNotificationCount());
137 EXPECT_TRUE(delegate->displayed());
140 TEST_F(PlatformNotificationServiceTest, DisplayPageCloseClosure) {
141 base::Closure close_closure;
142 CreateSimplePageNotificationWithCloseClosure(&close_closure);
144 EXPECT_EQ(1u, ui_manager()->GetNotificationCount());
146 ASSERT_FALSE(close_closure.is_null());
147 close_closure.Run();
149 EXPECT_EQ(0u, ui_manager()->GetNotificationCount());
151 // Note that we cannot verify whether the closed event was called on the
152 // delegate given that it'd result in a use-after-free.
155 // TODO(peter): Re-enable this test when //content is responsible for creating
156 // the notification delegate ids.
157 #if !defined(OS_ANDROID)
158 TEST_F(PlatformNotificationServiceTest, PersistentNotificationDisplay) {
159 content::PlatformNotificationData notification_data;
160 notification_data.title = base::ASCIIToUTF16("My notification's title");
161 notification_data.body = base::ASCIIToUTF16("Hello, world!");
163 service()->DisplayPersistentNotification(
164 profile(), kPersistentNotificationId, GURL("https://chrome.com/"),
165 SkBitmap(), notification_data);
167 ASSERT_EQ(1u, ui_manager()->GetNotificationCount());
169 const Notification& notification = ui_manager()->GetNotificationAt(0);
170 EXPECT_EQ("https://chrome.com/", notification.origin_url().spec());
171 EXPECT_EQ("My notification's title",
172 base::UTF16ToUTF8(notification.title()));
173 EXPECT_EQ("Hello, world!",
174 base::UTF16ToUTF8(notification.message()));
176 service()->ClosePersistentNotification(profile(), kPersistentNotificationId);
177 EXPECT_EQ(0u, ui_manager()->GetNotificationCount());
179 #endif // !defined(OS_ANDROID)
181 TEST_F(PlatformNotificationServiceTest, DisplayPageNotificationMatches) {
182 std::vector<int> vibration_pattern(
183 kNotificationVibrationPattern,
184 kNotificationVibrationPattern + arraysize(kNotificationVibrationPattern));
186 content::PlatformNotificationData notification_data;
187 notification_data.title = base::ASCIIToUTF16("My notification's title");
188 notification_data.body = base::ASCIIToUTF16("Hello, world!");
189 notification_data.vibration_pattern = vibration_pattern;
190 notification_data.silent = true;
191 notification_data.actions.resize(2);
192 notification_data.actions[0].title = base::ASCIIToUTF16("Button 1");
193 notification_data.actions[1].title = base::ASCIIToUTF16("Button 2");
195 MockDesktopNotificationDelegate* delegate
196 = new MockDesktopNotificationDelegate();
197 service()->DisplayNotification(profile(),
198 GURL("https://chrome.com/"),
199 SkBitmap(),
200 notification_data,
201 make_scoped_ptr(delegate),
202 nullptr);
204 ASSERT_EQ(1u, ui_manager()->GetNotificationCount());
206 const Notification& notification = ui_manager()->GetNotificationAt(0);
207 EXPECT_EQ("https://chrome.com/", notification.origin_url().spec());
208 EXPECT_EQ("My notification's title",
209 base::UTF16ToUTF8(notification.title()));
210 EXPECT_EQ("Hello, world!",
211 base::UTF16ToUTF8(notification.message()));
213 EXPECT_THAT(notification.vibration_pattern(),
214 testing::ElementsAreArray(kNotificationVibrationPattern));
216 EXPECT_TRUE(notification.silent());
218 const auto& buttons = notification.buttons();
219 ASSERT_EQ(2u, buttons.size());
220 EXPECT_EQ("Button 1", base::UTF16ToUTF8(buttons[0].title));
221 EXPECT_EQ("Button 2", base::UTF16ToUTF8(buttons[1].title));
224 TEST_F(PlatformNotificationServiceTest, NotificationPermissionLastUsage) {
225 // Both page and persistent notifications should update the last usage
226 // time of the notification permission for the origin.
227 GURL origin("https://chrome.com/");
228 base::Time begin_time;
230 CreateSimplePageNotification();
232 base::Time after_page_notification =
233 profile()->GetHostContentSettingsMap()->GetLastUsage(
234 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
235 EXPECT_GT(after_page_notification, begin_time);
237 // Ensure that there is at least some time between the two calls.
238 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
240 service()->DisplayPersistentNotification(
241 profile(), 42 /* sw_registration_id */, origin, SkBitmap(),
242 content::PlatformNotificationData());
244 base::Time after_persistent_notification =
245 profile()->GetHostContentSettingsMap()->GetLastUsage(
246 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
247 EXPECT_GT(after_persistent_notification, after_page_notification);
250 #if defined(ENABLE_EXTENSIONS)
252 TEST_F(PlatformNotificationServiceTest, DisplayNameForContextMessage) {
253 base::string16 display_name = service()->DisplayNameForContextMessage(
254 profile(), GURL("https://chrome.com/"));
256 EXPECT_TRUE(display_name.empty());
258 // Create a mocked extension.
259 scoped_refptr<extensions::Extension> extension =
260 extensions::ExtensionBuilder()
261 .SetID("honijodknafkokifofgiaalefdiedpko")
262 .SetManifest(extensions::DictionaryBuilder()
263 .Set("name", "NotificationTest")
264 .Set("version", "1.0")
265 .Set("manifest_version", 2)
266 .Set("description", "Test Extension"))
267 .Build();
269 extensions::ExtensionRegistry* registry =
270 extensions::ExtensionRegistry::Get(profile());
271 EXPECT_TRUE(registry->AddEnabled(extension));
273 display_name = service()->DisplayNameForContextMessage(
274 profile(),
275 GURL("chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"));
276 EXPECT_EQ("NotificationTest", base::UTF16ToUTF8(display_name));
279 TEST_F(PlatformNotificationServiceTest, ExtensionPermissionChecks) {
280 #if defined(OS_CHROMEOS)
281 // The ExtensionService on Chrome OS requires these objects to be initialized.
282 chromeos::ScopedTestDeviceSettingsService test_device_settings_service;
283 chromeos::ScopedTestCrosSettings test_cros_settings;
284 chromeos::ScopedTestUserManager test_user_manager;
285 #endif
287 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
288 extensions::TestExtensionSystem* test_extension_system =
289 static_cast<extensions::TestExtensionSystem*>(
290 extensions::ExtensionSystem::Get(profile()));
292 ExtensionService* extension_service =
293 test_extension_system->CreateExtensionService(
294 &command_line, base::FilePath() /* install_directory */,
295 false /* autoupdate_enabled */);
297 // Create a mocked extension that has the notifications API permission.
298 scoped_refptr<extensions::Extension> extension =
299 extensions::ExtensionBuilder()
300 .SetManifest(extensions::DictionaryBuilder()
301 .Set("name", "NotificationTest")
302 .Set("version", "1.0")
303 .Set("manifest_version", 2)
304 .Set("description", "Test Extension")
305 .Set("permissions", extensions::ListBuilder().Append(
306 "notifications")))
307 .Build();
309 // Install the extension on the faked extension service, and verify that it
310 // has been added to the extension registry successfully.
311 extension_service->AddExtension(extension.get());
312 extensions::ExtensionRegistry* registry =
313 extensions::ExtensionRegistry::Get(profile());
315 ASSERT_TRUE(registry->GetExtensionById(
316 extension->id(), extensions::ExtensionRegistry::ENABLED));
318 const int kFakeRenderProcessId = 42;
320 // Mock that the extension is running in a fake render process id.
321 extensions::ProcessMap::Get(profile())->Insert(extension->id(),
322 kFakeRenderProcessId,
323 -1 /* site_instance_id */);
325 // Verify that the service indicates that permission has been granted. We only
326 // check the UI thread-method for now, as that's the one guarding the behavior
327 // in the browser process.
328 EXPECT_EQ(blink::WebNotificationPermissionAllowed,
329 service()->CheckPermissionOnUIThread(profile(),
330 extension->url(),
331 kFakeRenderProcessId));
334 TEST_F(PlatformNotificationServiceTest, CreateNotificationFromData) {
335 content::PlatformNotificationData notification_data;
336 notification_data.title = base::ASCIIToUTF16("My Notification");
337 notification_data.body = base::ASCIIToUTF16("Hello, world!");
339 Notification notification = service()->CreateNotificationFromData(
340 profile(), GURL("https://chrome.com/"), SkBitmap(), notification_data,
341 new MockNotificationDelegate("hello"));
342 EXPECT_TRUE(notification.context_message().empty());
344 // Create a mocked extension.
345 scoped_refptr<extensions::Extension> extension =
346 extensions::ExtensionBuilder()
347 .SetID("honijodknafkokifofgiaalefdiedpko")
348 .SetManifest(extensions::DictionaryBuilder()
349 .Set("name", "NotificationTest")
350 .Set("version", "1.0")
351 .Set("manifest_version", 2)
352 .Set("description", "Test Extension"))
353 .Build();
355 extensions::ExtensionRegistry* registry =
356 extensions::ExtensionRegistry::Get(profile());
357 EXPECT_TRUE(registry->AddEnabled(extension));
359 notification = service()->CreateNotificationFromData(
360 profile(),
361 GURL("chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html"),
362 SkBitmap(), notification_data, new MockNotificationDelegate("hello"));
363 EXPECT_EQ("NotificationTest",
364 base::UTF16ToUTF8(notification.context_message()));
367 #endif // defined(ENABLE_EXTENSIONS)