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/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" 24 25namespace extensions { 26 27using error_test_util::CreateNewManifestError; 28using error_test_util::CreateNewRuntimeError; 29 30class ErrorConsoleUnitTest : public testing::Test { 31 public: 32 ErrorConsoleUnitTest() : error_console_(NULL) { } 33 virtual ~ErrorConsoleUnitTest() { } 34 35 virtual void SetUp() OVERRIDE { 36 testing::Test::SetUp(); 37 38 // Errors are only kept if we have the FeatureSwitch and have Developer Mode 39 // enabled. 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()); 45 } 46 47 protected: 48 scoped_ptr<TestingProfile> profile_; 49 ErrorConsole* error_console_; 50}; 51 52// Test that the error console is enabled/disabled appropriately. 53TEST_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); 60 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()); 66 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()); 72 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()); 82 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()); 95 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 = 104 ExtensionBuilder() 105 .SetManifest( 106 DictionaryBuilder().Set("name", "apps dev tools") 107 .Set("version", "0.2.0") 108 .Set("manifest_version", 2) 109 .Build()) 110 .SetID(kAppsDeveloperToolsExtensionId) 111 .Build(); 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()); 118 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()); 125} 126 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 129TEST_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, 133 true); 134 ASSERT_EQ(0u, error_console_->GetErrorsForExtension(kId).size()); 135 136 for (size_t i = 0; i < kNumTotalErrors; ++i) { 137 error_console_->ReportError( 138 CreateNewManifestError(kId, base::UintToString(i))); 139 } 140 141 ASSERT_EQ(kNumTotalErrors, error_console_->GetErrorsForExtension(kId).size()); 142} 143 144TEST_F(ErrorConsoleUnitTest, DontStoreErrorsWithoutEnablingType) { 145 // Disable default runtime error reporting, and enable default manifest error 146 // reporting. 147 error_console_->set_default_reporting_for_test(ExtensionError::RUNTIME_ERROR, 148 false); 149 error_console_->set_default_reporting_for_test(ExtensionError::MANIFEST_ERROR, 150 true); 151 152 const std::string kId = crx_file::id_util::GenerateId("id"); 153 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()); 157 158 // Check that manifest errors are reported successfully. 159 error_console_->ReportError(CreateNewManifestError(kId, "b")); 160 ASSERT_EQ(1u, error_console_->GetErrorsForExtension(kId).size()); 161 162 // We should still ignore runtime errors. 163 error_console_->ReportError(CreateNewRuntimeError(kId, "c")); 164 ASSERT_EQ(1u, error_console_->GetErrorsForExtension(kId).size()); 165 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); 170 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()); 176 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()); 184 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()); 192} 193 194// Test that we only store errors by default for unpacked extensions, and that 195// assigning a preference to any extension overrides the defaults. 196TEST_F(ErrorConsoleUnitTest, TestDefaultStoringPrefs) { 197 // For this, we need actual extensions. 198 scoped_refptr<const Extension> unpacked_extension = 199 ExtensionBuilder() 200 .SetManifest(DictionaryBuilder() 201 .Set("name", "unpacked") 202 .Set("version", "0.0.1") 203 .Set("manifest_version", 2) 204 .Build()) 205 .SetLocation(Manifest::UNPACKED) 206 .SetID(crx_file::id_util::GenerateId("unpacked")) 207 .Build(); 208 scoped_refptr<const Extension> packed_extension = 209 ExtensionBuilder() 210 .SetManifest(DictionaryBuilder() 211 .Set("name", "packed") 212 .Set("version", "0.0.1") 213 .Set("manifest_version", 2) 214 .Build()) 215 .SetLocation(Manifest::INTERNAL) 216 .SetID(crx_file::id_util::GenerateId("packed")) 217 .Build(); 218 219 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_.get()); 220 registry->AddEnabled(unpacked_extension); 221 registry->AddEnabled(packed_extension); 222 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()); 228 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())); 239 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())); 250 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 253 // unpacked). 254 error_console_->SetReportingForExtension(packed_extension->id(), 255 ExtensionError::RUNTIME_ERROR, 256 true); 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())); 263 264 error_console_->SetReportingForExtension(unpacked_extension->id(), 265 ExtensionError::RUNTIME_ERROR, 266 false); 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())); 274} 275 276} // namespace extensions 277