| Index: chrome/browser/extensions/extension_blacklist_browsertest.cc
|
| diff --git a/chrome/browser/extensions/extension_blacklist_browsertest.cc b/chrome/browser/extensions/extension_blacklist_browsertest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cc6bc241bc47044b2e7127bd4a036b1a2beb9eab
|
| --- /dev/null
|
| +++ b/chrome/browser/extensions/extension_blacklist_browsertest.cc
|
| @@ -0,0 +1,389 @@
|
| +// Copyright 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/run_loop.h"
|
| +#include "base/stringprintf.h"
|
| +#include "chrome/browser/extensions/blacklist.h"
|
| +#include "chrome/browser/extensions/extension_browsertest.h"
|
| +#include "chrome/browser/extensions/extension_service.h"
|
| +#include "chrome/browser/extensions/extension_system.h"
|
| +#include "chrome/browser/ui/browser.h"
|
| +#include "chrome/common/chrome_notification_types.h"
|
| +#include "chrome/common/extensions/extension.h"
|
| +#include "chrome/common/extensions/extension_constants.h"
|
| +#include "content/public/browser/notification_details.h"
|
| +#include "content/public/browser/notification_observer.h"
|
| +#include "content/public/browser/notification_registrar.h"
|
| +#include "content/public/browser/notification_source.h"
|
| +
|
| +namespace extensions {
|
| +
|
| +namespace {
|
| +
|
| +// Records notifications, but only for extensions with specific IDs.
|
| +class FilteringNotificationObserver : public content::NotificationObserver {
|
| + public:
|
| + FilteringNotificationObserver(
|
| + content::NotificationSource source,
|
| + const std::set<std::string>& extension_ids)
|
| + : extension_ids_(extension_ids) {
|
| + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, source);
|
| + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, source);
|
| + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, source);
|
| + }
|
| +
|
| + // Checks then clears notifications for our extensions.
|
| + testing::AssertionResult CheckNotifications(chrome::NotificationType type) {
|
| + return CheckNotifications(std::vector<chrome::NotificationType>(1, type));
|
| + }
|
| +
|
| + // Checks then clears notifications for our extensions.
|
| + testing::AssertionResult CheckNotifications(chrome::NotificationType t1,
|
| + chrome::NotificationType t2) {
|
| + std::vector<chrome::NotificationType> types;
|
| + types.push_back(t1);
|
| + types.push_back(t2);
|
| + return CheckNotifications(types);
|
| + }
|
| +
|
| + // Checks then clears notifications for our extensions.
|
| + testing::AssertionResult CheckNotifications(chrome::NotificationType t1,
|
| + chrome::NotificationType t2,
|
| + chrome::NotificationType t3) {
|
| + std::vector<chrome::NotificationType> types;
|
| + types.push_back(t1);
|
| + types.push_back(t2);
|
| + types.push_back(t3);
|
| + return CheckNotifications(types);
|
| + }
|
| +
|
| + // Checks then clears notifications for our extensions.
|
| + testing::AssertionResult CheckNotifications(chrome::NotificationType t1,
|
| + chrome::NotificationType t2,
|
| + chrome::NotificationType t3,
|
| + chrome::NotificationType t4,
|
| + chrome::NotificationType t5,
|
| + chrome::NotificationType t6) {
|
| + std::vector<chrome::NotificationType> types;
|
| + types.push_back(t1);
|
| + types.push_back(t2);
|
| + types.push_back(t3);
|
| + types.push_back(t4);
|
| + types.push_back(t5);
|
| + types.push_back(t6);
|
| + return CheckNotifications(types);
|
| + }
|
| +
|
| + private:
|
| + // content::NotificationObserver implementation.
|
| + virtual void Observe(int type,
|
| + const content::NotificationSource& source,
|
| + const content::NotificationDetails& details) OVERRIDE {
|
| + switch (type) {
|
| + case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
|
| + const Extension* extension =
|
| + content::Details<const Extension>(details).ptr();
|
| + if (extension_ids_.count(extension->id()))
|
| + notifications_.push_back(static_cast<chrome::NotificationType>(type));
|
| + break;
|
| + }
|
| +
|
| + case chrome::NOTIFICATION_EXTENSION_LOADED: {
|
| + const Extension* extension =
|
| + content::Details<const Extension>(details).ptr();
|
| + if (extension_ids_.count(extension->id()))
|
| + notifications_.push_back(static_cast<chrome::NotificationType>(type));
|
| + break;
|
| + }
|
| +
|
| + case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
|
| + UnloadedExtensionInfo* reason =
|
| + content::Details<UnloadedExtensionInfo>(details).ptr();
|
| + if (extension_ids_.count(reason->extension->id())) {
|
| + notifications_.push_back(static_cast<chrome::NotificationType>(type));
|
| + // The only way that extensions are unloaded in these tests is
|
| + // by blacklisting.
|
| + EXPECT_EQ(extension_misc::UNLOAD_REASON_BLACKLIST,
|
| + reason->reason);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + default:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // Checks then clears notifications for our extensions.
|
| + testing::AssertionResult CheckNotifications(
|
| + const std::vector<chrome::NotificationType>& types) {
|
| + testing::AssertionResult result = (notifications_ == types) ?
|
| + testing::AssertionSuccess() :
|
| + testing::AssertionFailure() << "Expected " << Str(types) << ", " <<
|
| + "Got " << Str(notifications_);
|
| + notifications_.clear();
|
| + return result;
|
| + }
|
| +
|
| + std::string Str(const std::vector<chrome::NotificationType>& types) {
|
| + std::string str = "[";
|
| + bool needs_comma = false;
|
| + for (std::vector<chrome::NotificationType>::const_iterator it =
|
| + types.begin(); it != types.end(); ++it) {
|
| + if (needs_comma)
|
| + str += ",";
|
| + needs_comma = true;
|
| + str += base::StringPrintf("%d", *it);
|
| + }
|
| + return str + "]";
|
| + }
|
| +
|
| + const std::set<std::string> extension_ids_;
|
| +
|
| + std::vector<chrome::NotificationType> notifications_;
|
| +
|
| + content::NotificationRegistrar registrar_;
|
| +};
|
| +
|
| +// Stores the paths to CRX files of extensions, and the extension's ID.
|
| +// Use arbitrary extensions; we're just testing blacklisting behavior.
|
| +class CrxInfo {
|
| + public:
|
| + CrxInfo(const std::string& path, const std::string& id)
|
| + : path_(path), id_(id) {}
|
| +
|
| + const std::string& path() { return path_; }
|
| + const std::string& id() { return id_; }
|
| +
|
| + private:
|
| + const std::string path_;
|
| + const std::string id_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +class ExtensionBlacklistBrowserTest : public ExtensionBrowserTest {
|
| + public:
|
| + ExtensionBlacklistBrowserTest()
|
| + : info_a_("install/install.crx", "ogdbpbegnmindpdjfafpmpicikegejdj"),
|
| + info_b_("autoupdate/v1.crx", "ogjcoiohnmldgjemafoockdghcjciccf"),
|
| + info_c_("hosted_app.crx", "kbmnembihfiondgfjekmnmcbddelicoi") {}
|
| +
|
| + virtual ~ExtensionBlacklistBrowserTest() {}
|
| +
|
| + protected:
|
| + // Returns whether |extension| is strictly safe: in one of ExtensionService's
|
| + // non-blacklisted extension sets, and not in its blacklisted extensions.
|
| + testing::AssertionResult IsSafe(const Extension* extension) {
|
| + std::string id = extension->id();
|
| + int include_mask = ExtensionService::INCLUDE_EVERYTHING &
|
| + ~ExtensionService::INCLUDE_BLACKLISTED;
|
| + if (!extension_service()->GetExtensionById(id, include_mask))
|
| + return testing::AssertionFailure() << id << " is safe";
|
| + return IsInValidState(extension);
|
| + }
|
| +
|
| + // Returns whether |extension| is strictly blacklisted: in ExtensionService's
|
| + // blacklist, and not in any of its other extension sets.
|
| + testing::AssertionResult IsBlacklisted(const Extension* extension) {
|
| + std::string id = extension->id();
|
| + if (!extension_service()->blacklisted_extensions()->Contains(id))
|
| + return testing::AssertionFailure() << id << " is not blacklisted";
|
| + return IsInValidState(extension);
|
| + }
|
| +
|
| + std::set<std::string> GetTestExtensionIDs() {
|
| + std::set<std::string> extension_ids;
|
| + extension_ids.insert(info_a_.id());
|
| + extension_ids.insert(info_b_.id());
|
| + extension_ids.insert(info_c_.id());
|
| + return extension_ids;
|
| + }
|
| +
|
| + Blacklist* blacklist() {
|
| + return ExtensionSystem::Get(profile())->blacklist();
|
| + }
|
| +
|
| + CrxInfo info_a_;
|
| + CrxInfo info_b_;
|
| + CrxInfo info_c_;
|
| +
|
| + private:
|
| + // Returns whether |extension| is either installed or blacklisted, but
|
| + // neither both nor neither.
|
| + testing::AssertionResult IsInValidState(const Extension* extension) {
|
| + std::string id = extension->id();
|
| + bool is_blacklisted =
|
| + extension_service()->blacklisted_extensions()->Contains(id);
|
| + int safe_mask = ExtensionService::INCLUDE_EVERYTHING &
|
| + ~ExtensionService::INCLUDE_BLACKLISTED;
|
| + bool is_safe = extension_service()->GetExtensionById(id, safe_mask) != NULL;
|
| + if (is_blacklisted && is_safe) {
|
| + return testing::AssertionFailure() <<
|
| + id << " is both safe and in blacklisted_extensions";
|
| + }
|
| + if (!is_blacklisted && !is_safe) {
|
| + return testing::AssertionFailure() <<
|
| + id << " is neither safe nor in blacklisted_extensions";
|
| + }
|
| + return testing::AssertionSuccess();
|
| + }
|
| +};
|
| +
|
| +// Stage 1: blacklisting when there weren't any extensions installed when the
|
| +// browser started.
|
| +IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, PRE_Blacklist) {
|
| + FilteringNotificationObserver notifications(
|
| + content::NotificationService::AllSources(), GetTestExtensionIDs());
|
| +
|
| + scoped_refptr<const Extension> extension_a =
|
| + InstallExtension(test_data_dir_.AppendASCII(info_a_.path()), 1);
|
| + scoped_refptr<const Extension> extension_b =
|
| + InstallExtension(test_data_dir_.AppendASCII(info_b_.path()), 1);
|
| + scoped_refptr<const Extension> extension_c =
|
| + InstallExtension(test_data_dir_.AppendASCII(info_c_.path()), 1);
|
| +
|
| + EXPECT_TRUE(notifications.CheckNotifications(
|
| + chrome::NOTIFICATION_EXTENSION_INSTALLED,
|
| + chrome::NOTIFICATION_EXTENSION_LOADED,
|
| + chrome::NOTIFICATION_EXTENSION_INSTALLED,
|
| + chrome::NOTIFICATION_EXTENSION_LOADED,
|
| + chrome::NOTIFICATION_EXTENSION_INSTALLED,
|
| + chrome::NOTIFICATION_EXTENSION_LOADED));
|
| +
|
| + ASSERT_TRUE(extension_a);
|
| + ASSERT_TRUE(extension_b);
|
| + ASSERT_EQ(info_a_.id(), extension_a->id());
|
| + ASSERT_EQ(info_b_.id(), extension_b->id());
|
| + ASSERT_EQ(info_c_.id(), extension_c->id());
|
| +
|
| + std::vector<std::string> empty_vector;
|
| + std::vector<std::string> vector_a(1, info_a_.id());
|
| + std::vector<std::string> vector_b(1, info_b_.id());
|
| + std::vector<std::string> vector_c(1, info_c_.id());
|
| + std::vector<std::string> vector_ab(1, info_a_.id());
|
| + vector_ab.push_back(info_b_.id());
|
| + std::vector<std::string> vector_bc(1, info_b_.id());
|
| + vector_bc.push_back(info_c_.id());
|
| + std::vector<std::string> vector_abc(1, info_a_.id());
|
| + vector_abc.push_back(info_b_.id());
|
| + vector_abc.push_back(info_c_.id());
|
| +
|
| + EXPECT_TRUE(IsSafe(extension_a));
|
| + EXPECT_TRUE(IsSafe(extension_b));
|
| + EXPECT_TRUE(IsSafe(extension_c));
|
| +
|
| + // Blacklist a and b.
|
| + blacklist()->SetFromUpdater(vector_ab, "1");
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_TRUE(IsBlacklisted(extension_a));
|
| + EXPECT_TRUE(IsBlacklisted(extension_b));
|
| + EXPECT_TRUE(IsSafe(extension_c));
|
| + EXPECT_TRUE(notifications.CheckNotifications(
|
| + chrome::NOTIFICATION_EXTENSION_UNLOADED,
|
| + chrome::NOTIFICATION_EXTENSION_UNLOADED));
|
| +
|
| + // Un-blacklist a.
|
| + blacklist()->SetFromUpdater(vector_b, "2");
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_TRUE(IsSafe(extension_a));
|
| + EXPECT_TRUE(IsBlacklisted(extension_b));
|
| + EXPECT_TRUE(IsSafe(extension_c));
|
| + EXPECT_TRUE(notifications.CheckNotifications(
|
| + chrome::NOTIFICATION_EXTENSION_LOADED));
|
| +
|
| + // Blacklist a then switch with c.
|
| + blacklist()->SetFromUpdater(vector_ab, "3");
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_TRUE(IsBlacklisted(extension_a));
|
| + EXPECT_TRUE(IsBlacklisted(extension_b));
|
| + EXPECT_TRUE(IsSafe(extension_c));
|
| + EXPECT_TRUE(notifications.CheckNotifications(
|
| + chrome::NOTIFICATION_EXTENSION_UNLOADED));
|
| +
|
| + blacklist()->SetFromUpdater(vector_bc, "4");
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_TRUE(IsSafe(extension_a));
|
| + EXPECT_TRUE(IsBlacklisted(extension_b));
|
| + EXPECT_TRUE(IsBlacklisted(extension_c));
|
| + EXPECT_TRUE(notifications.CheckNotifications(
|
| + chrome::NOTIFICATION_EXTENSION_LOADED,
|
| + chrome::NOTIFICATION_EXTENSION_UNLOADED));
|
| +
|
| + // Add a to blacklist.
|
| + blacklist()->SetFromUpdater(vector_abc, "5");
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_TRUE(IsBlacklisted(extension_a));
|
| + EXPECT_TRUE(IsBlacklisted(extension_b));
|
| + EXPECT_TRUE(IsBlacklisted(extension_c));
|
| + EXPECT_TRUE(notifications.CheckNotifications(
|
| + chrome::NOTIFICATION_EXTENSION_UNLOADED));
|
| +
|
| + // Clear blacklist.
|
| + blacklist()->SetFromUpdater(empty_vector, "6");
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_TRUE(IsSafe(extension_a));
|
| + EXPECT_TRUE(IsSafe(extension_b));
|
| + EXPECT_TRUE(IsSafe(extension_c));
|
| + EXPECT_TRUE(notifications.CheckNotifications(
|
| + chrome::NOTIFICATION_EXTENSION_LOADED,
|
| + chrome::NOTIFICATION_EXTENSION_LOADED,
|
| + chrome::NOTIFICATION_EXTENSION_LOADED));
|
| +
|
| + // Add a and b back again for the next test.
|
| + blacklist()->SetFromUpdater(vector_ab, "7");
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_TRUE(IsBlacklisted(extension_a));
|
| + EXPECT_TRUE(IsBlacklisted(extension_b));
|
| + EXPECT_TRUE(IsSafe(extension_c));
|
| + EXPECT_TRUE(notifications.CheckNotifications(
|
| + chrome::NOTIFICATION_EXTENSION_UNLOADED,
|
| + chrome::NOTIFICATION_EXTENSION_UNLOADED));
|
| +}
|
| +
|
| +// Stage 2: blacklisting with extensions A and B having been installed,
|
| +// with A actually in the blacklist.
|
| +IN_PROC_BROWSER_TEST_F(ExtensionBlacklistBrowserTest, Blacklist) {
|
| + FilteringNotificationObserver notifications(
|
| + content::Source<Profile>(profile()), GetTestExtensionIDs());
|
| +
|
| + scoped_refptr<const Extension> extension_a =
|
| + extension_service()->blacklisted_extensions()->GetByID(info_a_.id());
|
| + ASSERT_TRUE(extension_a);
|
| +
|
| + scoped_refptr<const Extension> extension_b =
|
| + extension_service()->blacklisted_extensions()->GetByID(info_b_.id());
|
| + ASSERT_TRUE(extension_b);
|
| +
|
| + scoped_refptr<const Extension> extension_c =
|
| + extension_service()->extensions()->GetByID(info_c_.id());
|
| + ASSERT_TRUE(extension_c);
|
| +
|
| + EXPECT_TRUE(IsBlacklisted(extension_a));
|
| + EXPECT_TRUE(IsBlacklisted(extension_b));
|
| + EXPECT_TRUE(IsSafe(extension_c));
|
| +
|
| + // Make sure that we can still blacklist c and unblacklist b.
|
| + std::vector<std::string> vector_ac(1, extension_a->id());
|
| + vector_ac.push_back(extension_c->id());
|
| + blacklist()->SetFromUpdater(vector_ac, "8");
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_TRUE(IsBlacklisted(extension_a));
|
| + EXPECT_TRUE(IsSafe(extension_b));
|
| + EXPECT_TRUE(IsBlacklisted(extension_c));
|
| + EXPECT_TRUE(notifications.CheckNotifications(
|
| + chrome::NOTIFICATION_EXTENSION_LOADED,
|
| + chrome::NOTIFICATION_EXTENSION_UNLOADED));
|
| +}
|
| +
|
| +} // namespace extensions
|
|
|