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.
5 #include "chrome/browser/extensions/error_console/error_console.h"
7 #include "base/logging.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "chrome/common/extensions/features/feature_channel.h"
13 #include "chrome/common/pref_names.h"
14 #include "chrome/test/base/testing_profile.h"
15 #include "components/crx_file/id_util.h"
16 #include "extensions/browser/extension_error.h"
17 #include "extensions/browser/extension_error_test_util.h"
18 #include "extensions/browser/extension_registry.h"
19 #include "extensions/common/constants.h"
20 #include "extensions/common/extension_builder.h"
21 #include "extensions/common/feature_switch.h"
22 #include "extensions/common/value_builder.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 namespace extensions {
27 using error_test_util::CreateNewManifestError;
28 using error_test_util::CreateNewRuntimeError;
30 class ErrorConsoleUnitTest : public testing::Test {
32 ErrorConsoleUnitTest() : error_console_(NULL) { }
33 ~ErrorConsoleUnitTest() override {}
35 void SetUp() override {
36 testing::Test::SetUp();
38 // Errors are only kept if we have the FeatureSwitch and have Developer Mode
40 FeatureSwitch::error_console()->SetOverrideValue(
41 FeatureSwitch::OVERRIDE_ENABLED);
42 profile_.reset(new TestingProfile);
43 profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
44 error_console_ = ErrorConsole::Get(profile_.get());
48 scoped_ptr<TestingProfile> profile_;
49 ErrorConsole* error_console_;
52 // Test that the error console is enabled/disabled appropriately.
53 TEST_F(ErrorConsoleUnitTest, EnableAndDisableErrorConsole) {
54 // Start in Dev Channel, without the feature switch.
55 scoped_ptr<ScopedCurrentChannel> channel_override(
56 new ScopedCurrentChannel(chrome::VersionInfo::CHANNEL_DEV));
57 ASSERT_EQ(chrome::VersionInfo::CHANNEL_DEV, GetCurrentChannel());
58 FeatureSwitch::error_console()->SetOverrideValue(
59 FeatureSwitch::OVERRIDE_DISABLED);
61 // At the start, the error console should be enabled, and specifically
62 // enabled for the chrome:extensions page.
63 EXPECT_TRUE(error_console_->enabled());
64 EXPECT_TRUE(error_console_->IsEnabledForChromeExtensionsPage());
65 EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
67 // If we disable developer mode, we should disable error console.
68 profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, false);
69 EXPECT_FALSE(error_console_->enabled());
70 EXPECT_FALSE(error_console_->IsEnabledForChromeExtensionsPage());
71 EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
73 // Similarly, if we change the current to less fun than Dev, ErrorConsole
74 // should be disabled.
75 channel_override.reset();
76 channel_override.reset(
77 new ScopedCurrentChannel(chrome::VersionInfo::CHANNEL_BETA));
78 profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
79 EXPECT_FALSE(error_console_->enabled());
80 EXPECT_FALSE(error_console_->IsEnabledForChromeExtensionsPage());
81 EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
83 // But if we add the feature switch, that should override the channel.
84 FeatureSwitch::error_console()->SetOverrideValue(
85 FeatureSwitch::OVERRIDE_ENABLED);
86 ASSERT_TRUE(FeatureSwitch::error_console()->IsEnabled());
87 // We use a pref mod to "poke" the ErrorConsole, because it needs an
88 // indication that something changed (FeatureSwitches don't change in a real
89 // environment, so ErrorConsole doesn't listen for them).
90 profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, false);
91 profile_->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, true);
92 EXPECT_TRUE(error_console_->enabled());
93 EXPECT_TRUE(error_console_->IsEnabledForChromeExtensionsPage());
94 EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
96 // Next, remove the feature switch (turning error console off), and install
97 // the Apps Developer Tools. If we have Apps Developer Tools, Error Console
98 // should be enabled by default.
99 FeatureSwitch::error_console()->SetOverrideValue(
100 FeatureSwitch::OVERRIDE_DISABLED);
101 const char kAppsDeveloperToolsExtensionId[] =
102 "ohmmkhmmmpcnpikjeljgnaoabkaalbgc";
103 scoped_refptr<Extension> adt =
106 DictionaryBuilder().Set("name", "apps dev tools")
107 .Set("version", "0.2.0")
108 .Set("manifest_version", 2)
110 .SetID(kAppsDeveloperToolsExtensionId)
112 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_.get());
113 registry->AddEnabled(adt);
114 registry->TriggerOnLoaded(adt.get());
115 EXPECT_TRUE(error_console_->enabled());
116 EXPECT_FALSE(error_console_->IsEnabledForChromeExtensionsPage());
117 EXPECT_TRUE(error_console_->IsEnabledForAppsDeveloperTools());
119 // Unloading the Apps Developer Tools should disable error console.
120 registry->RemoveEnabled(adt->id());
121 registry->TriggerOnUnloaded(adt.get(), UnloadedExtensionInfo::REASON_DISABLE);
122 EXPECT_FALSE(error_console_->enabled());
123 EXPECT_FALSE(error_console_->IsEnabledForChromeExtensionsPage());
124 EXPECT_FALSE(error_console_->IsEnabledForAppsDeveloperTools());
127 // Test that errors are successfully reported. This is a simple test, since it
128 // is tested more thoroughly in extensions/browser/error_map_unittest.cc
129 TEST_F(ErrorConsoleUnitTest, ReportErrors) {
130 const size_t kNumTotalErrors = 6;
131 const std::string kId = crx_file::id_util::GenerateId("id");
132 error_console_->set_default_reporting_for_test(ExtensionError::MANIFEST_ERROR,
134 ASSERT_EQ(0u, error_console_->GetErrorsForExtension(kId).size());
136 for (size_t i = 0; i < kNumTotalErrors; ++i) {
137 error_console_->ReportError(
138 CreateNewManifestError(kId, base::UintToString(i)));
141 ASSERT_EQ(kNumTotalErrors, error_console_->GetErrorsForExtension(kId).size());
144 TEST_F(ErrorConsoleUnitTest, DontStoreErrorsWithoutEnablingType) {
145 // Disable default runtime error reporting, and enable default manifest error
147 error_console_->set_default_reporting_for_test(ExtensionError::RUNTIME_ERROR,
149 error_console_->set_default_reporting_for_test(ExtensionError::MANIFEST_ERROR,
152 const std::string kId = crx_file::id_util::GenerateId("id");
154 // Try to report a runtime error - it should be ignored.
155 error_console_->ReportError(CreateNewRuntimeError(kId, "a"));
156 ASSERT_EQ(0u, error_console_->GetErrorsForExtension(kId).size());
158 // Check that manifest errors are reported successfully.
159 error_console_->ReportError(CreateNewManifestError(kId, "b"));
160 ASSERT_EQ(1u, error_console_->GetErrorsForExtension(kId).size());
162 // We should still ignore runtime errors.
163 error_console_->ReportError(CreateNewRuntimeError(kId, "c"));
164 ASSERT_EQ(1u, error_console_->GetErrorsForExtension(kId).size());
166 // Enable runtime errors specifically for this extension, and disable the use
167 // of the default mask.
168 error_console_->SetReportingForExtension(
169 kId, ExtensionError::RUNTIME_ERROR, true);
171 // We should now accept runtime and manifest errors.
172 error_console_->ReportError(CreateNewManifestError(kId, "d"));
173 ASSERT_EQ(2u, error_console_->GetErrorsForExtension(kId).size());
174 error_console_->ReportError(CreateNewRuntimeError(kId, "e"));
175 ASSERT_EQ(3u, error_console_->GetErrorsForExtension(kId).size());
177 // All other extensions should still use the default mask, and ignore runtime
178 // errors but report manifest errors.
179 const std::string kId2 = crx_file::id_util::GenerateId("id2");
180 error_console_->ReportError(CreateNewRuntimeError(kId2, "f"));
181 ASSERT_EQ(0u, error_console_->GetErrorsForExtension(kId2).size());
182 error_console_->ReportError(CreateNewManifestError(kId2, "g"));
183 ASSERT_EQ(1u, error_console_->GetErrorsForExtension(kId2).size());
185 // By reverting to default reporting, we should again allow manifest errors,
186 // but not runtime errors.
187 error_console_->UseDefaultReportingForExtension(kId);
188 error_console_->ReportError(CreateNewManifestError(kId, "h"));
189 ASSERT_EQ(4u, error_console_->GetErrorsForExtension(kId).size());
190 error_console_->ReportError(CreateNewRuntimeError(kId, "i"));
191 ASSERT_EQ(4u, error_console_->GetErrorsForExtension(kId).size());
194 // Test that we only store errors by default for unpacked extensions, and that
195 // assigning a preference to any extension overrides the defaults.
196 TEST_F(ErrorConsoleUnitTest, TestDefaultStoringPrefs) {
197 // For this, we need actual extensions.
198 scoped_refptr<const Extension> unpacked_extension =
200 .SetManifest(DictionaryBuilder()
201 .Set("name", "unpacked")
202 .Set("version", "0.0.1")
203 .Set("manifest_version", 2)
205 .SetLocation(Manifest::UNPACKED)
206 .SetID(crx_file::id_util::GenerateId("unpacked"))
208 scoped_refptr<const Extension> packed_extension =
210 .SetManifest(DictionaryBuilder()
211 .Set("name", "packed")
212 .Set("version", "0.0.1")
213 .Set("manifest_version", 2)
215 .SetLocation(Manifest::INTERNAL)
216 .SetID(crx_file::id_util::GenerateId("packed"))
219 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_.get());
220 registry->AddEnabled(unpacked_extension);
221 registry->AddEnabled(packed_extension);
223 // We should start with a clean slate.
224 EXPECT_EQ(0u, error_console_->GetErrorsForExtension(
225 unpacked_extension->id()).size());
226 EXPECT_EQ(0u, error_console_->GetErrorsForExtension(
227 packed_extension->id()).size());
229 // Errors should be ignored by default for the packed extension.
230 error_console_->ReportError(
231 CreateNewManifestError(packed_extension->id(), "manifest error 1"));
232 error_console_->ReportError(
233 CreateNewRuntimeError(packed_extension->id(), "runtime error 1"));
234 EXPECT_EQ(0u, error_console_->GetErrorsForExtension(
235 packed_extension->id()).size());
236 // Also check that reporting settings are correctly returned.
237 EXPECT_FALSE(error_console_->IsReportingEnabledForExtension(
238 packed_extension->id()));
240 // Errors should be reported by default for the unpacked extension.
241 error_console_->ReportError(
242 CreateNewManifestError(unpacked_extension->id(), "manifest error 2"));
243 error_console_->ReportError(
244 CreateNewRuntimeError(unpacked_extension->id(), "runtime error 2"));
245 EXPECT_EQ(2u, error_console_->GetErrorsForExtension(
246 unpacked_extension->id()).size());
247 // Also check that reporting settings are correctly returned.
248 EXPECT_TRUE(error_console_->IsReportingEnabledForExtension(
249 unpacked_extension->id()));
251 // Registering a preference should override this for both types of extensions
252 // (should be able to enable errors for packed, or disable errors for
254 error_console_->SetReportingForExtension(packed_extension->id(),
255 ExtensionError::RUNTIME_ERROR,
257 error_console_->ReportError(
258 CreateNewRuntimeError(packed_extension->id(), "runtime error 3"));
259 EXPECT_EQ(1u, error_console_->GetErrorsForExtension(
260 packed_extension->id()).size());
261 EXPECT_TRUE(error_console_->IsReportingEnabledForExtension(
262 packed_extension->id()));
264 error_console_->SetReportingForExtension(unpacked_extension->id(),
265 ExtensionError::RUNTIME_ERROR,
267 error_console_->ReportError(
268 CreateNewRuntimeError(packed_extension->id(), "runtime error 4"));
269 EXPECT_EQ(2u, // We should still have the first two errors.
270 error_console_->GetErrorsForExtension(
271 unpacked_extension->id()).size());
272 EXPECT_FALSE(error_console_->IsReportingEnabledForExtension(
273 unpacked_extension->id()));
276 } // namespace extensions