Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 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 "extensions/browser/error_map.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "components/crx_file/id_util.h"
     11 #include "extensions/browser/extension_error.h"
     12 #include "extensions/browser/extension_error_test_util.h"
     13 #include "extensions/common/constants.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace extensions {
     17 
     18 using error_test_util::CreateNewRuntimeError;
     19 
     20 class ErrorMapUnitTest : public testing::Test {
     21  public:
     22   ErrorMapUnitTest() { }
     23   virtual ~ErrorMapUnitTest() { }
     24 
     25   virtual void SetUp() OVERRIDE {
     26     testing::Test::SetUp();
     27   }
     28 
     29  protected:
     30   ErrorMap errors_;
     31 };
     32 
     33 // Test adding errors, and removing them by reference, by incognito status,
     34 // and in bulk.
     35 TEST_F(ErrorMapUnitTest, AddAndRemoveErrors) {
     36   ASSERT_EQ(0u, errors_.size());
     37 
     38   const size_t kNumTotalErrors = 6;
     39   const size_t kNumNonIncognitoErrors = 3;
     40   const std::string kId = crx_file::id_util::GenerateId("id");
     41   // Populate with both incognito and non-incognito errors (evenly distributed).
     42   for (size_t i = 0; i < kNumTotalErrors; ++i) {
     43     ASSERT_TRUE(errors_.AddError(
     44         CreateNewRuntimeError(kId, base::UintToString(i), i % 2 == 0)));
     45   }
     46 
     47   // There should only be one entry in the map, since errors are stored in lists
     48   // keyed by extension id.
     49   ASSERT_EQ(1u, errors_.size());
     50 
     51   ASSERT_EQ(kNumTotalErrors, errors_.GetErrorsForExtension(kId).size());
     52 
     53   // Remove the incognito errors; three errors should remain, and all should
     54   // be from non-incognito contexts.
     55   errors_.RemoveIncognitoErrors();
     56   const ErrorList& list = errors_.GetErrorsForExtension(kId);
     57   ASSERT_EQ(kNumNonIncognitoErrors, list.size());
     58   for (size_t i = 0; i < list.size(); ++i)
     59     ASSERT_FALSE(list[i]->from_incognito());
     60 
     61   // Add another error for a different extension id.
     62   const std::string kSecondId = crx_file::id_util::GenerateId("id2");
     63   ASSERT_TRUE(errors_.AddError(CreateNewRuntimeError(kSecondId, "foo")));
     64 
     65   // There should be two entries now, one for each id, and there should be one
     66   // error for the second extension.
     67   ASSERT_EQ(2u, errors_.size());
     68   ASSERT_EQ(1u, errors_.GetErrorsForExtension(kSecondId).size());
     69 
     70   // Remove all errors for the second id.
     71   errors_.Remove(kSecondId);
     72   ASSERT_EQ(1u, errors_.size());
     73   ASSERT_EQ(0u, errors_.GetErrorsForExtension(kSecondId).size());
     74   // First extension should be unaffected.
     75   ASSERT_EQ(kNumNonIncognitoErrors,
     76             errors_.GetErrorsForExtension(kId).size());
     77 
     78   // Remove remaining errors.
     79   errors_.RemoveAllErrors();
     80   ASSERT_EQ(0u, errors_.size());
     81   ASSERT_EQ(0u, errors_.GetErrorsForExtension(kId).size());
     82 }
     83 
     84 // Test that if we add enough errors, only the most recent
     85 // kMaxErrorsPerExtension are kept.
     86 TEST_F(ErrorMapUnitTest, ExcessiveErrorsGetCropped) {
     87   ASSERT_EQ(0u, errors_.size());
     88 
     89   // This constant matches one of the same name in error_console.cc.
     90   const size_t kMaxErrorsPerExtension = 100;
     91   const size_t kNumExtraErrors = 5;
     92   const std::string kId = crx_file::id_util::GenerateId("id");
     93 
     94   // Add new errors, with each error's message set to its number.
     95   for (size_t i = 0; i < kMaxErrorsPerExtension + kNumExtraErrors; ++i) {
     96     ASSERT_TRUE(errors_.AddError(
     97         CreateNewRuntimeError(kId, base::UintToString(i))));
     98   }
     99 
    100   ASSERT_EQ(1u, errors_.size());
    101 
    102   const ErrorList& list = errors_.GetErrorsForExtension(kId);
    103   ASSERT_EQ(kMaxErrorsPerExtension, list.size());
    104 
    105   // We should have popped off errors in the order they arrived, so the
    106   // first stored error should be the 6th reported (zero-based)...
    107   ASSERT_EQ(base::UintToString16(kNumExtraErrors),
    108             list.front()->message());
    109   // ..and the last stored should be the 105th reported.
    110   ASSERT_EQ(base::UintToString16(kMaxErrorsPerExtension + kNumExtraErrors - 1),
    111             list.back()->message());
    112 }
    113 
    114 // Test to ensure that the error console will not add duplicate errors, but will
    115 // keep the latest version of an error.
    116 TEST_F(ErrorMapUnitTest, DuplicateErrorsAreReplaced) {
    117   ASSERT_EQ(0u, errors_.size());
    118 
    119   const std::string kId = crx_file::id_util::GenerateId("id");
    120   const size_t kNumErrors = 3u;
    121 
    122   // Report three errors.
    123   for (size_t i = 0; i < kNumErrors; ++i) {
    124     ASSERT_TRUE(errors_.AddError(
    125         CreateNewRuntimeError(kId, base::UintToString(i))));
    126   }
    127 
    128   // Create an error identical to the second error reported, save its
    129   // location, and add it to the error map.
    130   scoped_ptr<ExtensionError> runtime_error2 =
    131       CreateNewRuntimeError(kId, base::UintToString(1u));
    132   const ExtensionError* weak_error = runtime_error2.get();
    133   ASSERT_TRUE(errors_.AddError(runtime_error2.Pass()));
    134 
    135   // We should only have three errors stored, since two of the four reported
    136   // were identical, and the older should have been replaced.
    137   ASSERT_EQ(1u, errors_.size());
    138   const ErrorList& list = errors_.GetErrorsForExtension(kId);
    139   ASSERT_EQ(kNumErrors, list.size());
    140 
    141   // The duplicate error should be the last reported (pointer comparison)...
    142   ASSERT_EQ(weak_error, list.back());
    143   // ... and should have two reported occurrences.
    144   ASSERT_EQ(2u, list.back()->occurrences());
    145 }
    146 
    147 }  // namespace extensions
    148