No dual_mode on Win10+ shortcuts.
[chromium-blink-merge.git] / chrome / browser / notifications / platform_notification_service_unittest.cc
blob9c4e58b941eaaf8512b53af43f01eea1cdd75ddf
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_test_util.h"
9 #include "chrome/browser/notifications/platform_notification_service_impl.h"
10 #include "chrome/test/base/testing_profile.h"
11 #include "components/content_settings/core/browser/host_content_settings_map.h"
12 #include "content/public/browser/desktop_notification_delegate.h"
13 #include "content/public/common/platform_notification_data.h"
14 #include "content/public/test/test_browser_thread_bundle.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/skia/include/core/SkBitmap.h"
19 #if defined(ENABLE_EXTENSIONS)
20 #include "base/command_line.h"
21 #include "chrome/browser/extensions/extension_service.h"
22 #include "chrome/browser/extensions/test_extension_system.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/process_map.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/extension_builder.h"
27 #include "extensions/common/permissions/api_permission.h"
28 #include "extensions/common/value_builder.h"
29 #endif
31 #if defined(ENABLE_EXTENSIONS) && defined(OS_CHROMEOS)
32 #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h"
33 #include "chrome/browser/chromeos/settings/cros_settings.h"
34 #include "chrome/browser/chromeos/settings/device_settings_service.h"
35 #endif
37 namespace {
39 const int kNotificationVibrationPattern[] = { 100, 200, 300 };
41 #if !defined(OS_ANDROID)
42 const int64_t kPersistentNotificationId = 42;
43 #endif
45 class MockDesktopNotificationDelegate
46 : public content::DesktopNotificationDelegate {
47 public:
48 MockDesktopNotificationDelegate()
49 : displayed_(false),
50 clicked_(false) {}
52 ~MockDesktopNotificationDelegate() override {}
54 // content::DesktopNotificationDelegate implementation.
55 void NotificationDisplayed() override { displayed_ = true; }
56 void NotificationClosed() override {}
57 void NotificationClick() override { clicked_ = true; }
59 bool displayed() const { return displayed_; }
60 bool clicked() const { return clicked_; }
62 private:
63 bool displayed_;
64 bool clicked_;
67 } // namespace
69 class PlatformNotificationServiceTest : public testing::Test {
70 public:
71 void SetUp() override {
72 ui_manager_.reset(new StubNotificationUIManager);
73 profile_.reset(new TestingProfile());
75 service()->SetNotificationUIManagerForTesting(ui_manager_.get());
78 void TearDown() override {
79 service()->SetNotificationUIManagerForTesting(nullptr);
81 profile_.reset();
82 ui_manager_.reset();
85 protected:
86 // Displays a simple, fake notifications and returns a weak pointer to the
87 // delegate receiving events for it (ownership is transferred to the service).
88 MockDesktopNotificationDelegate* CreateSimplePageNotification() const {
89 return CreateSimplePageNotificationWithCloseClosure(nullptr);
92 // Displays a simple, fake notification and returns a weak pointer to the
93 // delegate receiving events for it (ownership is transferred to the service).
94 // The close closure may be specified if so desired.
95 MockDesktopNotificationDelegate* CreateSimplePageNotificationWithCloseClosure(
96 base::Closure* close_closure) const {
97 content::PlatformNotificationData notification_data;
98 notification_data.title = base::ASCIIToUTF16("My Notification");
99 notification_data.body = base::ASCIIToUTF16("Hello, world!");
101 MockDesktopNotificationDelegate* delegate =
102 new MockDesktopNotificationDelegate();
104 service()->DisplayNotification(profile(),
105 GURL("https://chrome.com/"),
106 SkBitmap(),
107 notification_data,
108 make_scoped_ptr(delegate),
109 close_closure);
111 return delegate;
114 // Returns the Platform Notification Service these unit tests are for.
115 PlatformNotificationServiceImpl* service() const {
116 return PlatformNotificationServiceImpl::GetInstance();
119 // Returns the Profile to be used for these tests.
120 Profile* profile() const { return profile_.get(); }
122 // Returns the UI Manager on which notifications will be displayed.
123 StubNotificationUIManager* ui_manager() const { return ui_manager_.get(); }
125 private:
126 scoped_ptr<StubNotificationUIManager> ui_manager_;
127 scoped_ptr<TestingProfile> profile_;
129 content::TestBrowserThreadBundle thread_bundle_;
132 TEST_F(PlatformNotificationServiceTest, DisplayPageDisplayedEvent) {
133 auto* delegate = CreateSimplePageNotification();
135 EXPECT_EQ(1u, ui_manager()->GetNotificationCount());
136 EXPECT_TRUE(delegate->displayed());
139 TEST_F(PlatformNotificationServiceTest, DisplayPageCloseClosure) {
140 base::Closure close_closure;
141 CreateSimplePageNotificationWithCloseClosure(&close_closure);
143 EXPECT_EQ(1u, ui_manager()->GetNotificationCount());
145 ASSERT_FALSE(close_closure.is_null());
146 close_closure.Run();
148 EXPECT_EQ(0u, ui_manager()->GetNotificationCount());
150 // Note that we cannot verify whether the closed event was called on the
151 // delegate given that it'd result in a use-after-free.
154 // TODO(peter): Re-enable this test when //content is responsible for creating
155 // the notification delegate ids.
156 #if !defined(OS_ANDROID)
157 TEST_F(PlatformNotificationServiceTest, PersistentNotificationDisplay) {
158 content::PlatformNotificationData notification_data;
159 notification_data.title = base::ASCIIToUTF16("My notification's title");
160 notification_data.body = base::ASCIIToUTF16("Hello, world!");
162 service()->DisplayPersistentNotification(
163 profile(), kPersistentNotificationId, GURL("https://chrome.com/"),
164 SkBitmap(), notification_data);
166 ASSERT_EQ(1u, ui_manager()->GetNotificationCount());
168 const Notification& notification = ui_manager()->GetNotificationAt(0);
169 EXPECT_EQ("https://chrome.com/", notification.origin_url().spec());
170 EXPECT_EQ("My notification's title",
171 base::UTF16ToUTF8(notification.title()));
172 EXPECT_EQ("Hello, world!",
173 base::UTF16ToUTF8(notification.message()));
175 service()->ClosePersistentNotification(profile(), kPersistentNotificationId);
176 EXPECT_EQ(0u, ui_manager()->GetNotificationCount());
178 #endif // !defined(OS_ANDROID)
180 TEST_F(PlatformNotificationServiceTest, DisplayPageNotificationMatches) {
181 std::vector<int> vibration_pattern(
182 kNotificationVibrationPattern,
183 kNotificationVibrationPattern + arraysize(kNotificationVibrationPattern));
185 content::PlatformNotificationData notification_data;
186 notification_data.title = base::ASCIIToUTF16("My notification's title");
187 notification_data.body = base::ASCIIToUTF16("Hello, world!");
188 notification_data.vibration_pattern = vibration_pattern;
189 notification_data.silent = true;
191 MockDesktopNotificationDelegate* delegate
192 = new MockDesktopNotificationDelegate();
193 service()->DisplayNotification(profile(),
194 GURL("https://chrome.com/"),
195 SkBitmap(),
196 notification_data,
197 make_scoped_ptr(delegate),
198 nullptr);
200 ASSERT_EQ(1u, ui_manager()->GetNotificationCount());
202 const Notification& notification = ui_manager()->GetNotificationAt(0);
203 EXPECT_EQ("https://chrome.com/", notification.origin_url().spec());
204 EXPECT_EQ("My notification's title",
205 base::UTF16ToUTF8(notification.title()));
206 EXPECT_EQ("Hello, world!",
207 base::UTF16ToUTF8(notification.message()));
209 EXPECT_THAT(notification.vibration_pattern(),
210 testing::ElementsAreArray(kNotificationVibrationPattern));
212 EXPECT_TRUE(notification.silent());
215 TEST_F(PlatformNotificationServiceTest, DisplayNameForOrigin) {
216 base::string16 display_name =
217 service()->DisplayNameForOrigin(profile(), GURL("https://chrome.com/"));
219 EXPECT_EQ(base::ASCIIToUTF16("chrome.com"), display_name);
221 // TODO(peter): Include unit tests for the extension-name translation
222 // functionality of DisplayNameForOriginInProcessId.
225 TEST_F(PlatformNotificationServiceTest, TestWebOriginDisplayName) {
226 std::string language("en-us");
228 GURL https_origin("https://mail.google.com/");
229 base::string16 expected_display_name = base::ASCIIToUTF16("mail.google.com");
230 EXPECT_EQ(expected_display_name,
231 PlatformNotificationServiceImpl::WebOriginDisplayName(https_origin,
232 language));
234 GURL https_origin_standard_port("https://mail.google.com:443/");
235 expected_display_name = base::ASCIIToUTF16("mail.google.com");
236 EXPECT_EQ(expected_display_name,
237 PlatformNotificationServiceImpl::WebOriginDisplayName(
238 https_origin_standard_port, language));
240 GURL https_origin_nonstandard_port("https://mail.google.com:444/");
241 expected_display_name = base::ASCIIToUTF16("mail.google.com:444");
242 EXPECT_EQ(expected_display_name,
243 PlatformNotificationServiceImpl::WebOriginDisplayName(
244 https_origin_nonstandard_port, language));
246 GURL http_origin("http://mail.google.com/");
247 expected_display_name = base::ASCIIToUTF16("http://mail.google.com");
248 EXPECT_EQ(expected_display_name,
249 PlatformNotificationServiceImpl::WebOriginDisplayName(http_origin,
250 language));
252 GURL http_origin_standard_port("http://mail.google.com:80/");
253 expected_display_name = base::ASCIIToUTF16("http://mail.google.com");
254 EXPECT_EQ(expected_display_name,
255 PlatformNotificationServiceImpl::WebOriginDisplayName(
256 http_origin_standard_port, language));
258 GURL http_origin_nonstandard_port("http://mail.google.com:81/");
259 expected_display_name = base::ASCIIToUTF16("http://mail.google.com:81");
260 EXPECT_EQ(expected_display_name,
261 PlatformNotificationServiceImpl::WebOriginDisplayName(
262 http_origin_nonstandard_port, language));
263 // TODO(dewittj): Add file origin once it's supported.
266 TEST_F(PlatformNotificationServiceTest, NotificationPermissionLastUsage) {
267 // Both page and persistent notifications should update the last usage
268 // time of the notification permission for the origin.
269 GURL origin("https://chrome.com/");
270 base::Time begin_time;
272 CreateSimplePageNotification();
274 base::Time after_page_notification =
275 profile()->GetHostContentSettingsMap()->GetLastUsage(
276 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
277 EXPECT_GT(after_page_notification, begin_time);
279 // Ensure that there is at least some time between the two calls.
280 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
282 service()->DisplayPersistentNotification(
283 profile(), 42 /* sw_registration_id */, origin, SkBitmap(),
284 content::PlatformNotificationData());
286 base::Time after_persistent_notification =
287 profile()->GetHostContentSettingsMap()->GetLastUsage(
288 origin, origin, CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
289 EXPECT_GT(after_persistent_notification, after_page_notification);
292 #if defined(ENABLE_EXTENSIONS)
294 TEST_F(PlatformNotificationServiceTest, ExtensionPermissionChecks) {
295 #if defined(OS_CHROMEOS)
296 // The ExtensionService on Chrome OS requires these objects to be initialized.
297 chromeos::ScopedTestDeviceSettingsService test_device_settings_service;
298 chromeos::ScopedTestCrosSettings test_cros_settings;
299 chromeos::ScopedTestUserManager test_user_manager;
300 #endif
302 base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
303 extensions::TestExtensionSystem* test_extension_system =
304 static_cast<extensions::TestExtensionSystem*>(
305 extensions::ExtensionSystem::Get(profile()));
307 ExtensionService* extension_service =
308 test_extension_system->CreateExtensionService(
309 &command_line, base::FilePath() /* install_directory */,
310 false /* autoupdate_enabled*/);
312 // Create a mocked extension that has the notifications API permission.
313 scoped_refptr<extensions::Extension> extension =
314 extensions::ExtensionBuilder().SetManifest(
315 extensions::DictionaryBuilder()
316 .Set("name", "NotificationTest")
317 .Set("version", "1.0")
318 .Set("manifest_version", 2)
319 .Set("description", "Test Extension")
320 .Set("permissions",
321 extensions::ListBuilder().Append("notifications"))).Build();
323 // Install the extension on the faked extension service, and verify that it
324 // has been added to the extension registry successfully.
325 extension_service->AddExtension(extension.get());
326 extensions::ExtensionRegistry* registry =
327 extensions::ExtensionRegistry::Get(profile());
329 ASSERT_TRUE(registry->GetExtensionById(
330 extension->id(), extensions::ExtensionRegistry::ENABLED));
332 const int kFakeRenderProcessId = 42;
334 // Mock that the extension is running in a fake render process id.
335 extensions::ProcessMap::Get(profile())->Insert(extension->id(),
336 kFakeRenderProcessId,
337 -1 /* site_instance_id */);
339 // Verify that the service indicates that permission has been granted. We only
340 // check the UI thread-method for now, as that's the one guarding the behavior
341 // in the browser process.
342 EXPECT_EQ(blink::WebNotificationPermissionAllowed,
343 service()->CheckPermissionOnUIThread(profile(),
344 extension->url(),
345 kFakeRenderProcessId));
348 #endif // defined(ENABLE_EXTENSIONS)