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 Blacklist* blacklist() { |
| 187 return ExtensionSystem::Get(profile())->blacklist(); |
| 188 } |
| 189 |
| 190 CrxInfo info_a_; |
| 191 |
| 192 CrxInfo info_b_; |
| 193 |
| 194 private: |
| 195 // Returns whether |extension| is either installed or blacklisted, but |
| 196 // neither both nor neither. |
| 197 testing::AssertionResult IsInValidState(const Extension* extension) { |
| 198 std::string id = extension->id(); |
| 199 bool is_blacklisted = |
| 200 extension_service()->blacklisted_extensions()->Contains(id); |
| 201 bool is_installed = extension_service()->GetInstalledExtension(id); |
| 202 if (is_blacklisted && is_installed) { |
| 203 return testing::AssertionFailure() << |
| 204 id << " is both installed and in blacklisted_extensions"; |
| 205 } |
| 206 if (!is_blacklisted && !is_installed) { |
| 207 return testing::AssertionFailure() << |
| 208 id << " is neither installed nor in blacklisted_extensions"; |
| 209 } |
| 210 return testing::AssertionSuccess(); |
| 211 } |
| 212 }; |
| 213 |
| 214 // Stage 1: blacklisting when there weren't any extensions installed when the |
| 215 // browser started. |
| 216 IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, PRE_Blacklist) { |
| 217 //FilteringNotificationObserver notifications( |
| 218 // content::Source<Profile>(profile()), GetTestExtensionIDs()); |
| 219 FilteringNotificationObserver notifications( |
| 220 content::NotificationService::AllSources(), GetTestExtensionIDs()); |
| 221 |
| 222 scoped_refptr<const Extension> extension_a = |
| 223 InstallExtension(test_data_dir_.AppendASCII(info_a_.path()), 1); |
| 224 scoped_refptr<const Extension> extension_b = |
| 225 InstallExtension(test_data_dir_.AppendASCII(info_b_.path()), 1); |
| 226 |
| 227 EXPECT_TRUE(notifications.CheckNotifications( |
| 228 chrome::NOTIFICATION_EXTENSION_INSTALLED, |
| 229 chrome::NOTIFICATION_EXTENSION_LOADED, |
| 230 chrome::NOTIFICATION_EXTENSION_INSTALLED, |
| 231 chrome::NOTIFICATION_EXTENSION_LOADED)); |
| 232 |
| 233 ASSERT_TRUE(extension_a); |
| 234 ASSERT_TRUE(extension_b); |
| 235 ASSERT_EQ(info_a_.id(), extension_a->id()); |
| 236 ASSERT_EQ(info_b_.id(), extension_b->id()); |
| 237 |
| 238 std::vector<std::string> empty_vector; |
| 239 std::vector<std::string> vector_a(1, info_a_.id()); |
| 240 std::vector<std::string> vector_b(1, info_b_.id()); |
| 241 std::vector<std::string> vector_ab(1, info_a_.id()); |
| 242 vector_ab.push_back(info_b_.id()); |
| 243 |
| 244 EXPECT_TRUE(IsInstalled(extension_a)); |
| 245 EXPECT_TRUE(IsInstalled(extension_b)); |
| 246 |
| 247 // Blacklist a. |
| 248 blacklist()->SetFromUpdater(vector_a, "1"); |
| 249 base::RunLoop().RunUntilIdle(); |
| 250 |
| 251 EXPECT_TRUE(IsBlacklisted(extension_a)); |
| 252 EXPECT_TRUE(IsInstalled(extension_b)); |
| 253 EXPECT_TRUE(notifications.CheckNotifications( |
| 254 chrome::NOTIFICATION_EXTENSION_UNLOADED)); |
| 255 |
| 256 // Un-blacklist a. |
| 257 blacklist()->SetFromUpdater(empty_vector, "2"); |
| 258 base::RunLoop().RunUntilIdle(); |
| 259 |
| 260 EXPECT_TRUE(IsInstalled(extension_a)); |
| 261 EXPECT_TRUE(IsInstalled(extension_b)); |
| 262 EXPECT_TRUE(notifications.CheckNotifications( |
| 263 chrome::NOTIFICATION_EXTENSION_LOADED)); |
| 264 |
| 265 // Blacklist a then switch with b. |
| 266 blacklist()->SetFromUpdater(vector_a, "3"); |
| 267 base::RunLoop().RunUntilIdle(); |
| 268 |
| 269 EXPECT_TRUE(IsBlacklisted(extension_a)); |
| 270 EXPECT_TRUE(IsInstalled(extension_b)); |
| 271 EXPECT_TRUE(notifications.CheckNotifications( |
| 272 chrome::NOTIFICATION_EXTENSION_UNLOADED)); |
| 273 |
| 274 blacklist()->SetFromUpdater(vector_b, "4"); |
| 275 base::RunLoop().RunUntilIdle(); |
| 276 |
| 277 EXPECT_TRUE(IsInstalled(extension_a)); |
| 278 EXPECT_TRUE(IsBlacklisted(extension_b)); |
| 279 EXPECT_TRUE(notifications.CheckNotifications( |
| 280 chrome::NOTIFICATION_EXTENSION_LOADED, |
| 281 chrome::NOTIFICATION_EXTENSION_UNLOADED)); |
| 282 |
| 283 // Add a to blacklist. |
| 284 blacklist()->SetFromUpdater(vector_ab, "5"); |
| 285 base::RunLoop().RunUntilIdle(); |
| 286 |
| 287 EXPECT_TRUE(IsBlacklisted(extension_a)); |
| 288 EXPECT_TRUE(IsBlacklisted(extension_b)); |
| 289 EXPECT_TRUE(notifications.CheckNotifications( |
| 290 chrome::NOTIFICATION_EXTENSION_UNLOADED)); |
| 291 |
| 292 // Clear blacklist. |
| 293 blacklist()->SetFromUpdater(empty_vector, "6"); |
| 294 base::RunLoop().RunUntilIdle(); |
| 295 |
| 296 EXPECT_TRUE(IsInstalled(extension_a)); |
| 297 EXPECT_TRUE(IsInstalled(extension_b)); |
| 298 EXPECT_TRUE(notifications.CheckNotifications( |
| 299 chrome::NOTIFICATION_EXTENSION_LOADED, |
| 300 chrome::NOTIFICATION_EXTENSION_LOADED)); |
| 301 |
| 302 // Add b back again for the next test. |
| 303 blacklist()->SetFromUpdater(vector_b, "7"); |
| 304 base::RunLoop().RunUntilIdle(); |
| 305 |
| 306 EXPECT_TRUE(IsInstalled(extension_a)); |
| 307 EXPECT_TRUE(IsBlacklisted(extension_b)); |
| 308 EXPECT_TRUE(notifications.CheckNotifications( |
| 309 chrome::NOTIFICATION_EXTENSION_UNLOADED)); |
| 310 } |
| 311 |
| 312 // Stage 2: blacklisting with extensions A and B having been installed, |
| 313 // with B actually in the blacklist. |
| 314 IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, Blacklist) { |
| 315 FilteringNotificationObserver notifications( |
| 316 content::Source<Profile>(profile()), GetTestExtensionIDs()); |
| 317 |
| 318 scoped_refptr<const Extension> extension_a = |
| 319 extension_service()->extensions()->GetByID(info_a_.id()); |
| 320 ASSERT_TRUE(extension_a); |
| 321 |
| 322 scoped_refptr<const Extension> extension_b = |
| 323 extension_service()->blacklisted_extensions()->GetByID(info_b_.id()); |
| 324 ASSERT_TRUE(extension_b); |
| 325 |
| 326 EXPECT_TRUE(IsInstalled(extension_a)); |
| 327 EXPECT_TRUE(IsBlacklisted(extension_b)); |
| 328 |
| 329 // Make sure that we can still blacklist a and unblacklist b. |
| 330 std::vector<std::string> vector_a(1, extension_a->id()); |
| 331 blacklist()->SetFromUpdater(vector_a, "8"); |
| 332 base::RunLoop().RunUntilIdle(); |
| 333 |
| 334 EXPECT_TRUE(IsBlacklisted(extension_a)); |
| 335 EXPECT_TRUE(IsInstalled(extension_b)); |
| 336 EXPECT_TRUE(notifications.CheckNotifications( |
| 337 chrome::NOTIFICATION_EXTENSION_LOADED, |
| 338 chrome::NOTIFICATION_EXTENSION_UNLOADED)); |
| 339 } |
| 340 |
| 341 } // namespace extensions |
OLD | NEW |