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