Home | History | Annotate | Download | only in error_console
      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 
     25 namespace extensions {
     26 
     27 using error_test_util::CreateNewManifestError;
     28 using error_test_util::CreateNewRuntimeError;
     29 
     30 class 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.
     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);
     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
    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,
    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 
    144 TEST_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.
    196 TEST_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