Index: chrome/browser/extensions/error_console/error_console_browsertest.cc |
diff --git a/chrome/browser/extensions/error_console/error_console_browsertest.cc b/chrome/browser/extensions/error_console/error_console_browsertest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b1c2eade8a051741cb248dfa01ee08670e49170c |
--- /dev/null |
+++ b/chrome/browser/extensions/error_console/error_console_browsertest.cc |
@@ -0,0 +1,248 @@ |
+// Copyright 2013 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 "chrome/browser/extensions/error_console/error_console.h" |
+ |
+#include "base/files/file_path.h" |
+#include "base/prefs/pref_service.h" |
+#include "base/strings/string16.h" |
+#include "base/strings/utf_string_conversions.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/profiles/profile.h" |
+#include "chrome/common/extensions/extension.h" |
+#include "chrome/common/pref_names.h" |
+#include "chrome/test/base/ui_test_utils.h" |
+#include "extensions/browser/extension_error.h" |
+#include "extensions/common/constants.h" |
+#include "extensions/common/error_utils.h" |
+#include "extensions/common/manifest_constants.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "url/gurl.h" |
+ |
+using base::string16; |
+using base::UTF8ToUTF16; |
+ |
+namespace extensions { |
+ |
+namespace { |
+ |
+base::string16 GetManifestFilename() { |
+ return base::FilePath(kManifestFilename).AsUTF16Unsafe(); |
+} |
+ |
+// Verify that all properties of a given |error| are correct. |
+void CheckError(const ExtensionError* error, |
+ ExtensionError::Type type, |
+ const std::string& id, |
+ const string16& source, |
+ bool from_incognito, |
+ const string16& message) { |
+ ASSERT_TRUE(error); |
+ EXPECT_EQ(type, error->type()); |
+ EXPECT_EQ(id, error->extension_id()); |
+ EXPECT_EQ(source, error->source()); |
+ EXPECT_EQ(from_incognito, error->from_incognito()); |
+ EXPECT_EQ(message, error->message()); |
+} |
+ |
+void CheckManifestError(const ExtensionError* error, |
+ const std::string& id, |
+ const string16& message, |
+ const string16& manifest_key, |
+ const string16& manifest_specific) { |
+ CheckError(error, |
+ ExtensionError::MANIFEST_ERROR, |
+ id, |
+ GetManifestFilename(), // source is always the manifest. |
+ false, // manifest errors are never from incognito. |
+ message); |
+ |
+ const ManifestError* manifest_error = |
+ static_cast<const ManifestError*>(error); |
+ EXPECT_EQ(manifest_key, manifest_error->manifest_key()); |
+ EXPECT_EQ(manifest_specific, manifest_error->manifest_specific()); |
+} |
+ |
+} // namespace |
+ |
+class ErrorConsoleBrowserTest : public ExtensionBrowserTest { |
+ public: |
+ ErrorConsoleBrowserTest() : error_console_(NULL) { } |
+ virtual ~ErrorConsoleBrowserTest() { } |
+ |
+ protected: |
+ // A helper class in order to wait for the proper number of errors to be |
+ // caught by the ErrorConsole. This will run the MessageLoop until a given |
+ // number of errors are observed. |
+ // Usage: |
+ // ... |
+ // ErrorObserver observer(3, error_console); |
+ // <Cause three errors...> |
+ // observer.WaitForErrors(); |
+ // <Perform any additional checks...> |
+ class ErrorObserver : public ErrorConsole::Observer { |
+ public: |
+ ErrorObserver(size_t errors_expected, ErrorConsole* error_console) |
+ : errors_observed_(0), |
+ errors_expected_(errors_expected), |
+ waiting_(false), |
+ error_console_(error_console) { |
+ error_console_->AddObserver(this); |
+ } |
+ virtual ~ErrorObserver() { |
+ if (error_console_) |
+ error_console_->RemoveObserver(this); |
+ } |
+ |
+ // ErrorConsole::Observer implementation. |
+ virtual void OnErrorAdded(const ExtensionError* error) OVERRIDE { |
+ ++errors_observed_; |
+ if (errors_observed_ >= errors_expected_) { |
+ if (waiting_) |
+ base::MessageLoopForUI::current()->Quit(); |
+ } |
+ } |
+ |
+ virtual void OnErrorConsoleDestroyed() OVERRIDE { |
+ error_console_ = NULL; |
+ } |
+ |
+ // Spin until the appropriate number of errors have been observed. |
+ void WaitForErrors() { |
+ if (errors_observed_ < errors_expected_) { |
+ waiting_ = true; |
+ content::RunMessageLoop(); |
+ waiting_ = false; |
+ } |
+ } |
+ |
+ private: |
+ size_t errors_observed_; |
+ size_t errors_expected_; |
+ bool waiting_; |
+ |
+ ErrorConsole* error_console_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ErrorObserver); |
+ }; |
+ |
+ virtual void SetUpOnMainThread() OVERRIDE { |
+ ExtensionBrowserTest::SetUpOnMainThread(); |
+ |
+ // Errors are only kept if we have Developer Mode enabled. |
+ profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true); |
+ |
+ error_console_ = ErrorConsole::Get(profile()); |
+ CHECK(error_console_); |
+ |
+ test_data_dir_ = test_data_dir_.AppendASCII("error_console"); |
+ } |
+ |
+ // Load the extension at |path| and wait for |expected_errors| errors. |
+ // Populates |extension| with a pointer to the loaded extension. |
+ void LoadExtensionAndCheckErrors( |
+ const std::string& path, |
+ int flags, |
+ size_t errors_expected, |
+ const Extension** extension) { |
+ ErrorObserver observer(errors_expected, error_console_); |
+ *extension = |
+ LoadExtensionWithFlags(test_data_dir_.AppendASCII(path), flags); |
+ ASSERT_TRUE(*extension); |
+ observer.WaitForErrors(); |
+ |
+ // We should only have errors for a single extension, or should have no |
+ // entries, if no errors were expected. |
+ ASSERT_EQ(errors_expected > 0 ? 1u : 0u, error_console()->errors().size()); |
+ ASSERT_EQ( |
+ errors_expected, |
+ error_console()->GetErrorsForExtension((*extension)->id()).size()); |
+ } |
+ |
+ ErrorConsole* error_console() { return error_console_; } |
+ private: |
+ // Weak reference to the ErrorConsole object. |
+ ErrorConsole* error_console_; |
+}; |
+ |
+// Test to ensure that we are successfully reporting manifest errors as an |
+// extension is installed. |
+IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, ReportManifestErrors) { |
+ const Extension* extension = NULL; |
+ // We expect two errors - one for an invalid permission, and a second for |
+ // an unknown key. |
+ LoadExtensionAndCheckErrors("manifest_warnings", |
+ ExtensionBrowserTest::kFlagIgnoreManifestWarnings, |
+ 2, |
+ &extension); |
+ |
+ const ErrorConsole::ErrorList& errors = |
+ error_console()->GetErrorsForExtension(extension->id()); |
+ |
+ // Unfortunately, there's not always a hard guarantee of order in parsing the |
+ // manifest, so there's not a definitive order in which these errors may |
+ // occur. As such, we need to determine which error corresponds to which |
+ // expected error. |
+ const ExtensionError* permissions_error = NULL; |
+ const ExtensionError* unknown_key_error = NULL; |
+ const char kFakeKey[] = "not_a_real_key"; |
+ for (size_t i = 0; i < errors.size(); ++i) { |
+ ASSERT_EQ(ExtensionError::MANIFEST_ERROR, errors[i]->type()); |
+ std::string utf8_key = UTF16ToUTF8( |
+ (static_cast<const ManifestError*>(errors[i]))->manifest_key()); |
+ if (utf8_key == manifest_keys::kPermissions) |
+ permissions_error = errors[i]; |
+ else if (utf8_key == kFakeKey) |
+ unknown_key_error = errors[i]; |
+ } |
+ ASSERT_TRUE(permissions_error); |
+ ASSERT_TRUE(unknown_key_error); |
+ |
+ const char kFakePermission[] = "not_a_real_permission"; |
+ CheckManifestError(permissions_error, |
+ extension->id(), |
+ base::UTF8ToUTF16( |
+ ErrorUtils::FormatErrorMessage( |
+ manifest_errors::kPermissionUnknownOrMalformed, |
+ kFakePermission)), |
+ base::UTF8ToUTF16(manifest_keys::kPermissions), |
+ base::UTF8ToUTF16(kFakePermission)); |
+ |
+ CheckManifestError(unknown_key_error, |
+ extension->id(), |
+ base::UTF8ToUTF16( |
+ ErrorUtils::FormatErrorMessage( |
+ manifest_errors::kUnrecognizedManifestKey, |
+ kFakeKey)), |
+ base::UTF8ToUTF16(kFakeKey), |
+ EmptyString16()); |
+} |
+ |
+// Test that we do not store any errors unless the Developer Mode switch is |
+// toggled on the profile. |
+IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, |
+ DontStoreErrorsWithoutDeveloperMode) { |
+ profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, false); |
+ |
+ const Extension* extension = NULL; |
+ // Same test as ReportManifestErrors, except we don't expect any errors since |
+ // we disable Developer Mode. |
+ LoadExtensionAndCheckErrors("manifest_warnings", |
+ ExtensionBrowserTest::kFlagIgnoreManifestWarnings, |
+ 0, |
+ &extension); |
+ |
+ // Now if we enable developer mode, the errors should be reported... |
+ profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true); |
+ EXPECT_EQ(2u, error_console()->GetErrorsForExtension(extension->id()).size()); |
+ |
+ // ... and if we disable it again, all errors which we were holding should be |
+ // removed. |
+ profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, false); |
+ EXPECT_EQ(0u, error_console()->GetErrorsForExtension(extension->id()).size()); |
+} |
+ |
+} // namespace extensions |