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