15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/error_map.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
1003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/crx_file/id_util.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_error.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_error_test_util.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/constants.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace extensions {
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using error_test_util::CreateNewRuntimeError;
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ErrorMapUnitTest : public testing::Test {
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ErrorMapUnitTest() { }
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~ErrorMapUnitTest() { }
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    testing::Test::SetUp();
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) protected:
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ErrorMap errors_;
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Test adding errors, and removing them by reference, by incognito status,
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// and in bulk.
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(ErrorMapUnitTest, AddAndRemoveErrors) {
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0u, errors_.size());
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const size_t kNumTotalErrors = 6;
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const size_t kNumNonIncognitoErrors = 3;
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const std::string kId = crx_file::id_util::GenerateId("id");
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Populate with both incognito and non-incognito errors (evenly distributed).
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < kNumTotalErrors; ++i) {
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_TRUE(errors_.AddError(
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        CreateNewRuntimeError(kId, base::UintToString(i), i % 2 == 0)));
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There should only be one entry in the map, since errors are stored in lists
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // keyed by extension id.
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(1u, errors_.size());
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(kNumTotalErrors, errors_.GetErrorsForExtension(kId).size());
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Remove the incognito errors; three errors should remain, and all should
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // be from non-incognito contexts.
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  errors_.RemoveIncognitoErrors();
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ErrorList& list = errors_.GetErrorsForExtension(kId);
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(kNumNonIncognitoErrors, list.size());
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < list.size(); ++i)
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_FALSE(list[i]->from_incognito());
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Add another error for a different extension id.
6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const std::string kSecondId = crx_file::id_util::GenerateId("id2");
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(errors_.AddError(CreateNewRuntimeError(kSecondId, "foo")));
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There should be two entries now, one for each id, and there should be one
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // error for the second extension.
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(2u, errors_.size());
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(1u, errors_.GetErrorsForExtension(kSecondId).size());
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Remove all errors for the second id.
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  errors_.Remove(kSecondId);
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(1u, errors_.size());
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0u, errors_.GetErrorsForExtension(kSecondId).size());
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // First extension should be unaffected.
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(kNumNonIncognitoErrors,
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            errors_.GetErrorsForExtension(kId).size());
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Remove remaining errors.
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  errors_.RemoveAllErrors();
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0u, errors_.size());
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0u, errors_.GetErrorsForExtension(kId).size());
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Test that if we add enough errors, only the most recent
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// kMaxErrorsPerExtension are kept.
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(ErrorMapUnitTest, ExcessiveErrorsGetCropped) {
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0u, errors_.size());
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This constant matches one of the same name in error_console.cc.
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const size_t kMaxErrorsPerExtension = 100;
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const size_t kNumExtraErrors = 5;
9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const std::string kId = crx_file::id_util::GenerateId("id");
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Add new errors, with each error's message set to its number.
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < kMaxErrorsPerExtension + kNumExtraErrors; ++i) {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_TRUE(errors_.AddError(
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        CreateNewRuntimeError(kId, base::UintToString(i))));
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(1u, errors_.size());
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ErrorList& list = errors_.GetErrorsForExtension(kId);
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(kMaxErrorsPerExtension, list.size());
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // We should have popped off errors in the order they arrived, so the
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // first stored error should be the 6th reported (zero-based)...
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(base::UintToString16(kNumExtraErrors),
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            list.front()->message());
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // ..and the last stored should be the 105th reported.
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(base::UintToString16(kMaxErrorsPerExtension + kNumExtraErrors - 1),
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            list.back()->message());
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Test to ensure that the error console will not add duplicate errors, but will
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// keep the latest version of an error.
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(ErrorMapUnitTest, DuplicateErrorsAreReplaced) {
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(0u, errors_.size());
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
11903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const std::string kId = crx_file::id_util::GenerateId("id");
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const size_t kNumErrors = 3u;
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Report three errors.
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < kNumErrors; ++i) {
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_TRUE(errors_.AddError(
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        CreateNewRuntimeError(kId, base::UintToString(i))));
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Create an error identical to the second error reported, save its
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // location, and add it to the error map.
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ExtensionError> runtime_error2 =
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      CreateNewRuntimeError(kId, base::UintToString(1u));
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ExtensionError* weak_error = runtime_error2.get();
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(errors_.AddError(runtime_error2.Pass()));
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // We should only have three errors stored, since two of the four reported
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // were identical, and the older should have been replaced.
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(1u, errors_.size());
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const ErrorList& list = errors_.GetErrorsForExtension(kId);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(kNumErrors, list.size());
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The duplicate error should be the last reported (pointer comparison)...
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(weak_error, list.back());
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // ... and should have two reported occurrences.
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(2u, list.back()->occurrences());
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace extensions
148