OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 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/browser/extensions/error_console/error_console.h" |
| 6 |
| 7 #include "base/files/file_path.h" |
| 8 #include "base/prefs/pref_service.h" |
| 9 #include "base/strings/string16.h" |
| 10 #include "base/strings/utf_string_conversions.h" |
| 11 #include "chrome/browser/extensions/extension_browsertest.h" |
| 12 #include "chrome/browser/extensions/extension_service.h" |
| 13 #include "chrome/browser/extensions/extension_system.h" |
| 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/common/extensions/extension.h" |
| 16 #include "chrome/common/extensions/extension_manifest_constants.h" |
| 17 #include "chrome/common/pref_names.h" |
| 18 #include "chrome/test/base/ui_test_utils.h" |
| 19 #include "extensions/browser/extension_error.h" |
| 20 #include "extensions/common/constants.h" |
| 21 #include "extensions/common/error_utils.h" |
| 22 #include "extensions/common/manifest_constants.h" |
| 23 #include "testing/gtest/include/gtest/gtest.h" |
| 24 #include "url/gurl.h" |
| 25 |
| 26 using base::string16; |
| 27 using base::UTF8ToUTF16; |
| 28 |
| 29 namespace errors = extension_manifest_errors; |
| 30 |
| 31 namespace extensions { |
| 32 |
| 33 namespace { |
| 34 |
| 35 base::string16 GetManifestFilename() { |
| 36 return base::FilePath(kManifestFilename).AsUTF16Unsafe(); |
| 37 } |
| 38 |
| 39 // Verify that all properites of a given |error| are correct. |
| 40 void CheckError(const ExtensionError* error, |
| 41 ExtensionError::Type type, |
| 42 const std::string& id, |
| 43 const string16& source, |
| 44 bool from_incognito, |
| 45 const string16& message) { |
| 46 ASSERT_TRUE(error); |
| 47 EXPECT_EQ(type, error->type()); |
| 48 EXPECT_EQ(id, error->extension_id()); |
| 49 EXPECT_EQ(source, error->source()); |
| 50 EXPECT_EQ(from_incognito, error->from_incognito()); |
| 51 EXPECT_EQ(message, error->message()); |
| 52 } |
| 53 |
| 54 void CheckManifestError(const ExtensionError* error, |
| 55 const std::string& id, |
| 56 const string16& message, |
| 57 const string16& manifest_key, |
| 58 const string16& manifest_specific) { |
| 59 CheckError(error, |
| 60 ExtensionError::MANIFEST_PARSING_ERROR, |
| 61 id, |
| 62 GetManifestFilename(), // source is always the manifest. |
| 63 false, // manifest errors are never from incognito. |
| 64 message); |
| 65 |
| 66 const ManifestParsingError* manifest_error = |
| 67 static_cast<const ManifestParsingError*>(error); |
| 68 EXPECT_EQ(manifest_key, manifest_error->manifest_key()); |
| 69 EXPECT_EQ(manifest_specific, manifest_error->manifest_specific()); |
| 70 } |
| 71 |
| 72 } // namespace |
| 73 |
| 74 class ErrorConsoleBrowserTest : public ExtensionBrowserTest { |
| 75 public: |
| 76 ErrorConsoleBrowserTest() : error_console_(NULL) { } |
| 77 virtual ~ErrorConsoleBrowserTest() { } |
| 78 |
| 79 protected: |
| 80 // A helper class in order to wait for the proper number of errors to be |
| 81 // caught by the ErrorConsole. This will run the MessageLoop until a given |
| 82 // number of errors are observed. |
| 83 // Usage: |
| 84 // ... |
| 85 // ErrorObserver observer(3, error_console); |
| 86 // <Cause three errors...> |
| 87 // observer.WaitForErrors(); |
| 88 // <Perform any additional checks...> |
| 89 class ErrorObserver : public ErrorConsole::Observer { |
| 90 public: |
| 91 ErrorObserver(size_t errors_expected, ErrorConsole* error_console) |
| 92 : errors_observed_(0), |
| 93 errors_expected_(errors_expected), |
| 94 waiting_(false), |
| 95 error_console_(error_console) { |
| 96 error_console_->AddObserver(this); |
| 97 } |
| 98 virtual ~ErrorObserver() { |
| 99 if (error_console_) |
| 100 error_console_->RemoveObserver(this); |
| 101 } |
| 102 |
| 103 // ErrorConsole::Observer implementation. |
| 104 virtual void OnErrorAdded(const ExtensionError* error) OVERRIDE { |
| 105 ++errors_observed_; |
| 106 if (errors_observed_ >= errors_expected_) { |
| 107 if (waiting_) |
| 108 base::MessageLoopForUI::current()->Quit(); |
| 109 } |
| 110 } |
| 111 |
| 112 virtual void OnErrorConsoleDestroyed() OVERRIDE { |
| 113 error_console_ = NULL; |
| 114 } |
| 115 |
| 116 // Spin until the appropriate number of errors have been observed. |
| 117 void WaitForErrors() { |
| 118 if (errors_observed_ < errors_expected_) { |
| 119 waiting_ = true; |
| 120 content::RunMessageLoop(); |
| 121 waiting_ = false; |
| 122 } |
| 123 } |
| 124 |
| 125 private: |
| 126 size_t errors_observed_; |
| 127 size_t errors_expected_; |
| 128 bool waiting_; |
| 129 |
| 130 ErrorConsole* error_console_; |
| 131 |
| 132 DISALLOW_COPY_AND_ASSIGN(ErrorObserver); |
| 133 }; |
| 134 |
| 135 virtual void SetUpOnMainThread() OVERRIDE { |
| 136 ExtensionBrowserTest::SetUpOnMainThread(); |
| 137 |
| 138 // Errors are only kept if we have Developer Mode enabled. |
| 139 profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true); |
| 140 |
| 141 error_console_ = ErrorConsole::Get(profile()); |
| 142 CHECK(error_console_); |
| 143 |
| 144 test_data_dir_ = test_data_dir_.AppendASCII("error_console"); |
| 145 } |
| 146 |
| 147 // Load the extension at |path| wait for |expected_errors| errors. |
| 148 // Populates |extension| with a pointer to the loaded extension. |
| 149 void LoadExtensionAndCheckErrors( |
| 150 const std::string& path, |
| 151 int flags, |
| 152 size_t errors_expected, |
| 153 const Extension** extension) { |
| 154 ErrorObserver observer(errors_expected, error_console_); |
| 155 *extension = |
| 156 LoadExtensionWithFlags(test_data_dir_.AppendASCII(path), flags); |
| 157 ASSERT_TRUE(extension); |
| 158 observer.WaitForErrors(); |
| 159 |
| 160 // We should only have errors for a single extension, or should have no |
| 161 // entries, if no errors were expected. |
| 162 ASSERT_EQ(errors_expected > 0 ? 1u : 0u, error_console()->errors().size()); |
| 163 ASSERT_EQ( |
| 164 errors_expected, |
| 165 error_console()->GetErrorsForExtension((*extension)->id()).size()); |
| 166 } |
| 167 |
| 168 ErrorConsole* error_console() { return error_console_; } |
| 169 private: |
| 170 // Weak reference to the ErrorConsole object. |
| 171 ErrorConsole* error_console_; |
| 172 }; |
| 173 |
| 174 // Test to ensure that we are successfully reporting manifest errors as an |
| 175 // extension is installed. |
| 176 IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, ReportManifestErrors) { |
| 177 const Extension* extension = NULL; |
| 178 // We expect two errors - one for an invalid permission, and a second for |
| 179 // an unknown key. |
| 180 LoadExtensionAndCheckErrors("manifest_warnings", |
| 181 ExtensionBrowserTest::kFlagIgnoreManifestWarnings, |
| 182 2, |
| 183 &extension); |
| 184 |
| 185 const ErrorConsole::ErrorList& errors = |
| 186 error_console()->GetErrorsForExtension(extension->id()); |
| 187 |
| 188 // Unfortunately, there's not always a hard guarantee of order in parsing the |
| 189 // manifest, so there's not a definitive order in which these errors may |
| 190 // occur. As such, we need to determine which error corresponds to which |
| 191 // expected error. |
| 192 ASSERT_EQ(ExtensionError::MANIFEST_PARSING_ERROR, errors[0]->type()); |
| 193 const ManifestParsingError* temp_error = |
| 194 static_cast<const ManifestParsingError*>(errors[0]); |
| 195 |
| 196 const ExtensionError* permissions_error = NULL; |
| 197 const ExtensionError* unknown_key_error = NULL; |
| 198 if (temp_error->manifest_key() == base::UTF8ToUTF16("permissions")) { |
| 199 permissions_error = errors[0]; |
| 200 unknown_key_error = errors[1]; |
| 201 } else { |
| 202 permissions_error = errors[1]; |
| 203 unknown_key_error = errors[0]; |
| 204 } |
| 205 |
| 206 const char kFakePermission[] = "not_a_real_permission"; |
| 207 CheckManifestError(permissions_error, |
| 208 extension->id(), |
| 209 base::UTF8ToUTF16( |
| 210 ErrorUtils::FormatErrorMessage( |
| 211 errors::kPermissionUnknownOrMalformed, |
| 212 kFakePermission)), |
| 213 base::UTF8ToUTF16(manifest_keys::kPermissions), |
| 214 base::UTF8ToUTF16(kFakePermission)); |
| 215 |
| 216 const char kFakeKey[] = "not_a_real_key"; |
| 217 CheckManifestError(unknown_key_error, |
| 218 extension->id(), |
| 219 base::UTF8ToUTF16( |
| 220 ErrorUtils::FormatErrorMessage( |
| 221 errors::kUnrecognizedManifestKey, |
| 222 kFakeKey)), |
| 223 base::UTF8ToUTF16(kFakeKey), |
| 224 EmptyString16()); |
| 225 } |
| 226 |
| 227 // Test that we do not store any errors unless the Developer Mode switch is |
| 228 // toggled on the profile. |
| 229 IN_PROC_BROWSER_TEST_F(ErrorConsoleBrowserTest, |
| 230 DontStoreErrorsWithoutDeveloperMode) { |
| 231 profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, false); |
| 232 |
| 233 const Extension* extension = NULL; |
| 234 // Same test as ReportManifestErrors, except we don't expect any errors since |
| 235 // we disable Developer Mode. |
| 236 LoadExtensionAndCheckErrors("manifest_warnings", |
| 237 ExtensionBrowserTest::kFlagIgnoreManifestWarnings, |
| 238 0, |
| 239 &extension); |
| 240 |
| 241 // Now if we enable developer mode, the errors should be reported... |
| 242 profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true); |
| 243 EXPECT_EQ(2u, error_console()->GetErrorsForExtension(extension->id()).size()); |
| 244 |
| 245 // ... and if we disable it again, all errors which we were holding should be |
| 246 // removed. |
| 247 profile()->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, false); |
| 248 EXPECT_EQ(0u, error_console()->GetErrorsForExtension(extension->id()).size()); |
| 249 } |
| 250 |
| 251 } // namespace extensions |
OLD | NEW |