OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 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/run_loop.h" | |
6 #include "base/stringprintf.h" | |
7 #include "chrome/browser/extensions/blacklist.h" | |
8 #include "chrome/browser/extensions/extension_browsertest.h" | |
9 #include "chrome/browser/extensions/extension_service.h" | |
10 #include "chrome/browser/extensions/extension_system.h" | |
11 #include "chrome/browser/ui/browser.h" | |
12 #include "chrome/common/chrome_notification_types.h" | |
13 #include "chrome/common/extensions/extension.h" | |
14 #include "chrome/common/extensions/extension_constants.h" | |
15 #include "content/public/browser/notification_details.h" | |
16 #include "content/public/browser/notification_observer.h" | |
17 #include "content/public/browser/notification_registrar.h" | |
18 #include "content/public/browser/notification_source.h" | |
19 | |
20 namespace extensions { | |
21 | |
22 namespace { | |
23 | |
24 // Records notifications, but only for extensions with specific IDs. | |
25 class FilteringNotificationObserver : public content::NotificationObserver { | |
26 public: | |
27 FilteringNotificationObserver( | |
28 content::NotificationSource source, | |
29 const std::set<std::string>& extension_ids) | |
30 : extension_ids_(extension_ids) { | |
31 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, source); | |
32 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, source); | |
33 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, source); | |
34 } | |
35 | |
36 // Checks then clears notifications for our extensions. | |
37 testing::AssertionResult CheckNotifications(chrome::NotificationType type) { | |
38 return CheckNotifications(std::vector<chrome::NotificationType>(1, type)); | |
39 } | |
40 | |
41 // Checks then clears notifications for our extensions. | |
42 testing::AssertionResult CheckNotifications(chrome::NotificationType t1, | |
43 chrome::NotificationType t2) { | |
44 std::vector<chrome::NotificationType> types; | |
45 types.push_back(t1); | |
46 types.push_back(t2); | |
47 return CheckNotifications(types); | |
48 } | |
49 | |
50 // Checks then clears notifications for our extensions. | |
51 testing::AssertionResult CheckNotifications(chrome::NotificationType t1, | |
52 chrome::NotificationType t2, | |
53 chrome::NotificationType t3, | |
54 chrome::NotificationType t4) { | |
55 std::vector<chrome::NotificationType> types; | |
56 types.push_back(t1); | |
57 types.push_back(t2); | |
58 types.push_back(t3); | |
59 types.push_back(t4); | |
60 return CheckNotifications(types); | |
61 } | |
62 | |
63 private: | |
64 // content::NotificationObserver implementation. | |
65 virtual void Observe(int type, | |
66 const content::NotificationSource& source, | |
67 const content::NotificationDetails& details) OVERRIDE { | |
68 switch (type) { | |
69 case chrome::NOTIFICATION_EXTENSION_INSTALLED: { | |
70 const Extension* extension = | |
71 content::Details<const Extension>(details).ptr(); | |
72 if (extension_ids_.count(extension->id())) | |
73 notifications_.push_back(static_cast<chrome::NotificationType>(type)); | |
74 break; | |
75 } | |
76 | |
77 case chrome::NOTIFICATION_EXTENSION_LOADED: { | |
78 const Extension* extension = | |
79 content::Details<const Extension>(details).ptr(); | |
80 if (extension_ids_.count(extension->id())) | |
81 notifications_.push_back(static_cast<chrome::NotificationType>(type)); | |
82 break; | |
83 } | |
84 | |
85 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { | |
86 UnloadedExtensionInfo* reason = | |
87 content::Details<UnloadedExtensionInfo>(details).ptr(); | |
88 if (extension_ids_.count(reason->extension->id())) { | |
89 notifications_.push_back(static_cast<chrome::NotificationType>(type)); | |
90 // The only way that extensions are unloaded in these tests is | |
91 // by blacklisting. | |
92 EXPECT_EQ(extension_misc::UNLOAD_REASON_BLACKLIST, | |
93 reason->reason); | |
94 } | |
95 break; | |
96 } | |
97 | |
98 default: | |
99 NOTREACHED(); | |
100 break; | |
101 } | |
102 } | |
103 | |
104 // Checks then clears notifications for our extensions. | |
105 testing::AssertionResult CheckNotifications( | |
106 const std::vector<chrome::NotificationType>& types) { | |
107 testing::AssertionResult result = (notifications_ == types) ? | |
108 testing::AssertionSuccess() : | |
109 testing::AssertionFailure() << "Expected " << Str(types) << ", " << | |
110 "Got " << Str(notifications_); | |
111 notifications_.clear(); | |
112 return result; | |
113 } | |
114 | |
115 std::string Str(const std::vector<chrome::NotificationType>& types) { | |
116 std::string str = "["; | |
117 bool needs_comma = false; | |
118 for (std::vector<chrome::NotificationType>::const_iterator it = | |
119 types.begin(); it != types.end(); ++it) { | |
120 if (needs_comma) | |
121 str += ","; | |
122 needs_comma = true; | |
123 str += base::StringPrintf("%d", *it); | |
124 } | |
125 return str + "]"; | |
126 } | |
127 | |
128 const std::set<std::string> extension_ids_; | |
129 | |
130 std::vector<chrome::NotificationType> notifications_; | |
131 | |
132 content::NotificationRegistrar registrar_; | |
133 }; | |
134 | |
135 // Stores the paths to CRX files of extensions, and the extension's ID. | |
136 // Use arbitrary extensions; we're just testing blacklisting behavior. | |
137 class CrxInfo { | |
138 public: | |
139 CrxInfo(const std::string& path, const std::string& id) | |
140 : path_(path), id_(id) {} | |
141 | |
142 const std::string& path() { return path_; } | |
143 const std::string& id() { return id_; } | |
144 | |
145 private: | |
146 const std::string path_; | |
147 const std::string id_; | |
148 }; | |
149 | |
150 } // namespace | |
151 | |
152 class ExtensionBlacklistBrowserTest : public ExtensionBrowserTest { | |
153 public: | |
154 ExtensionBlacklistBrowserTest() | |
155 : info_a_("install/install.crx", "ogdbpbegnmindpdjfafpmpicikegejdj"), | |
156 info_b_("autoupdate/v1.crx", "ogjcoiohnmldgjemafoockdghcjciccf") {} | |
157 | |
158 virtual ~ExtensionBlacklistBrowserTest() {} | |
159 | |
160 protected: | |
161 // Returns whether |extension| is strictly installed: in ExtensionService's | |
162 // installed extensions, and not in its blacklisted extensions. | |
163 testing::AssertionResult IsInstalled(const Extension* extension) { | |
164 std::string id = extension->id(); | |
165 if (!extension_service()->extensions()->Contains(id)) | |
166 return testing::AssertionFailure() << id << " is not in extensions"; | |
167 return IsInValidState(extension); | |
168 } | |
169 | |
170 // Returns whether |extension| is strictly blacklisted: in ExtensionService's | |
171 // blacklist, and not installed. | |
172 testing::AssertionResult IsBlacklisted(const Extension* extension) { | |
173 std::string id = extension->id(); | |
174 if (!extension_service()->blacklisted_extensions()->Contains(id)) | |
175 return testing::AssertionFailure() << id << " is not in blacklisted"; | |
176 return IsInValidState(extension); | |
177 } | |
178 | |
179 std::set<std::string> GetTestExtensionIDs() { | |
180 std::set<std::string> extension_ids; | |
181 extension_ids.insert(info_a_.id()); | |
182 extension_ids.insert(info_b_.id()); | |
183 return extension_ids; | |
184 } | |
185 | |
186 Profile* profile() { | |
asargent_no_longer_on_chrome
2012/11/30 21:44:22
optional suggestion: It might be worth hoisting th
not at google - send to devlin
2012/11/30 23:09:54
Done.
| |
187 return browser()->profile(); | |
188 } | |
189 | |
190 ExtensionSystem* extension_system() { | |
191 return ExtensionSystem::Get(profile()); | |
192 } | |
193 | |
194 ExtensionService* extension_service() { | |
asargent_no_longer_on_chrome
2012/11/30 21:44:22
same for this one
not at google - send to devlin
2012/11/30 23:09:54
Done.
| |
195 return extension_system()->extension_service(); | |
196 } | |
197 | |
198 CrxInfo info_a_; | |
199 | |
200 CrxInfo info_b_; | |
201 | |
202 private: | |
203 // Returns whether |extension| is either installed or blacklisted, but | |
204 // neither both nor neither. | |
205 testing::AssertionResult IsInValidState(const Extension* extension) { | |
206 std::string id = extension->id(); | |
207 bool is_blacklisted = | |
208 extension_service()->blacklisted_extensions()->Contains(id); | |
209 bool is_installed = extension_service()->GetInstalledExtension(id); | |
210 if (is_blacklisted && is_installed) { | |
211 return testing::AssertionFailure() << | |
212 id << " is both installed and in blacklisted_extensions"; | |
213 } | |
214 if (!is_blacklisted && !is_installed) { | |
215 return testing::AssertionFailure() << | |
216 id << " is neither installed nor in blacklisted_extensions"; | |
217 } | |
218 return testing::AssertionSuccess(); | |
219 } | |
220 }; | |
221 | |
222 // Stage 1: blacklisting when there weren't any extensions installed when the | |
223 // browser started. | |
224 IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, PRE_Blacklist) { | |
225 //FilteringNotificationObserver notifications( | |
226 // content::Source<Profile>(profile()), GetTestExtensionIDs()); | |
227 FilteringNotificationObserver notifications( | |
228 content::NotificationService::AllSources(), GetTestExtensionIDs()); | |
229 | |
230 scoped_refptr<const Extension> extension_a = | |
231 InstallExtension(test_data_dir_.AppendASCII(info_a_.path()), 1); | |
232 scoped_refptr<const Extension> extension_b = | |
233 InstallExtension(test_data_dir_.AppendASCII(info_b_.path()), 1); | |
234 | |
235 EXPECT_TRUE(notifications.CheckNotifications( | |
236 chrome::NOTIFICATION_EXTENSION_INSTALLED, | |
237 chrome::NOTIFICATION_EXTENSION_LOADED, | |
238 chrome::NOTIFICATION_EXTENSION_INSTALLED, | |
239 chrome::NOTIFICATION_EXTENSION_LOADED)); | |
240 | |
241 ASSERT_TRUE(extension_a); | |
242 ASSERT_TRUE(extension_b); | |
243 ASSERT_EQ(info_a_.id(), extension_a->id()); | |
244 ASSERT_EQ(info_b_.id(), extension_b->id()); | |
245 | |
246 std::vector<std::string> empty_vector; | |
247 std::vector<std::string> vector_a(1, info_a_.id()); | |
248 std::vector<std::string> vector_b(1, info_b_.id()); | |
249 std::vector<std::string> vector_ab(1, info_a_.id()); | |
250 vector_ab.push_back(info_b_.id()); | |
251 | |
252 EXPECT_TRUE(IsInstalled(extension_a)); | |
253 EXPECT_TRUE(IsInstalled(extension_b)); | |
254 | |
255 // Blacklist a. | |
256 extension_system()->blacklist()->SetFromUpdater(vector_a, "1"); | |
257 base::RunLoop().RunUntilIdle(); | |
258 | |
259 EXPECT_TRUE(IsBlacklisted(extension_a)); | |
260 EXPECT_TRUE(IsInstalled(extension_b)); | |
261 EXPECT_TRUE(notifications.CheckNotifications( | |
262 chrome::NOTIFICATION_EXTENSION_UNLOADED)); | |
263 | |
264 // Un-blacklist a. | |
265 extension_system()->blacklist()->SetFromUpdater(empty_vector, "2"); | |
266 base::RunLoop().RunUntilIdle(); | |
267 | |
268 EXPECT_TRUE(IsInstalled(extension_a)); | |
269 EXPECT_TRUE(IsInstalled(extension_b)); | |
270 EXPECT_TRUE(notifications.CheckNotifications( | |
271 chrome::NOTIFICATION_EXTENSION_LOADED)); | |
272 | |
273 // Blacklist a then switch with b. | |
274 extension_system()->blacklist()->SetFromUpdater(vector_a, "3"); | |
275 base::RunLoop().RunUntilIdle(); | |
276 | |
277 EXPECT_TRUE(IsBlacklisted(extension_a)); | |
278 EXPECT_TRUE(IsInstalled(extension_b)); | |
279 EXPECT_TRUE(notifications.CheckNotifications( | |
280 chrome::NOTIFICATION_EXTENSION_UNLOADED)); | |
281 | |
282 extension_system()->blacklist()->SetFromUpdater(vector_b, "4"); | |
283 base::RunLoop().RunUntilIdle(); | |
284 | |
285 EXPECT_TRUE(IsInstalled(extension_a)); | |
286 EXPECT_TRUE(IsBlacklisted(extension_b)); | |
287 EXPECT_TRUE(notifications.CheckNotifications( | |
288 chrome::NOTIFICATION_EXTENSION_LOADED, | |
289 chrome::NOTIFICATION_EXTENSION_UNLOADED)); | |
290 | |
291 // Add a to blacklist. | |
292 extension_system()->blacklist()->SetFromUpdater(vector_ab, "5"); | |
293 base::RunLoop().RunUntilIdle(); | |
294 | |
295 EXPECT_TRUE(IsBlacklisted(extension_a)); | |
296 EXPECT_TRUE(IsBlacklisted(extension_b)); | |
297 EXPECT_TRUE(notifications.CheckNotifications( | |
298 chrome::NOTIFICATION_EXTENSION_UNLOADED)); | |
299 | |
300 // Clear blacklist. | |
301 extension_system()->blacklist()->SetFromUpdater(empty_vector, "6"); | |
302 base::RunLoop().RunUntilIdle(); | |
303 | |
304 EXPECT_TRUE(IsInstalled(extension_a)); | |
305 EXPECT_TRUE(IsInstalled(extension_b)); | |
306 EXPECT_TRUE(notifications.CheckNotifications( | |
307 chrome::NOTIFICATION_EXTENSION_LOADED, | |
308 chrome::NOTIFICATION_EXTENSION_LOADED)); | |
309 | |
310 // Add b back again for the next test. | |
311 extension_system()->blacklist()->SetFromUpdater(vector_b, "7"); | |
312 base::RunLoop().RunUntilIdle(); | |
313 | |
314 EXPECT_TRUE(IsInstalled(extension_a)); | |
315 EXPECT_TRUE(IsBlacklisted(extension_b)); | |
316 EXPECT_TRUE(notifications.CheckNotifications( | |
317 chrome::NOTIFICATION_EXTENSION_UNLOADED)); | |
318 } | |
319 | |
320 // Stage 2: blacklisting with extensions A and B having been installed, | |
321 // with B actually in the blacklist. | |
322 IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, Blacklist) { | |
323 FilteringNotificationObserver notifications( | |
324 content::Source<Profile>(profile()), GetTestExtensionIDs()); | |
325 | |
326 scoped_refptr<const Extension> extension_a = | |
327 extension_service()->extensions()->GetByID(info_a_.id()); | |
328 ASSERT_TRUE(extension_a); | |
329 | |
330 scoped_refptr<const Extension> extension_b = | |
331 extension_service()->blacklisted_extensions()->GetByID(info_b_.id()); | |
332 ASSERT_TRUE(extension_b); | |
333 | |
334 EXPECT_TRUE(IsInstalled(extension_a)); | |
335 EXPECT_TRUE(IsBlacklisted(extension_b)); | |
336 | |
337 // Make sure that we can still blacklist a and unblacklist b. | |
338 std::vector<std::string> vector_a(1, extension_a->id()); | |
339 extension_system()->blacklist()->SetFromUpdater(vector_a, "8"); | |
340 base::RunLoop().RunUntilIdle(); | |
341 | |
342 EXPECT_TRUE(IsBlacklisted(extension_a)); | |
343 EXPECT_TRUE(IsInstalled(extension_b)); | |
344 EXPECT_TRUE(notifications.CheckNotifications( | |
345 chrome::NOTIFICATION_EXTENSION_LOADED, | |
346 chrome::NOTIFICATION_EXTENSION_UNLOADED)); | |
347 } | |
348 | |
349 } // namespace extensions | |
OLD | NEW |