1 // Copyright (c) 2012 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/strings/string_number_conversions.h" 6 #include "base/strings/stringprintf.h" 7 #include "base/strings/utf_string_conversions.h" 8 #include "chrome/browser/browser_process.h" 9 #include "chrome/browser/extensions/api/notifications/notifications_api.h" 10 #include "chrome/browser/extensions/extension_apitest.h" 11 #include "chrome/browser/extensions/extension_function_test_utils.h" 12 #include "chrome/browser/notifications/notification.h" 13 #include "chrome/browser/notifications/notification_ui_manager.h" 14 #include "content/public/browser/notification_service.h" 15 #include "content/public/test/test_utils.h" 16 #include "extensions/browser/api/test/test_api.h" 17 #include "extensions/browser/notification_types.h" 18 #include "extensions/common/features/feature.h" 19 #include "extensions/common/test_util.h" 20 #include "extensions/test/result_catcher.h" 21 #include "ui/message_center/message_center.h" 22 #include "ui/message_center/notification_list.h" 23 #include "ui/message_center/notifier_settings.h" 24 25 using extensions::Extension; 26 using extensions::ResultCatcher; 27 28 namespace utils = extension_function_test_utils; 29 30 namespace { 31 32 // A class that waits for a |chrome.test.sendMessage| call, ignores the message, 33 // and writes down the user gesture status of the message. 34 class UserGestureCatcher : public content::NotificationObserver { 35 public: 36 UserGestureCatcher() : waiting_(false) { 37 registrar_.Add(this, 38 extensions::NOTIFICATION_EXTENSION_TEST_MESSAGE, 39 content::NotificationService::AllSources()); 40 } 41 42 virtual ~UserGestureCatcher() {} 43 44 bool GetNextResult() { 45 if (results_.empty()) { 46 waiting_ = true; 47 content::RunMessageLoop(); 48 waiting_ = false; 49 } 50 51 if (!results_.empty()) { 52 bool ret = results_.front(); 53 results_.pop_front(); 54 return ret; 55 } 56 NOTREACHED(); 57 return false; 58 } 59 60 private: 61 virtual void Observe(int type, 62 const content::NotificationSource& source, 63 const content::NotificationDetails& details) OVERRIDE { 64 results_.push_back( 65 static_cast<content::Source<extensions::TestSendMessageFunction> >( 66 source) 67 .ptr() 68 ->user_gesture()); 69 if (waiting_) 70 base::MessageLoopForUI::current()->Quit(); 71 } 72 73 content::NotificationRegistrar registrar_; 74 75 // A sequential list of user gesture notifications from the test extension(s). 76 std::deque<bool> results_; 77 78 // True if we're in a nested message loop waiting for results from 79 // the extension. 80 bool waiting_; 81 }; 82 83 class NotificationsApiTest : public ExtensionApiTest { 84 public: 85 const extensions::Extension* LoadExtensionAndWait( 86 const std::string& test_name) { 87 base::FilePath extdir = test_data_dir_.AppendASCII(test_name); 88 content::WindowedNotificationObserver page_created( 89 extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, 90 content::NotificationService::AllSources()); 91 const extensions::Extension* extension = LoadExtension(extdir); 92 if (extension) { 93 page_created.Wait(); 94 } 95 return extension; 96 } 97 }; 98 99 } // namespace 100 101 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestBasicUsage) { 102 ASSERT_TRUE(RunExtensionTest("notifications/api/basic_usage")) << message_; 103 } 104 105 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestEvents) { 106 ASSERT_TRUE(RunExtensionTest("notifications/api/events")) << message_; 107 } 108 109 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestCSP) { 110 ASSERT_TRUE(RunExtensionTest("notifications/api/csp")) << message_; 111 } 112 113 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestByUser) { 114 const extensions::Extension* extension = 115 LoadExtensionAndWait("notifications/api/by_user"); 116 ASSERT_TRUE(extension) << message_; 117 118 { 119 ResultCatcher catcher; 120 g_browser_process->message_center()->RemoveNotification( 121 extension->id() + "-FOO", 122 false); 123 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 124 } 125 126 { 127 ResultCatcher catcher; 128 g_browser_process->message_center()->RemoveNotification( 129 extension->id() + "-BAR", 130 true); 131 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 132 } 133 134 { 135 ResultCatcher catcher; 136 g_browser_process->message_center()->RemoveAllNotifications(false); 137 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 138 } 139 { 140 ResultCatcher catcher; 141 g_browser_process->message_center()->RemoveAllNotifications(true); 142 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 143 } 144 } 145 146 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestPartialUpdate) { 147 ASSERT_TRUE(RunExtensionTest("notifications/api/partial_update")) << message_; 148 const extensions::Extension* extension = GetSingleLoadedExtension(); 149 ASSERT_TRUE(extension) << message_; 150 151 const char kNewTitle[] = "Changed!"; 152 const char kNewMessage[] = "Too late! The show ended yesterday"; 153 int kNewPriority = 2; 154 155 const message_center::NotificationList::Notifications& notifications = 156 g_browser_process->message_center()->GetVisibleNotifications(); 157 ASSERT_EQ(1u, notifications.size()); 158 message_center::Notification* notification = *(notifications.begin()); 159 LOG(INFO) << "Notification ID: " << notification->id(); 160 161 EXPECT_EQ(base::ASCIIToUTF16(kNewTitle), notification->title()); 162 EXPECT_EQ(base::ASCIIToUTF16(kNewMessage), notification->message()); 163 EXPECT_EQ(kNewPriority, notification->priority()); 164 EXPECT_EQ(0u, notification->buttons().size()); 165 } 166 167 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestGetPermissionLevel) { 168 scoped_refptr<Extension> empty_extension( 169 extensions::test_util::CreateEmptyExtension()); 170 171 // Get permission level for the extension whose notifications are enabled. 172 { 173 scoped_refptr<extensions::NotificationsGetPermissionLevelFunction> 174 notification_function( 175 new extensions::NotificationsGetPermissionLevelFunction()); 176 177 notification_function->set_extension(empty_extension.get()); 178 notification_function->set_has_callback(true); 179 180 scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult( 181 notification_function.get(), 182 "[]", 183 browser(), 184 utils::NONE)); 185 186 EXPECT_EQ(base::Value::TYPE_STRING, result->GetType()); 187 std::string permission_level; 188 EXPECT_TRUE(result->GetAsString(&permission_level)); 189 EXPECT_EQ("granted", permission_level); 190 } 191 192 // Get permission level for the extension whose notifications are disabled. 193 { 194 scoped_refptr<extensions::NotificationsGetPermissionLevelFunction> 195 notification_function( 196 new extensions::NotificationsGetPermissionLevelFunction()); 197 198 notification_function->set_extension(empty_extension.get()); 199 notification_function->set_has_callback(true); 200 201 message_center::NotifierId notifier_id( 202 message_center::NotifierId::APPLICATION, 203 empty_extension->id()); 204 message_center::Notifier notifier(notifier_id, base::string16(), true); 205 g_browser_process->message_center()->GetNotifierSettingsProvider()-> 206 SetNotifierEnabled(notifier, false); 207 208 scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult( 209 notification_function.get(), 210 "[]", 211 browser(), 212 utils::NONE)); 213 214 EXPECT_EQ(base::Value::TYPE_STRING, result->GetType()); 215 std::string permission_level; 216 EXPECT_TRUE(result->GetAsString(&permission_level)); 217 EXPECT_EQ("denied", permission_level); 218 } 219 } 220 221 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestOnPermissionLevelChanged) { 222 const extensions::Extension* extension = 223 LoadExtensionAndWait("notifications/api/permission"); 224 ASSERT_TRUE(extension) << message_; 225 226 // Test permission level changing from granted to denied. 227 { 228 ResultCatcher catcher; 229 230 message_center::NotifierId notifier_id( 231 message_center::NotifierId::APPLICATION, 232 extension->id()); 233 message_center::Notifier notifier(notifier_id, base::string16(), true); 234 g_browser_process->message_center()->GetNotifierSettingsProvider()-> 235 SetNotifierEnabled(notifier, false); 236 237 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 238 } 239 240 // Test permission level changing from denied to granted. 241 { 242 ResultCatcher catcher; 243 244 message_center::NotifierId notifier_id( 245 message_center::NotifierId::APPLICATION, 246 extension->id()); 247 message_center::Notifier notifier(notifier_id, base::string16(), false); 248 g_browser_process->message_center()->GetNotifierSettingsProvider()-> 249 SetNotifierEnabled(notifier, true); 250 251 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 252 } 253 } 254 255 IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestUserGesture) { 256 const extensions::Extension* extension = 257 LoadExtensionAndWait("notifications/api/user_gesture"); 258 ASSERT_TRUE(extension) << message_; 259 260 const message_center::NotificationList::Notifications& notifications = 261 g_browser_process->message_center()->GetVisibleNotifications(); 262 ASSERT_EQ(1u, notifications.size()); 263 message_center::Notification* notification = *(notifications.begin()); 264 265 { 266 UserGestureCatcher catcher; 267 notification->ButtonClick(0); 268 EXPECT_TRUE(catcher.GetNextResult()); 269 notification->Click(); 270 EXPECT_TRUE(catcher.GetNextResult()); 271 notification->Close(true); 272 EXPECT_TRUE(catcher.GetNextResult()); 273 notification->Close(false); 274 EXPECT_FALSE(catcher.GetNextResult()); 275 } 276 } 277