Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/notifications/notification_platform_bridge_linux.h" | 5 #include "chrome/browser/notifications/notification_platform_bridge_linux.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/i18n/number_formatting.h" | |
| 11 #include "base/logging.h" | 12 #include "base/logging.h" |
| 12 #include "base/memory/ptr_util.h" | 13 #include "base/memory/ptr_util.h" |
| 13 #include "base/memory/ref_counted.h" | 14 #include "base/memory/ref_counted.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
| 15 #include "chrome/browser/notifications/notification.h" | 16 #include "chrome/browser/notifications/notification.h" |
| 16 #include "chrome/browser/notifications/notification_test_util.h" | 17 #include "chrome/browser/notifications/notification_test_util.h" |
| 17 #include "content/public/test/test_browser_thread_bundle.h" | 18 #include "content/public/test/test_browser_thread_bundle.h" |
| 18 #include "content/public/test/test_utils.h" | 19 #include "content/public/test/test_utils.h" |
| 19 #include "dbus/mock_bus.h" | 20 #include "dbus/mock_bus.h" |
| 20 #include "dbus/mock_object_proxy.h" | 21 #include "dbus/mock_object_proxy.h" |
| 21 #include "testing/gmock/include/gmock/gmock.h" | 22 #include "testing/gmock/include/gmock/gmock.h" |
| 22 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
| 23 | 24 |
| 24 using testing::_; | 25 using testing::_; |
| 25 using testing::Return; | 26 using testing::Return; |
| 26 using testing::StrictMock; | 27 using testing::StrictMock; |
| 27 | 28 |
| 28 namespace { | 29 namespace { |
| 29 | 30 |
| 30 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications"; | 31 const char kFreedesktopNotificationsName[] = "org.freedesktop.Notifications"; |
| 31 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications"; | 32 const char kFreedesktopNotificationsPath[] = "/org/freedesktop/Notifications"; |
| 32 | 33 |
| 33 ACTION_P(RegisterSignalCallback, callback_addr) { | 34 class NotificationBuilder { |
| 34 *callback_addr = arg2; | 35 public: |
| 35 arg3.Run("" /* interface_name */, "" /* signal_name */, true /* success */); | 36 explicit NotificationBuilder(const std::string& id) |
| 36 } | 37 : notification_(message_center::NOTIFICATION_TYPE_SIMPLE, |
| 38 base::string16(), | |
| 39 base::string16(), | |
| 40 gfx::Image(), | |
| 41 message_center::NotifierId(GURL()), | |
| 42 base::string16(), | |
| 43 GURL(), | |
| 44 id, | |
| 45 message_center::RichNotificationData(), | |
| 46 new MockNotificationDelegate(id)) {} | |
| 37 | 47 |
| 38 ACTION_P(OnGetCapabilities, capabilities) { | 48 Notification GetResult() { return notification_; } |
| 39 // MockObjectProxy::CallMethodAndBlock will wrap the return value in | |
| 40 // a unique_ptr. | |
| 41 dbus::Response* response = dbus::Response::CreateEmpty().release(); | |
| 42 dbus::MessageWriter writer(response); | |
| 43 writer.AppendArrayOfStrings(capabilities); | |
| 44 return response; | |
| 45 } | |
| 46 | 49 |
| 47 ACTION_P(OnGetServerInformation, spec_version) { | 50 NotificationBuilder& SetProgress(int progress) { |
| 48 dbus::Response* response = dbus::Response::CreateEmpty().release(); | 51 notification_.set_progress(progress); |
| 49 dbus::MessageWriter writer(response); | 52 return *this; |
| 50 writer.AppendString(""); // name | 53 } |
| 51 writer.AppendString(""); // vendor | |
| 52 writer.AppendString(""); // version | |
| 53 writer.AppendString(spec_version); | |
| 54 return response; | |
| 55 } | |
| 56 | 54 |
| 57 ACTION_P(OnNotify, id) { | 55 NotificationBuilder& SetTitle(const base::string16& title) { |
| 56 notification_.set_title(title); | |
| 57 return *this; | |
| 58 } | |
| 59 | |
| 60 NotificationBuilder& SetType(message_center::NotificationType type) { | |
| 61 notification_.set_type(type); | |
| 62 return *this; | |
| 63 } | |
| 64 | |
| 65 private: | |
| 66 Notification notification_; | |
| 67 }; | |
| 68 | |
| 69 struct NotificationRequest { | |
|
Lei Zhang
2017/05/10 20:45:28
Is this going to have more members later?
Tom (Use chromium acct)
2017/05/10 21:05:44
Yes:
https://codereview.chromium.org/2875443002/
| |
| 70 std::string summary; | |
| 71 }; | |
| 72 | |
| 73 NotificationRequest ParseRequest(dbus::MethodCall* method_call) { | |
| 58 // The "Notify" message must have type (susssasa{sv}i). | 74 // The "Notify" message must have type (susssasa{sv}i). |
| 59 // https://developer.gnome.org/notification-spec/#command-notify | 75 // https://developer.gnome.org/notification-spec/#command-notify |
| 60 dbus::MethodCall* method_call = arg0; | 76 NotificationRequest request; |
| 77 | |
| 61 dbus::MessageReader reader(method_call); | 78 dbus::MessageReader reader(method_call); |
| 62 std::string str; | 79 std::string str; |
| 63 uint32_t uint32; | 80 uint32_t uint32; |
| 64 int32_t int32; | 81 int32_t int32; |
| 65 EXPECT_TRUE(reader.PopString(&str)); | 82 EXPECT_TRUE(reader.PopString(&str)); // app_name |
| 66 EXPECT_TRUE(reader.PopUint32(&uint32)); | 83 EXPECT_TRUE(reader.PopUint32(&uint32)); // replaces_id |
| 67 EXPECT_TRUE(reader.PopString(&str)); | 84 EXPECT_TRUE(reader.PopString(&str)); // app_icon |
| 68 EXPECT_TRUE(reader.PopString(&str)); | 85 EXPECT_TRUE(reader.PopString(&request.summary)); // summary |
| 69 EXPECT_TRUE(reader.PopString(&str)); | 86 EXPECT_TRUE(reader.PopString(&str)); // body |
| 70 | 87 |
| 71 { | 88 { |
| 72 dbus::MessageReader actions_reader(nullptr); | 89 dbus::MessageReader actions_reader(nullptr); |
| 73 EXPECT_TRUE(reader.PopArray(&actions_reader)); | 90 EXPECT_TRUE(reader.PopArray(&actions_reader)); |
| 74 while (actions_reader.HasMoreData()) { | 91 while (actions_reader.HasMoreData()) { |
| 75 // Actions come in pairs. | 92 // Actions come in pairs. |
| 76 EXPECT_TRUE(actions_reader.PopString(&str)); | 93 EXPECT_TRUE(actions_reader.PopString(&str)); |
| 77 EXPECT_TRUE(actions_reader.PopString(&str)); | 94 EXPECT_TRUE(actions_reader.PopString(&str)); |
| 78 } | 95 } |
| 79 } | 96 } |
| 80 | 97 |
| 81 { | 98 { |
| 82 dbus::MessageReader hints_reader(nullptr); | 99 dbus::MessageReader hints_reader(nullptr); |
| 83 EXPECT_TRUE(reader.PopArray(&hints_reader)); | 100 EXPECT_TRUE(reader.PopArray(&hints_reader)); |
| 84 while (hints_reader.HasMoreData()) { | 101 while (hints_reader.HasMoreData()) { |
| 85 dbus::MessageReader dict_entry_reader(nullptr); | 102 dbus::MessageReader dict_entry_reader(nullptr); |
| 86 EXPECT_TRUE(hints_reader.PopDictEntry(&dict_entry_reader)); | 103 EXPECT_TRUE(hints_reader.PopDictEntry(&dict_entry_reader)); |
| 87 EXPECT_TRUE(dict_entry_reader.PopString(&str)); | 104 EXPECT_TRUE(dict_entry_reader.PopString(&str)); |
| 88 dbus::MessageReader variant_reader(nullptr); | 105 dbus::MessageReader variant_reader(nullptr); |
| 89 EXPECT_TRUE(dict_entry_reader.PopVariant(&variant_reader)); | 106 EXPECT_TRUE(dict_entry_reader.PopVariant(&variant_reader)); |
| 90 EXPECT_FALSE(dict_entry_reader.HasMoreData()); | 107 EXPECT_FALSE(dict_entry_reader.HasMoreData()); |
| 91 } | 108 } |
| 92 } | 109 } |
| 93 | 110 |
| 94 EXPECT_TRUE(reader.PopInt32(&int32)); | 111 EXPECT_TRUE(reader.PopInt32(&int32)); // expire_timeout |
| 95 EXPECT_FALSE(reader.HasMoreData()); | 112 EXPECT_FALSE(reader.HasMoreData()); |
| 96 | 113 |
| 114 return request; | |
| 115 } | |
| 116 | |
| 117 dbus::Response* GetIdResponse(uint32_t id) { | |
| 97 dbus::Response* response = dbus::Response::CreateEmpty().release(); | 118 dbus::Response* response = dbus::Response::CreateEmpty().release(); |
| 98 dbus::MessageWriter writer(response); | 119 dbus::MessageWriter writer(response); |
| 99 writer.AppendUint32(id); | 120 writer.AppendUint32(id); |
| 100 return response; | 121 return response; |
| 101 } | 122 } |
| 102 | 123 |
| 124 ACTION_P(RegisterSignalCallback, callback_addr) { | |
| 125 *callback_addr = arg2; | |
| 126 arg3.Run("" /* interface_name */, "" /* signal_name */, true /* success */); | |
| 127 } | |
| 128 | |
| 129 ACTION_P(OnGetCapabilities, capabilities) { | |
| 130 // MockObjectProxy::CallMethodAndBlock will wrap the return value in | |
| 131 // a unique_ptr. | |
| 132 dbus::Response* response = dbus::Response::CreateEmpty().release(); | |
| 133 dbus::MessageWriter writer(response); | |
| 134 writer.AppendArrayOfStrings(capabilities); | |
| 135 return response; | |
| 136 } | |
| 137 | |
| 138 ACTION_P(OnGetServerInformation, spec_version) { | |
| 139 dbus::Response* response = dbus::Response::CreateEmpty().release(); | |
| 140 dbus::MessageWriter writer(response); | |
| 141 writer.AppendString(""); // name | |
| 142 writer.AppendString(""); // vendor | |
| 143 writer.AppendString(""); // version | |
| 144 writer.AppendString(spec_version); | |
| 145 return response; | |
| 146 } | |
| 147 | |
| 148 ACTION_P(OnNotify, id) { | |
| 149 ParseRequest(arg0); | |
| 150 return GetIdResponse(id); | |
| 151 } | |
| 152 | |
| 103 ACTION(OnCloseNotification) { | 153 ACTION(OnCloseNotification) { |
| 104 // The "CloseNotification" message must have type (u). | 154 // The "CloseNotification" message must have type (u). |
| 105 // https://developer.gnome.org/notification-spec/#command-close-notification | 155 // https://developer.gnome.org/notification-spec/#command-close-notification |
| 106 dbus::MethodCall* method_call = arg0; | 156 dbus::MethodCall* method_call = arg0; |
| 107 dbus::MessageReader reader(method_call); | 157 dbus::MessageReader reader(method_call); |
| 108 uint32_t uint32; | 158 uint32_t uint32; |
| 109 EXPECT_TRUE(reader.PopUint32(&uint32)); | 159 EXPECT_TRUE(reader.PopUint32(&uint32)); |
| 110 EXPECT_FALSE(reader.HasMoreData()); | 160 EXPECT_FALSE(reader.HasMoreData()); |
| 111 | 161 |
| 112 return dbus::Response::CreateEmpty().release(); | 162 return dbus::Response::CreateEmpty().release(); |
| 113 } | 163 } |
| 114 | 164 |
| 115 // Matches a method call to the specified dbus target. | 165 // Matches a method call to the specified dbus target. |
| 116 MATCHER_P(Calls, member, "") { | 166 MATCHER_P(Calls, member, "") { |
| 117 return arg->GetMember() == member; | 167 return arg->GetMember() == member; |
| 118 } | 168 } |
| 119 | 169 |
| 120 Notification CreateNotification(const char* id, | |
| 121 const char* title, | |
| 122 const char* body, | |
| 123 const char* origin) { | |
| 124 message_center::RichNotificationData optional_fields; | |
| 125 GURL url = GURL(origin); | |
| 126 return Notification(message_center::NOTIFICATION_TYPE_SIMPLE, | |
| 127 base::UTF8ToUTF16(title), base::UTF8ToUTF16(body), | |
| 128 gfx::Image(), message_center::NotifierId(url), | |
| 129 base::UTF8ToUTF16("Notifier's Name"), url, id, | |
| 130 optional_fields, new MockNotificationDelegate(id)); | |
| 131 } | |
| 132 | |
| 133 } // namespace | 170 } // namespace |
| 134 | 171 |
| 135 class NotificationPlatformBridgeLinuxTest : public testing::Test { | 172 class NotificationPlatformBridgeLinuxTest : public testing::Test { |
| 136 public: | 173 public: |
| 137 NotificationPlatformBridgeLinuxTest() = default; | 174 NotificationPlatformBridgeLinuxTest() = default; |
| 138 ~NotificationPlatformBridgeLinuxTest() override = default; | 175 ~NotificationPlatformBridgeLinuxTest() override = default; |
| 139 | 176 |
| 140 void SetUp() override { | 177 void SetUp() override { |
| 141 mock_bus_ = new dbus::MockBus(dbus::Bus::Options()); | 178 mock_bus_ = new dbus::MockBus(dbus::Bus::Options()); |
| 142 mock_notification_proxy_ = new StrictMock<dbus::MockObjectProxy>( | 179 mock_notification_proxy_ = new StrictMock<dbus::MockObjectProxy>( |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 204 EXPECT_CALL(*mock_notification_proxy_.get(), | 241 EXPECT_CALL(*mock_notification_proxy_.get(), |
| 205 MockCallMethodAndBlock(Calls("Notify"), _)) | 242 MockCallMethodAndBlock(Calls("Notify"), _)) |
| 206 .WillOnce(OnNotify(1)); | 243 .WillOnce(OnNotify(1)); |
| 207 EXPECT_CALL(*mock_notification_proxy_.get(), | 244 EXPECT_CALL(*mock_notification_proxy_.get(), |
| 208 MockCallMethodAndBlock(Calls("CloseNotification"), _)) | 245 MockCallMethodAndBlock(Calls("CloseNotification"), _)) |
| 209 .WillOnce(OnCloseNotification()); | 246 .WillOnce(OnCloseNotification()); |
| 210 | 247 |
| 211 CreateNotificationBridgeLinux(); | 248 CreateNotificationBridgeLinux(); |
| 212 notification_bridge_linux_->Display(NotificationCommon::PERSISTENT, "", "", | 249 notification_bridge_linux_->Display(NotificationCommon::PERSISTENT, "", "", |
| 213 false, | 250 false, |
| 214 CreateNotification("id1", "", "", "")); | 251 NotificationBuilder("").GetResult()); |
| 215 notification_bridge_linux_->Close("", ""); | 252 notification_bridge_linux_->Close("", ""); |
| 216 } | 253 } |
| 254 | |
| 255 ACTION_P2(VerifySummary, summary, id) { | |
| 256 NotificationRequest request = ParseRequest(arg0); | |
| 257 EXPECT_EQ(summary, request.summary); | |
| 258 return GetIdResponse(id); | |
| 259 } | |
| 260 | |
| 261 TEST_F(NotificationPlatformBridgeLinuxTest, ProgressPercentageAddedToSummary) { | |
| 262 EXPECT_CALL(*mock_notification_proxy_.get(), | |
| 263 MockCallMethodAndBlock(Calls("Notify"), _)) | |
| 264 .WillOnce(VerifySummary( | |
| 265 base::UTF16ToUTF8(base::FormatPercent(42)) + " - The Title", 1)); | |
| 266 | |
| 267 CreateNotificationBridgeLinux(); | |
| 268 notification_bridge_linux_->Display( | |
| 269 NotificationCommon::PERSISTENT, "", "", false, | |
| 270 NotificationBuilder("") | |
| 271 .SetType(message_center::NOTIFICATION_TYPE_PROGRESS) | |
| 272 .SetProgress(42) | |
| 273 .SetTitle(base::UTF8ToUTF16("The Title")) | |
| 274 .GetResult()); | |
| 275 } | |
| OLD | NEW |