Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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. | |
| 4 | |
| 5 #include "chrome/common/extensions/permissions/chrome_permission_message_provide r.h" | |
| 6 | |
| 7 #include "base/memory/scoped_ptr.h" | |
| 8 #include "base/strings/utf_string_conversions.h" | |
| 9 #include "chrome/browser/extensions/extension_service.h" | |
| 10 #include "chrome/browser/extensions/extension_service_test_base.h" | |
| 11 #include "chrome/browser/extensions/permissions_updater.h" | |
| 12 #include "chrome/browser/profiles/profile.h" | |
| 13 #include "chrome/grit/generated_resources.h" | |
| 14 #include "components/crx_file/id_util.h" | |
| 15 #include "extensions/browser/extension_prefs.h" | |
| 16 #include "extensions/browser/extension_registry.h" | |
| 17 #include "extensions/common/extension_builder.h" | |
| 18 #include "extensions/common/manifest.h" | |
| 19 #include "extensions/common/manifest_handlers/permissions_parser.h" | |
| 20 #include "extensions/common/permissions/permissions_data.h" | |
| 21 #include "extensions/common/test_util.h" | |
| 22 #include "testing/gtest/include/gtest/gtest.h" | |
| 23 #include "ui/base/l10n/l10n_util.h" | |
|
sashab
2014/09/23 04:52:56
Some of these #includes violate checkdeps rules:
scheib
2014/09/23 17:10:54
Looking into this raises a few questions:
1. Shou
sashab
2014/09/24 23:23:49
I'm actually really glad you brought this up - it
| |
| 24 | |
| 25 namespace extensions { | |
| 26 | |
| 27 // Tests that ChromePermissionMessageProvider provides not only correct, but | |
| 28 // meaningful permission messages. | |
| 29 // There are two main types of permission messages generated that we need to | |
| 30 // test: | |
| 31 // 1. The full set of required permissions, displayed at install time (or when | |
| 32 // the app has been disabled automatically and needs to be re-enabled) | |
| 33 // 2. The various combinations of optional permissions, displayed in a prompt | |
| 34 // when confirming the permission during runtime | |
| 35 // 3. The split set of required/optional permissions, as displayed in the App | |
| 36 // Info dialog, where the optional permissions are individually revokable. | |
| 37 // Some of these tests are currently 'anti-tests' - they demonstrate existing | |
|
scheib
2014/09/23 17:10:54
Which ones? Can I search this file for TODO or 'An
sashab
2014/09/24 23:23:49
Preceded them with 'AntiTest_'.
| |
| 38 // problematic functionality. These tests will be changed as the correct | |
| 39 // behaviour is implemented. | |
| 40 class ChromePermissionMessageProviderUnittest | |
| 41 : public ExtensionServiceTestBase { | |
| 42 public: | |
| 43 ChromePermissionMessageProviderUnittest() | |
| 44 : message_provider_(new ChromePermissionMessageProvider()) {} | |
| 45 virtual ~ChromePermissionMessageProviderUnittest() {} | |
| 46 | |
| 47 // Overridden from testing::Test: | |
| 48 virtual void SetUp() OVERRIDE { | |
| 49 ExtensionServiceTestBase::SetUp(); | |
| 50 InitializeExtensionService(CreateDefaultInitParams()); | |
| 51 InitializeProcessManager(); | |
| 52 } | |
| 53 | |
| 54 protected: | |
| 55 // Overridden from views::WidgetObserver: | |
| 56 void InstallApp(Profile* profile, const Extension* app) { | |
| 57 service()->AddExtension(app); | |
| 58 } | |
| 59 | |
| 60 void UninstallApp(const std::string& app_id) { | |
| 61 service()->UninstallExtension(app_id, | |
| 62 UninstallReason::UNINSTALL_REASON_FOR_TESTING, | |
| 63 base::Closure(), | |
| 64 NULL); | |
| 65 } | |
| 66 | |
| 67 void CreateAppWithPermissions(const std::string id_seed, | |
|
scheib
2014/09/23 17:10:54
Do we need an id_seed that varies between tests? C
sashab
2014/09/24 23:23:48
Now uses a constant.
| |
| 68 ListBuilder& required_permissions, | |
| 69 ListBuilder& optional_permissions) { | |
| 70 app_ = test_util::BuildApp(ExtensionBuilder().Pass()) | |
| 71 .MergeManifest( | |
| 72 DictionaryBuilder() | |
| 73 .Set("permissions", required_permissions) | |
| 74 .Set("optional_permissions", optional_permissions)) | |
| 75 .SetID(crx_file::id_util::GenerateId(id_seed)) | |
| 76 .SetLocation(Manifest::INTERNAL) | |
| 77 .Build(); | |
| 78 } | |
| 79 | |
| 80 void CreateExtensionWithPermissions(const std::string id_seed, | |
|
scheib
2014/09/23 17:10:54
ditto for id_seed here
sashab
2014/09/24 23:23:49
Done.
| |
| 81 ListBuilder& required_permissions, | |
| 82 ListBuilder& optional_permissions) { | |
| 83 app_ = test_util::BuildExtension(ExtensionBuilder().Pass()) | |
| 84 .MergeManifest( | |
| 85 DictionaryBuilder() | |
| 86 .Set("permissions", required_permissions) | |
| 87 .Set("optional_permissions", optional_permissions)) | |
| 88 .SetID(crx_file::id_util::GenerateId(id_seed)) | |
| 89 .SetLocation(Manifest::INTERNAL) | |
| 90 .Build(); | |
| 91 } | |
| 92 | |
| 93 scoped_refptr<PermissionSet> PermissionSetFromAPIPermissions( | |
| 94 APIPermissionSet& permissions) { | |
| 95 scoped_refptr<PermissionSet> permission_set = new PermissionSet( | |
| 96 permissions, ManifestPermissionSet(), URLPatternSet(), URLPatternSet()); | |
| 97 return permission_set; | |
| 98 } | |
| 99 | |
| 100 // Returns the permission messages that would display in the prompt that | |
| 101 // requests the given permissions for the current |app_|. | |
| 102 std::vector<base::string16> OptionalPermissionsRequestPromptMessages( | |
| 103 APIPermissionSet& permissions) { | |
| 104 scoped_refptr<PermissionSet> permission_set = new PermissionSet( | |
| 105 permissions, ManifestPermissionSet(), URLPatternSet(), URLPatternSet()); | |
| 106 permission_set = PermissionSet::CreateDifference( | |
| 107 permission_set.get(), granted_permissions().get()); | |
| 108 return message_provider_->GetWarningMessages(permission_set.get(), | |
| 109 app_->GetType()); | |
| 110 } | |
| 111 | |
| 112 void GrantPermissions(scoped_refptr<const PermissionSet> permissions) { | |
| 113 PermissionsUpdater perms_updater(profile()); | |
| 114 perms_updater.AddPermissions(app_.get(), permissions.get()); | |
| 115 } | |
| 116 | |
| 117 scoped_refptr<const PermissionSet> active_permissions() { | |
| 118 return app_->permissions_data()->active_permissions(); | |
| 119 } | |
| 120 | |
| 121 scoped_refptr<const PermissionSet> withheld_permissions() { | |
| 122 return app_->permissions_data()->withheld_permissions(); | |
| 123 } | |
| 124 | |
| 125 scoped_refptr<const PermissionSet> granted_permissions() { | |
| 126 return ExtensionPrefs::Get(profile())->GetGrantedPermissions(app_->id()); | |
| 127 } | |
| 128 | |
| 129 scoped_refptr<const PermissionSet> required_permissions() { | |
| 130 return PermissionsParser::GetRequiredPermissions(app_.get()); | |
| 131 } | |
| 132 | |
| 133 scoped_refptr<const PermissionSet> optional_permissions() { | |
| 134 return PermissionsParser::GetOptionalPermissions(app_.get()); | |
| 135 } | |
| 136 | |
| 137 std::vector<base::string16> messages( | |
|
scheib
2014/09/23 17:10:54
Simplify test code by having the 'required_permiss
sashab
2014/09/24 23:23:48
Good idea. Done :)
| |
| 138 scoped_refptr<const PermissionSet> permissions) { | |
| 139 return message_provider_->GetWarningMessages(permissions.get(), | |
| 140 app_->GetType()); | |
| 141 } | |
| 142 | |
| 143 scoped_ptr<ChromePermissionMessageProvider> message_provider_; | |
| 144 scoped_refptr<const Extension> app_; | |
| 145 | |
| 146 private: | |
| 147 DISALLOW_COPY_AND_ASSIGN(ChromePermissionMessageProviderUnittest); | |
| 148 }; | |
| 149 | |
| 150 // If an app has both the 'serial' and 'USB' permission, they should coalesce | |
| 151 // into a single permission message. | |
| 152 TEST_F(ChromePermissionMessageProviderUnittest, | |
| 153 RequiredPermissionMessagesCoalesce) { | |
| 154 CreateAppWithPermissions("app", | |
| 155 ListBuilder().Append("serial").Append("usb").Pass(), | |
| 156 ListBuilder().Pass()); | |
| 157 service()->AddExtension(app_.get()); | |
| 158 | |
| 159 std::vector<base::string16> required_permission_messages = | |
| 160 messages(required_permissions()); | |
| 161 ASSERT_EQ(1U, required_permission_messages.size()); | |
| 162 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_USB_SERIAL), | |
| 163 base::UTF16ToUTF8(required_permission_messages[0])); | |
| 164 | |
| 165 std::vector<base::string16> optional_permission_messages = | |
| 166 messages(optional_permissions()); | |
| 167 ASSERT_EQ(0U, optional_permission_messages.size()); | |
| 168 } | |
| 169 | |
| 170 // If an app has both the 'history' and 'tabs' permission, one should hide the | |
| 171 // other (the 'history' permission has superset permissions). | |
| 172 TEST_F(ChromePermissionMessageProviderUnittest, HistoryHidesTabsMessage) { | |
| 173 CreateExtensionWithPermissions( | |
| 174 "app", | |
| 175 ListBuilder().Append("tabs").Append("history").Pass(), | |
| 176 ListBuilder().Pass()); | |
| 177 service()->AddExtension(app_.get()); | |
| 178 | |
| 179 std::vector<base::string16> required_permission_messages = | |
| 180 messages(required_permissions()); | |
| 181 ASSERT_EQ(1U, required_permission_messages.size()); | |
| 182 EXPECT_EQ( | |
| 183 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), | |
| 184 base::UTF16ToUTF8(required_permission_messages[0])); | |
| 185 | |
| 186 std::vector<base::string16> optional_permission_messages = | |
| 187 messages(optional_permissions()); | |
| 188 ASSERT_EQ(0U, optional_permission_messages.size()); | |
| 189 } | |
| 190 | |
| 191 // If an app requests the 'history' permission, but already has the 'tabs' | |
| 192 // permission, only the new coalesced message is displayed. | |
| 193 TEST_F(ChromePermissionMessageProviderUnittest, | |
| 194 MixedPermissionMessagesCoalesceOnceGranted) { | |
| 195 CreateExtensionWithPermissions("app", | |
| 196 ListBuilder().Append("tabs").Pass(), | |
| 197 ListBuilder().Append("history").Pass()); | |
| 198 service()->AddExtension(app_.get()); | |
| 199 | |
| 200 std::vector<base::string16> required_permission_messages = | |
| 201 messages(required_permissions()); | |
| 202 ASSERT_EQ(1U, required_permission_messages.size()); | |
| 203 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), | |
| 204 base::UTF16ToUTF8(required_permission_messages[0])); | |
| 205 | |
| 206 std::vector<base::string16> optional_permission_messages = | |
| 207 messages(optional_permissions()); | |
| 208 ASSERT_EQ(1U, optional_permission_messages.size()); | |
| 209 EXPECT_EQ( | |
| 210 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), | |
| 211 base::UTF16ToUTF8(optional_permission_messages[0])); | |
| 212 | |
| 213 std::vector<base::string16> active_permission_messages = | |
| 214 messages(active_permissions()); | |
| 215 ASSERT_EQ(1U, active_permission_messages.size()); | |
| 216 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), | |
| 217 base::UTF16ToUTF8(active_permission_messages[0])); | |
| 218 | |
| 219 APIPermissionSet requested_optional_permissions; | |
| 220 requested_optional_permissions.insert(APIPermission::kHistory); | |
| 221 std::vector<base::string16> requested_optional_permission_messages = | |
| 222 OptionalPermissionsRequestPromptMessages(requested_optional_permissions); | |
| 223 ASSERT_EQ(1U, requested_optional_permission_messages.size()); | |
| 224 EXPECT_EQ( | |
| 225 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), | |
| 226 base::UTF16ToUTF8(requested_optional_permission_messages[0])); | |
| 227 | |
| 228 GrantPermissions( | |
| 229 PermissionSetFromAPIPermissions(requested_optional_permissions)); | |
| 230 | |
| 231 active_permission_messages = messages(active_permissions()); | |
| 232 ASSERT_EQ(1U, active_permission_messages.size()); | |
| 233 EXPECT_EQ( | |
| 234 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), | |
| 235 base::UTF16ToUTF8(active_permission_messages[0])); | |
| 236 } | |
| 237 | |
| 238 // If an app requests the 'tabs' permission but already has the 'history' | |
| 239 // permission, a prompt is displayed to request this permission, but it doesn't | |
| 240 // appear in the final list of permissions since it is a subset of an already | |
| 241 // granted permission. | |
| 242 TEST_F(ChromePermissionMessageProviderUnittest, | |
| 243 PromptCanRequestSubsetOfAlreadyGrantedPermissions) { | |
| 244 CreateExtensionWithPermissions("app", | |
| 245 ListBuilder().Append("history").Pass(), | |
| 246 ListBuilder().Append("tabs").Pass()); | |
| 247 service()->AddExtension(app_.get()); | |
| 248 | |
| 249 std::vector<base::string16> required_permission_messages = | |
| 250 messages(required_permissions()); | |
| 251 ASSERT_EQ(1U, required_permission_messages.size()); | |
| 252 EXPECT_EQ( | |
| 253 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), | |
| 254 base::UTF16ToUTF8(required_permission_messages[0])); | |
| 255 | |
| 256 std::vector<base::string16> optional_permission_messages = | |
| 257 messages(optional_permissions()); | |
| 258 ASSERT_EQ(1U, optional_permission_messages.size()); | |
| 259 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), | |
| 260 base::UTF16ToUTF8(optional_permission_messages[0])); | |
| 261 | |
| 262 std::vector<base::string16> active_permission_messages = | |
| 263 messages(active_permissions()); | |
| 264 ASSERT_EQ(1U, active_permission_messages.size()); | |
| 265 EXPECT_EQ( | |
| 266 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), | |
| 267 base::UTF16ToUTF8(active_permission_messages[0])); | |
| 268 | |
| 269 APIPermissionSet requested_optional_permissions; | |
| 270 requested_optional_permissions.insert(APIPermission::kTab); | |
| 271 std::vector<base::string16> requested_optional_permission_messages = | |
| 272 OptionalPermissionsRequestPromptMessages(requested_optional_permissions); | |
| 273 // TODO(sashab): This prompt should display no permissions, since READ is a | |
| 274 // subset permission of WRITE. | |
| 275 ASSERT_EQ(1U, requested_optional_permission_messages.size()); | |
| 276 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), | |
| 277 base::UTF16ToUTF8(requested_optional_permission_messages[0])); | |
| 278 | |
| 279 GrantPermissions( | |
| 280 PermissionSetFromAPIPermissions(requested_optional_permissions)); | |
| 281 | |
| 282 active_permission_messages = messages(active_permissions()); | |
| 283 ASSERT_EQ(1U, active_permission_messages.size()); | |
| 284 EXPECT_EQ( | |
| 285 l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_WRITE), | |
| 286 base::UTF16ToUTF8(active_permission_messages[0])); | |
| 287 } | |
| 288 | |
| 289 // If an app requests the 'sessions' permission, nothing is displayed in the | |
| 290 // permission request prompt, but the required permissions for the app are | |
| 291 // actually modified. | |
| 292 TEST_F(ChromePermissionMessageProviderUnittest, | |
| 293 PromptCanBeEmptyButCausesChangeInPermissions) { | |
| 294 CreateExtensionWithPermissions("app", | |
| 295 ListBuilder().Append("tabs").Pass(), | |
| 296 ListBuilder().Append("sessions").Pass()); | |
| 297 service()->AddExtension(app_.get()); | |
| 298 | |
| 299 std::vector<base::string16> required_permission_messages = | |
| 300 messages(required_permissions()); | |
| 301 ASSERT_EQ(1U, required_permission_messages.size()); | |
| 302 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), | |
| 303 base::UTF16ToUTF8(required_permission_messages[0])); | |
| 304 | |
| 305 std::vector<base::string16> optional_permission_messages = | |
| 306 messages(optional_permissions()); | |
| 307 ASSERT_EQ(0U, optional_permission_messages.size()); | |
| 308 | |
| 309 std::vector<base::string16> active_permission_messages = | |
| 310 messages(active_permissions()); | |
| 311 ASSERT_EQ(1U, active_permission_messages.size()); | |
| 312 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ), | |
| 313 base::UTF16ToUTF8(active_permission_messages[0])); | |
| 314 | |
| 315 APIPermissionSet requested_optional_permissions; | |
| 316 requested_optional_permissions.insert(APIPermission::kSessions); | |
| 317 std::vector<base::string16> requested_optional_permission_messages = | |
| 318 OptionalPermissionsRequestPromptMessages(requested_optional_permissions); | |
| 319 // TODO(sashab): This prompt should display the sessions permission message, | |
| 320 // as well as warn the user that it can affect the existing 'tab' permission. | |
| 321 ASSERT_EQ(0U, requested_optional_permission_messages.size()); | |
| 322 | |
| 323 GrantPermissions( | |
| 324 PermissionSetFromAPIPermissions(requested_optional_permissions)); | |
| 325 | |
| 326 active_permission_messages = messages(active_permissions()); | |
| 327 ASSERT_EQ(1U, active_permission_messages.size()); | |
| 328 EXPECT_EQ(l10n_util::GetStringUTF8( | |
| 329 IDS_EXTENSION_PROMPT_WARNING_HISTORY_READ_AND_SESSIONS), | |
| 330 base::UTF16ToUTF8(active_permission_messages[0])); | |
| 331 } | |
| 332 | |
| 333 } // namespace extensions | |
| OLD | NEW |