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