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 "components/version_info/version_info.h"
17 #include "content/public/test/test_browser_thread_bundle.h"
18 #include "extensions/browser/extension_error.h"
19 #include "extensions/browser/extension_error_test_util.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/common/constants.h"
22 #include "extensions/common/extension_builder.h"
23 #include "extensions/common/feature_switch.h"
24 #include "extensions/common/value_builder.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 namespace extensions
{
29 using error_test_util::CreateNewManifestError
;
30 using error_test_util::CreateNewRuntimeError
;
32 class ErrorConsoleUnitTest
: public testing::Test
{
34 ErrorConsoleUnitTest() : error_console_(NULL
) { }
35 ~ErrorConsoleUnitTest() override
{}
37 void SetUp() override
{
38 testing::Test::SetUp();
40 // Errors are only kept if we have the FeatureSwitch and have Developer Mode
42 FeatureSwitch::error_console()->SetOverrideValue(
43 FeatureSwitch::OVERRIDE_ENABLED
);
44 profile_
.reset(new TestingProfile
);
45 profile_
->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode
, true);
46 error_console_
= ErrorConsole::Get(profile_
.get());
50 content::TestBrowserThreadBundle thread_bundle_
;
51 scoped_ptr
<TestingProfile
> profile_
;
52 ErrorConsole
* error_console_
;
55 // Test that the error console is enabled/disabled appropriately.
56 TEST_F(ErrorConsoleUnitTest
, EnableAndDisableErrorConsole
) {
57 // Start in Dev Channel, without the feature switch.
58 scoped_ptr
<ScopedCurrentChannel
> channel_override(
59 new ScopedCurrentChannel(version_info::Channel::DEV
));
60 ASSERT_EQ(version_info::Channel::DEV
, GetCurrentChannel());
61 FeatureSwitch::error_console()->SetOverrideValue(
62 FeatureSwitch::OVERRIDE_DISABLED
);
64 // At the start, the error console should be enabled, and specifically
65 // enabled for the chrome:extensions page.
66 EXPECT_TRUE(error_console_
->enabled());
67 EXPECT_TRUE(error_console_
->IsEnabledForChromeExtensionsPage());
68 EXPECT_FALSE(error_console_
->IsEnabledForAppsDeveloperTools());
70 // If we disable developer mode, we should disable error console.
71 profile_
->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode
, false);
72 EXPECT_FALSE(error_console_
->enabled());
73 EXPECT_FALSE(error_console_
->IsEnabledForChromeExtensionsPage());
74 EXPECT_FALSE(error_console_
->IsEnabledForAppsDeveloperTools());
76 // Similarly, if we change the current to less fun than Dev, ErrorConsole
77 // should be disabled.
78 channel_override
.reset();
79 channel_override
.reset(
80 new ScopedCurrentChannel(version_info::Channel::BETA
));
81 profile_
->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode
, true);
82 EXPECT_FALSE(error_console_
->enabled());
83 EXPECT_FALSE(error_console_
->IsEnabledForChromeExtensionsPage());
84 EXPECT_FALSE(error_console_
->IsEnabledForAppsDeveloperTools());
86 // But if we add the feature switch, that should override the channel.
87 FeatureSwitch::error_console()->SetOverrideValue(
88 FeatureSwitch::OVERRIDE_ENABLED
);
89 ASSERT_TRUE(FeatureSwitch::error_console()->IsEnabled());
90 // We use a pref mod to "poke" the ErrorConsole, because it needs an
91 // indication that something changed (FeatureSwitches don't change in a real
92 // environment, so ErrorConsole doesn't listen for them).
93 profile_
->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode
, false);
94 profile_
->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode
, true);
95 EXPECT_TRUE(error_console_
->enabled());
96 EXPECT_TRUE(error_console_
->IsEnabledForChromeExtensionsPage());
97 EXPECT_FALSE(error_console_
->IsEnabledForAppsDeveloperTools());
99 // Next, remove the feature switch (turning error console off), and install
100 // the Apps Developer Tools. If we have Apps Developer Tools, Error Console
101 // should be enabled by default.
102 FeatureSwitch::error_console()->SetOverrideValue(
103 FeatureSwitch::OVERRIDE_DISABLED
);
104 const char kAppsDeveloperToolsExtensionId
[] =
105 "ohmmkhmmmpcnpikjeljgnaoabkaalbgc";
106 scoped_refptr
<Extension
> adt
=
109 DictionaryBuilder().Set("name", "apps dev tools")
110 .Set("version", "0.2.0")
111 .Set("manifest_version", 2)
113 .SetID(kAppsDeveloperToolsExtensionId
)
115 ExtensionRegistry
* registry
= ExtensionRegistry::Get(profile_
.get());
116 registry
->AddEnabled(adt
);
117 registry
->TriggerOnLoaded(adt
.get());
118 EXPECT_TRUE(error_console_
->enabled());
119 EXPECT_FALSE(error_console_
->IsEnabledForChromeExtensionsPage());
120 EXPECT_TRUE(error_console_
->IsEnabledForAppsDeveloperTools());
122 // Unloading the Apps Developer Tools should disable error console.
123 registry
->RemoveEnabled(adt
->id());
124 registry
->TriggerOnUnloaded(adt
.get(), UnloadedExtensionInfo::REASON_DISABLE
);
125 EXPECT_FALSE(error_console_
->enabled());
126 EXPECT_FALSE(error_console_
->IsEnabledForChromeExtensionsPage());
127 EXPECT_FALSE(error_console_
->IsEnabledForAppsDeveloperTools());
130 // Test that errors are successfully reported. This is a simple test, since it
131 // is tested more thoroughly in extensions/browser/error_map_unittest.cc
132 TEST_F(ErrorConsoleUnitTest
, ReportErrors
) {
133 const size_t kNumTotalErrors
= 6;
134 const std::string kId
= crx_file::id_util::GenerateId("id");
135 error_console_
->set_default_reporting_for_test(ExtensionError::MANIFEST_ERROR
,
137 ASSERT_EQ(0u, error_console_
->GetErrorsForExtension(kId
).size());
139 for (size_t i
= 0; i
< kNumTotalErrors
; ++i
) {
140 error_console_
->ReportError(
141 CreateNewManifestError(kId
, base::UintToString(i
)));
144 ASSERT_EQ(kNumTotalErrors
, error_console_
->GetErrorsForExtension(kId
).size());
147 TEST_F(ErrorConsoleUnitTest
, DontStoreErrorsWithoutEnablingType
) {
148 // Disable default runtime error reporting, and enable default manifest error
150 error_console_
->set_default_reporting_for_test(ExtensionError::RUNTIME_ERROR
,
152 error_console_
->set_default_reporting_for_test(ExtensionError::MANIFEST_ERROR
,
155 const std::string kId
= crx_file::id_util::GenerateId("id");
157 // Try to report a runtime error - it should be ignored.
158 error_console_
->ReportError(CreateNewRuntimeError(kId
, "a"));
159 ASSERT_EQ(0u, error_console_
->GetErrorsForExtension(kId
).size());
161 // Check that manifest errors are reported successfully.
162 error_console_
->ReportError(CreateNewManifestError(kId
, "b"));
163 ASSERT_EQ(1u, error_console_
->GetErrorsForExtension(kId
).size());
165 // We should still ignore runtime errors.
166 error_console_
->ReportError(CreateNewRuntimeError(kId
, "c"));
167 ASSERT_EQ(1u, error_console_
->GetErrorsForExtension(kId
).size());
169 // Enable runtime errors specifically for this extension, and disable the use
170 // of the default mask.
171 error_console_
->SetReportingForExtension(
172 kId
, ExtensionError::RUNTIME_ERROR
, true);
174 // We should now accept runtime and manifest errors.
175 error_console_
->ReportError(CreateNewManifestError(kId
, "d"));
176 ASSERT_EQ(2u, error_console_
->GetErrorsForExtension(kId
).size());
177 error_console_
->ReportError(CreateNewRuntimeError(kId
, "e"));
178 ASSERT_EQ(3u, error_console_
->GetErrorsForExtension(kId
).size());
180 // All other extensions should still use the default mask, and ignore runtime
181 // errors but report manifest errors.
182 const std::string kId2
= crx_file::id_util::GenerateId("id2");
183 error_console_
->ReportError(CreateNewRuntimeError(kId2
, "f"));
184 ASSERT_EQ(0u, error_console_
->GetErrorsForExtension(kId2
).size());
185 error_console_
->ReportError(CreateNewManifestError(kId2
, "g"));
186 ASSERT_EQ(1u, error_console_
->GetErrorsForExtension(kId2
).size());
188 // By reverting to default reporting, we should again allow manifest errors,
189 // but not runtime errors.
190 error_console_
->UseDefaultReportingForExtension(kId
);
191 error_console_
->ReportError(CreateNewManifestError(kId
, "h"));
192 ASSERT_EQ(4u, error_console_
->GetErrorsForExtension(kId
).size());
193 error_console_
->ReportError(CreateNewRuntimeError(kId
, "i"));
194 ASSERT_EQ(4u, error_console_
->GetErrorsForExtension(kId
).size());
197 // Test that we only store errors by default for unpacked extensions, and that
198 // assigning a preference to any extension overrides the defaults.
199 TEST_F(ErrorConsoleUnitTest
, TestDefaultStoringPrefs
) {
200 // For this, we need actual extensions.
201 scoped_refptr
<const Extension
> unpacked_extension
=
203 .SetManifest(DictionaryBuilder()
204 .Set("name", "unpacked")
205 .Set("version", "0.0.1")
206 .Set("manifest_version", 2)
208 .SetLocation(Manifest::UNPACKED
)
209 .SetID(crx_file::id_util::GenerateId("unpacked"))
211 scoped_refptr
<const Extension
> packed_extension
=
213 .SetManifest(DictionaryBuilder()
214 .Set("name", "packed")
215 .Set("version", "0.0.1")
216 .Set("manifest_version", 2)
218 .SetLocation(Manifest::INTERNAL
)
219 .SetID(crx_file::id_util::GenerateId("packed"))
222 ExtensionRegistry
* registry
= ExtensionRegistry::Get(profile_
.get());
223 registry
->AddEnabled(unpacked_extension
);
224 registry
->AddEnabled(packed_extension
);
226 // We should start with a clean slate.
227 EXPECT_EQ(0u, error_console_
->GetErrorsForExtension(
228 unpacked_extension
->id()).size());
229 EXPECT_EQ(0u, error_console_
->GetErrorsForExtension(
230 packed_extension
->id()).size());
232 // Errors should be ignored by default for the packed extension.
233 error_console_
->ReportError(
234 CreateNewManifestError(packed_extension
->id(), "manifest error 1"));
235 error_console_
->ReportError(
236 CreateNewRuntimeError(packed_extension
->id(), "runtime error 1"));
237 EXPECT_EQ(0u, error_console_
->GetErrorsForExtension(
238 packed_extension
->id()).size());
239 // Also check that reporting settings are correctly returned.
240 EXPECT_FALSE(error_console_
->IsReportingEnabledForExtension(
241 packed_extension
->id()));
243 // Errors should be reported by default for the unpacked extension.
244 error_console_
->ReportError(
245 CreateNewManifestError(unpacked_extension
->id(), "manifest error 2"));
246 error_console_
->ReportError(
247 CreateNewRuntimeError(unpacked_extension
->id(), "runtime error 2"));
248 EXPECT_EQ(2u, error_console_
->GetErrorsForExtension(
249 unpacked_extension
->id()).size());
250 // Also check that reporting settings are correctly returned.
251 EXPECT_TRUE(error_console_
->IsReportingEnabledForExtension(
252 unpacked_extension
->id()));
254 // Registering a preference should override this for both types of extensions
255 // (should be able to enable errors for packed, or disable errors for
257 error_console_
->SetReportingForExtension(packed_extension
->id(),
258 ExtensionError::RUNTIME_ERROR
,
260 error_console_
->ReportError(
261 CreateNewRuntimeError(packed_extension
->id(), "runtime error 3"));
262 EXPECT_EQ(1u, error_console_
->GetErrorsForExtension(
263 packed_extension
->id()).size());
264 EXPECT_TRUE(error_console_
->IsReportingEnabledForExtension(
265 packed_extension
->id()));
267 error_console_
->SetReportingForExtension(unpacked_extension
->id(),
268 ExtensionError::RUNTIME_ERROR
,
270 error_console_
->ReportError(
271 CreateNewRuntimeError(packed_extension
->id(), "runtime error 4"));
272 EXPECT_EQ(2u, // We should still have the first two errors.
273 error_console_
->GetErrorsForExtension(
274 unpacked_extension
->id()).size());
275 EXPECT_FALSE(error_console_
->IsReportingEnabledForExtension(
276 unpacked_extension
->id()));
279 } // namespace extensions