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 |