// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "base/files/scoped_temp_dir.h" #include "base/strings/stringprintf.h" #include "chrome/browser/extensions/activity_log/database_string_table.h" #include "sql/connection.h" #include "sql/statement.h" #include "sql/transaction.h" #include "testing/gtest/include/gtest/gtest.h" namespace extensions { class DatabaseStringTableTest : public testing::Test { protected: void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); base::FilePath db_file = temp_dir_.path().AppendASCII("StringTable.db"); ASSERT_TRUE(db_.Open(db_file)); } void TearDown() override { db_.Close(); } base::ScopedTempDir temp_dir_; sql::Connection db_; }; // Check that initializing the database works. TEST_F(DatabaseStringTableTest, Init) { DatabaseStringTable table("test"); table.Initialize(&db_); ASSERT_TRUE(db_.DoesTableExist("test")); ASSERT_TRUE(db_.DoesIndexExist("test_index")); } // Insert a new mapping into the table, then verify the table contents. TEST_F(DatabaseStringTableTest, Insert) { DatabaseStringTable table("test"); table.Initialize(&db_); int64_t id; ASSERT_TRUE(table.StringToInt(&db_, "abc", &id)); sql::Statement query( db_.GetUniqueStatement("SELECT id FROM test WHERE value = 'abc'")); ASSERT_TRUE(query.Step()); int64_t raw_id = query.ColumnInt64(0); ASSERT_EQ(id, raw_id); } // Check that different strings are mapped to different values, and the same // string is mapped to the same value repeatably. TEST_F(DatabaseStringTableTest, InsertMultiple) { DatabaseStringTable table("test"); table.Initialize(&db_); int64_t id1; int64_t id2; ASSERT_TRUE(table.StringToInt(&db_, "string1", &id1)); ASSERT_TRUE(table.StringToInt(&db_, "string2", &id2)); ASSERT_NE(id1, id2); int64_t id1a; ASSERT_TRUE(table.StringToInt(&db_, "string1", &id1a)); ASSERT_EQ(id1, id1a); } // Check that values can be read back from the database even after the // in-memory cache is cleared. TEST_F(DatabaseStringTableTest, CacheCleared) { DatabaseStringTable table("test"); table.Initialize(&db_); int64_t id1; ASSERT_TRUE(table.StringToInt(&db_, "string1", &id1)); table.ClearCache(); int64_t id2; ASSERT_TRUE(table.StringToInt(&db_, "string1", &id2)); ASSERT_EQ(id1, id2); } // Check that direct database modifications are picked up after the cache is // cleared. TEST_F(DatabaseStringTableTest, DatabaseModified) { DatabaseStringTable table("test"); table.Initialize(&db_); int64_t id1; ASSERT_TRUE(table.StringToInt(&db_, "modified", &id1)); ASSERT_TRUE( db_.Execute("UPDATE test SET id = id + 1 WHERE value = 'modified'")); int64_t id2; ASSERT_TRUE(table.StringToInt(&db_, "modified", &id2)); ASSERT_EQ(id1, id2); table.ClearCache(); int64_t id3; ASSERT_TRUE(table.StringToInt(&db_, "modified", &id3)); ASSERT_EQ(id1 + 1, id3); } // Check that looking up an unknown id returns an error. TEST_F(DatabaseStringTableTest, BadLookup) { DatabaseStringTable table("test"); table.Initialize(&db_); std::string value; ASSERT_FALSE(table.IntToString(&db_, 1, &value)); } // Check looking up an inserted value, both cached and not cached. TEST_F(DatabaseStringTableTest, Lookup) { DatabaseStringTable table("test"); table.Initialize(&db_); int64_t id; ASSERT_TRUE(table.StringToInt(&db_, "abc", &id)); std::string value; ASSERT_TRUE(table.IntToString(&db_, id, &value)); ASSERT_EQ("abc", value); table.ClearCache(); value = ""; ASSERT_TRUE(table.IntToString(&db_, id, &value)); ASSERT_EQ("abc", value); } // Check that the in-memory cache for the string table does not become too // large, even if many items are inserted. TEST_F(DatabaseStringTableTest, Prune) { DatabaseStringTable table("size_test"); table.Initialize(&db_); // Wrap the lookups in a transaction to improve performance. sql::Transaction transaction(&db_); transaction.Begin(); for (int i = 0; i < 2000; i++) { int64_t id; ASSERT_TRUE(table.StringToInt(&db_, base::StringPrintf("value-%d", i), &id)); } transaction.Commit(); // The maximum size below should correspond to kMaximumCacheSize in // database_string_table.cc, with a small amount of additional slop (an entry // might be inserted after doing the pruning). ASSERT_LE(table.id_to_value_.size(), 1005U); ASSERT_LE(table.value_to_id_.size(), 1005U); } } // namespace extensions