// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/notifications/notifications_api.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_function_test_utils.h" #include "chrome/browser/notifications/notification.h" #include "chrome/browser/notifications/notification_ui_manager.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_utils.h" #include "extensions/browser/api/test/test_api.h" #include "extensions/browser/notification_types.h" #include "extensions/common/features/feature.h" #include "extensions/common/test_util.h" #include "extensions/test/result_catcher.h" #include "ui/message_center/message_center.h" #include "ui/message_center/notification_list.h" #include "ui/message_center/notifier_settings.h" using extensions::Extension; using extensions::ResultCatcher; namespace utils = extension_function_test_utils; namespace { // A class that waits for a |chrome.test.sendMessage| call, ignores the message, // and writes down the user gesture status of the message. class UserGestureCatcher : public content::NotificationObserver { public: UserGestureCatcher() : waiting_(false) { registrar_.Add(this, extensions::NOTIFICATION_EXTENSION_TEST_MESSAGE, content::NotificationService::AllSources()); } virtual ~UserGestureCatcher() {} bool GetNextResult() { if (results_.empty()) { waiting_ = true; content::RunMessageLoop(); waiting_ = false; } if (!results_.empty()) { bool ret = results_.front(); results_.pop_front(); return ret; } NOTREACHED(); return false; } private: virtual void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE { results_.push_back( static_cast >( source) .ptr() ->user_gesture()); if (waiting_) base::MessageLoopForUI::current()->Quit(); } content::NotificationRegistrar registrar_; // A sequential list of user gesture notifications from the test extension(s). std::deque results_; // True if we're in a nested message loop waiting for results from // the extension. bool waiting_; }; class NotificationsApiTest : public ExtensionApiTest { public: const extensions::Extension* LoadExtensionAndWait( const std::string& test_name) { base::FilePath extdir = test_data_dir_.AppendASCII(test_name); content::WindowedNotificationObserver page_created( extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, content::NotificationService::AllSources()); const extensions::Extension* extension = LoadExtension(extdir); if (extension) { page_created.Wait(); } return extension; } }; } // namespace IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestBasicUsage) { ASSERT_TRUE(RunExtensionTest("notifications/api/basic_usage")) << message_; } IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestEvents) { ASSERT_TRUE(RunExtensionTest("notifications/api/events")) << message_; } IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestCSP) { ASSERT_TRUE(RunExtensionTest("notifications/api/csp")) << message_; } IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestByUser) { const extensions::Extension* extension = LoadExtensionAndWait("notifications/api/by_user"); ASSERT_TRUE(extension) << message_; { ResultCatcher catcher; g_browser_process->message_center()->RemoveNotification( extension->id() + "-FOO", false); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } { ResultCatcher catcher; g_browser_process->message_center()->RemoveNotification( extension->id() + "-BAR", true); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } { ResultCatcher catcher; g_browser_process->message_center()->RemoveAllNotifications(false); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } { ResultCatcher catcher; g_browser_process->message_center()->RemoveAllNotifications(true); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } } IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestPartialUpdate) { ASSERT_TRUE(RunExtensionTest("notifications/api/partial_update")) << message_; const extensions::Extension* extension = GetSingleLoadedExtension(); ASSERT_TRUE(extension) << message_; const char kNewTitle[] = "Changed!"; const char kNewMessage[] = "Too late! The show ended yesterday"; int kNewPriority = 2; const message_center::NotificationList::Notifications& notifications = g_browser_process->message_center()->GetVisibleNotifications(); ASSERT_EQ(1u, notifications.size()); message_center::Notification* notification = *(notifications.begin()); LOG(INFO) << "Notification ID: " << notification->id(); EXPECT_EQ(base::ASCIIToUTF16(kNewTitle), notification->title()); EXPECT_EQ(base::ASCIIToUTF16(kNewMessage), notification->message()); EXPECT_EQ(kNewPriority, notification->priority()); EXPECT_EQ(0u, notification->buttons().size()); } IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestGetPermissionLevel) { scoped_refptr empty_extension( extensions::test_util::CreateEmptyExtension()); // Get permission level for the extension whose notifications are enabled. { scoped_refptr notification_function( new extensions::NotificationsGetPermissionLevelFunction()); notification_function->set_extension(empty_extension.get()); notification_function->set_has_callback(true); scoped_ptr result(utils::RunFunctionAndReturnSingleResult( notification_function.get(), "[]", browser(), utils::NONE)); EXPECT_EQ(base::Value::TYPE_STRING, result->GetType()); std::string permission_level; EXPECT_TRUE(result->GetAsString(&permission_level)); EXPECT_EQ("granted", permission_level); } // Get permission level for the extension whose notifications are disabled. { scoped_refptr notification_function( new extensions::NotificationsGetPermissionLevelFunction()); notification_function->set_extension(empty_extension.get()); notification_function->set_has_callback(true); message_center::NotifierId notifier_id( message_center::NotifierId::APPLICATION, empty_extension->id()); message_center::Notifier notifier(notifier_id, base::string16(), true); g_browser_process->message_center()->GetNotifierSettingsProvider()-> SetNotifierEnabled(notifier, false); scoped_ptr result(utils::RunFunctionAndReturnSingleResult( notification_function.get(), "[]", browser(), utils::NONE)); EXPECT_EQ(base::Value::TYPE_STRING, result->GetType()); std::string permission_level; EXPECT_TRUE(result->GetAsString(&permission_level)); EXPECT_EQ("denied", permission_level); } } IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestOnPermissionLevelChanged) { const extensions::Extension* extension = LoadExtensionAndWait("notifications/api/permission"); ASSERT_TRUE(extension) << message_; // Test permission level changing from granted to denied. { ResultCatcher catcher; message_center::NotifierId notifier_id( message_center::NotifierId::APPLICATION, extension->id()); message_center::Notifier notifier(notifier_id, base::string16(), true); g_browser_process->message_center()->GetNotifierSettingsProvider()-> SetNotifierEnabled(notifier, false); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } // Test permission level changing from denied to granted. { ResultCatcher catcher; message_center::NotifierId notifier_id( message_center::NotifierId::APPLICATION, extension->id()); message_center::Notifier notifier(notifier_id, base::string16(), false); g_browser_process->message_center()->GetNotifierSettingsProvider()-> SetNotifierEnabled(notifier, true); EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); } } IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestUserGesture) { const extensions::Extension* extension = LoadExtensionAndWait("notifications/api/user_gesture"); ASSERT_TRUE(extension) << message_; const message_center::NotificationList::Notifications& notifications = g_browser_process->message_center()->GetVisibleNotifications(); ASSERT_EQ(1u, notifications.size()); message_center::Notification* notification = *(notifications.begin()); { UserGestureCatcher catcher; notification->ButtonClick(0); EXPECT_TRUE(catcher.GetNextResult()); notification->Click(); EXPECT_TRUE(catcher.GetNextResult()); notification->Close(true); EXPECT_TRUE(catcher.GetNextResult()); notification->Close(false); EXPECT_FALSE(catcher.GetNextResult()); } }