Chromium Code Reviews| Index: webkit/quota/quota_database_unittest.cc |
| diff --git a/webkit/quota/quota_database_unittest.cc b/webkit/quota/quota_database_unittest.cc |
| index f126f31dda0ad4bc8beb2fc679c9e95ae76db2e6..cabc0d3ff4a2342cd7164d5b58c6bca343455193 100644 |
| --- a/webkit/quota/quota_database_unittest.cc |
| +++ b/webkit/quota/quota_database_unittest.cc |
| @@ -7,6 +7,7 @@ |
| #include <set> |
| #include "app/sql/connection.h" |
| +#include "app/sql/meta_table.h" |
| #include "app/sql/statement.h" |
| #include "app/sql/transaction.h" |
| #include "base/bind.h" |
| @@ -18,6 +19,7 @@ |
| #include "webkit/quota/mock_special_storage_policy.h" |
| #include "webkit/quota/quota_database.h" |
| +namespace quota { |
| namespace { |
| const base::Time kZeroTime; |
| @@ -30,74 +32,54 @@ class TestErrorDelegate : public sql::ErrorDelegate { |
| return error; |
| } |
| }; |
| + |
| } // namespace |
| -namespace quota { |
| +namespace v2 { |
| -class QuotaDatabaseTest : public testing::Test { |
| - protected: |
| - typedef QuotaDatabase::QuotaTableEntry QuotaTableEntry; |
| - typedef QuotaDatabase::QuotaTableCallback QuotaTableCallback; |
| - typedef QuotaDatabase::LastAccessTimeTableEntry LastAccessTimeTableEntry; |
| - typedef QuotaDatabase::LastAccessTimeTableCallback |
| - LastAccessTimeTableCallback; |
| +// Definitions for version 2 database schema. |
| - template <typename Iterator> |
| - bool AssignQuotaTable( |
| - QuotaDatabase* quota_database, Iterator itr, Iterator end) { |
| - if (!quota_database->LazyOpen(true)) |
| - return false; |
| +const int kCurrentVersion = 2; |
| +const int kCompatibleVersion = 2; |
| - for (; itr != end; ++itr) { |
| - const char* kSql = |
| - "INSERT INTO HostQuotaTable" |
| - " (host, type, quota)" |
| - " VALUES (?, ?, ?)"; |
| - sql::Statement statement; |
| - statement.Assign( |
| - quota_database->db_->GetCachedStatement( |
| - SQL_FROM_HERE, kSql)); |
| - EXPECT_TRUE(statement.is_valid()); |
| +const char kHostQuotaTable[] = "HostQuotaTable"; |
| +const char kOriginLastAccessTable[] = "OriginLastAccessTable"; |
| - statement.BindString(0, itr->host); |
| - statement.BindInt(1, static_cast<int>(itr->type)); |
| - statement.BindInt64(2, itr->quota); |
| - if (!statement.Run()) |
| - return false; |
| - } |
| - |
| - quota_database->Commit(); |
| - return true; |
| - } |
| +const QuotaDatabase::TableSchema kTables[] = { |
| + { kHostQuotaTable, |
| + "(host TEXT NOT NULL," |
| + " type INTEGER NOT NULL," |
| + " quota INTEGER," |
| + " UNIQUE(host, type))" }, |
| + { kOriginLastAccessTable, |
| + "(origin TEXT NOT NULL," |
| + " type INTEGER NOT NULL," |
| + " used_count INTEGER," |
| + " last_access_time INTEGER," |
| + " UNIQUE(origin, type))" }, |
| +}; |
| - template <typename Iterator> |
| - bool AssignLastAccessTimeTable( |
| - QuotaDatabase* quota_database, Iterator itr, Iterator end) { |
| - if (!quota_database->LazyOpen(true)) |
| - return false; |
| +const QuotaDatabase::IndexSchema kIndexes[] = { |
| + { "HostIndex", |
| + kHostQuotaTable, |
| + "(host)", |
| + false }, |
| + { "OriginLastAccessIndex", |
| + kOriginLastAccessTable, |
| + "(origin, last_access_time)", |
| + false }, |
| +}; |
| - for (; itr != end; ++itr) { |
| - const char* kSql = |
| - "INSERT INTO OriginLastAccessTable" |
| - " (origin, type, used_count, last_access_time)" |
| - " VALUES (?, ?, ?, ?)"; |
| - sql::Statement statement; |
| - statement.Assign( |
| - quota_database->db_->GetCachedStatement( |
| - SQL_FROM_HERE, kSql)); |
| - EXPECT_TRUE(statement.is_valid()); |
| +} // namespace v2 |
| - statement.BindString(0, itr->origin.spec()); |
| - statement.BindInt(1, static_cast<int>(itr->type)); |
| - statement.BindInt(2, itr->used_count); |
| - statement.BindInt64(3, itr->last_access_time.ToInternalValue()); |
| - if (!statement.Run()) |
| - return false; |
| - } |
| +class QuotaDatabaseTest : public testing::Test { |
| + protected: |
| + typedef QuotaDatabase::QuotaTableEntry QuotaTableEntry; |
| + typedef QuotaDatabase::QuotaTableCallback QuotaTableCallback; |
| + typedef QuotaDatabase::OriginInfoTableEntry OriginInfoTableEntry; |
| + typedef QuotaDatabase::OriginInfoTableCallback |
| + OriginInfoTableCallback; |
| - quota_database->Commit(); |
| - return true; |
| - } |
| void LazyOpen(const FilePath& kDbFile) { |
| QuotaDatabase db(kDbFile); |
| @@ -107,6 +89,28 @@ class QuotaDatabaseTest : public testing::Test { |
| EXPECT_TRUE(kDbFile.empty() || file_util::PathExists(kDbFile)); |
| } |
| + void UpgradeSchema(const FilePath& kDbFile) { |
|
michaeln
2011/07/01 00:17:39
Might be good to be explicit about what versions y
kinuko
2011/07/04 07:43:52
Done.
|
| + const QuotaTableEntry entries[] = { |
| + { "a", kStorageTypeTemporary, 1 }, |
| + { "b", kStorageTypeTemporary, 2 }, |
| + { "c", kStorageTypePersistent, 3 }, |
| + }; |
| + |
| + CreateV2Database(kDbFile, entries, ARRAYSIZE_UNSAFE(entries)); |
| + |
| + QuotaDatabase db(kDbFile); |
| + EXPECT_TRUE(db.LazyOpen(true)); |
| + EXPECT_TRUE(db.db_.get()); |
| + |
| + typedef EntryVerifier<QuotaTableEntry> Verifier; |
| + Verifier verifier(entries, entries + ARRAYSIZE_UNSAFE(entries)); |
| + EXPECT_TRUE(db.DumpQuotaTable( |
| + new QuotaTableCallback( |
| + base::Bind(&Verifier::Run, |
| + base::Unretained(&verifier))))); |
| + EXPECT_TRUE(verifier.table.empty()); |
|
michaeln
2011/07/01 00:17:39
it took me a moment to realize how the verifier wo
|
| + } |
| + |
| void HostQuota(const FilePath& kDbFile) { |
| QuotaDatabase db(kDbFile); |
| ASSERT_TRUE(db.LazyOpen(true)); |
| @@ -223,7 +227,7 @@ class QuotaDatabaseTest : public testing::Test { |
| kOrigin1, kStorageTypeTemporary, base::Time::Now())); |
| // Delete origin/type last access time information. |
| - EXPECT_TRUE(db.DeleteOriginLastAccessTime(kOrigin3, kStorageTypeTemporary)); |
| + EXPECT_TRUE(db.DeleteOriginInfo(kOrigin3, kStorageTypeTemporary)); |
| // Querying again to see if the deletion has worked. |
| exceptions.clear(); |
| @@ -238,7 +242,77 @@ class QuotaDatabaseTest : public testing::Test { |
| EXPECT_TRUE(origin.is_empty()); |
| } |
| - void RegisterOrigins(const FilePath& kDbFile) { |
| + void OriginLastModifiedSince(const FilePath& kDbFile) { |
| + QuotaDatabase db(kDbFile); |
| + ASSERT_TRUE(db.LazyOpen(true)); |
| + |
| + std::set<GURL> origins; |
| + EXPECT_TRUE(db.GetOriginsModifiedSince( |
| + kStorageTypeTemporary, &origins, base::Time())); |
| + EXPECT_TRUE(origins.empty()); |
| + |
| + const GURL kOrigin1("http://a/"); |
| + const GURL kOrigin2("http://b/"); |
| + const GURL kOrigin3("http://c/"); |
| + |
| + // Report last mod time for the test origins. |
| + EXPECT_TRUE(db.SetOriginLastModifiedTime( |
| + kOrigin1, kStorageTypeTemporary, base::Time::FromInternalValue(10))); |
| + EXPECT_TRUE(db.SetOriginLastModifiedTime( |
| + kOrigin2, kStorageTypeTemporary, base::Time::FromInternalValue(20))); |
| + EXPECT_TRUE(db.SetOriginLastModifiedTime( |
| + kOrigin3, kStorageTypeTemporary, base::Time::FromInternalValue(30))); |
| + |
| + EXPECT_TRUE(db.GetOriginsModifiedSince( |
| + kStorageTypeTemporary, &origins, base::Time::FromInternalValue(15))); |
| + EXPECT_EQ(2U, origins.size()); |
| + EXPECT_EQ(0U, origins.count(kOrigin1)); |
| + EXPECT_EQ(1U, origins.count(kOrigin2)); |
| + EXPECT_EQ(1U, origins.count(kOrigin3)); |
| + |
| + EXPECT_TRUE(db.GetOriginsModifiedSince( |
| + kStorageTypeTemporary, &origins, base::Time::FromInternalValue(25))); |
| + EXPECT_EQ(1U, origins.size()); |
| + EXPECT_EQ(0U, origins.count(kOrigin1)); |
| + EXPECT_EQ(0U, origins.count(kOrigin2)); |
| + EXPECT_EQ(1U, origins.count(kOrigin3)); |
| + |
| + EXPECT_TRUE(db.GetOriginsModifiedSince( |
| + kStorageTypeTemporary, &origins, base::Time::FromInternalValue(35))); |
| + EXPECT_TRUE(origins.empty()); |
| + |
| + // Update origin1's mod time but for persistent storage. |
| + EXPECT_TRUE(db.SetOriginLastModifiedTime( |
| + kOrigin1, kStorageTypePersistent, base::Time::FromInternalValue(40))); |
| + |
| + // Must have no effects on temporary origins info. |
| + EXPECT_TRUE(db.GetOriginsModifiedSince( |
| + kStorageTypeTemporary, &origins, base::Time::FromInternalValue(15))); |
| + EXPECT_EQ(2U, origins.size()); |
| + EXPECT_EQ(0U, origins.count(kOrigin1)); |
| + EXPECT_EQ(1U, origins.count(kOrigin2)); |
| + EXPECT_EQ(1U, origins.count(kOrigin3)); |
| + |
| + // One more update for persistent origin2. |
| + EXPECT_TRUE(db.SetOriginLastModifiedTime( |
| + kOrigin2, kStorageTypePersistent, base::Time::FromInternalValue(50))); |
| + |
| + EXPECT_TRUE(db.GetOriginsModifiedSince( |
| + kStorageTypePersistent, &origins, base::Time::FromInternalValue(35))); |
| + EXPECT_EQ(2U, origins.size()); |
| + EXPECT_EQ(1U, origins.count(kOrigin1)); |
| + EXPECT_EQ(1U, origins.count(kOrigin2)); |
| + EXPECT_EQ(0U, origins.count(kOrigin3)); |
| + |
| + EXPECT_TRUE(db.GetOriginsModifiedSince( |
| + kStorageTypePersistent, &origins, base::Time::FromInternalValue(45))); |
| + EXPECT_EQ(1U, origins.size()); |
| + EXPECT_EQ(0U, origins.count(kOrigin1)); |
| + EXPECT_EQ(1U, origins.count(kOrigin2)); |
| + EXPECT_EQ(0U, origins.count(kOrigin3)); |
| + } |
| + |
| + void RegisterInitialOriginInfo(const FilePath& kDbFile) { |
| QuotaDatabase db(kDbFile); |
| const GURL kOrigins[] = { |
| @@ -247,9 +321,7 @@ class QuotaDatabaseTest : public testing::Test { |
| GURL("http://c/") }; |
| std::set<GURL> origins(kOrigins, kOrigins + ARRAYSIZE_UNSAFE(kOrigins)); |
| - EXPECT_TRUE(db.RegisterOrigins(origins, |
| - kStorageTypeTemporary, |
| - base::Time())); |
| + EXPECT_TRUE(db.RegisterInitialOriginInfo(origins, kStorageTypeTemporary)); |
| int used_count = -1; |
| EXPECT_TRUE(db.FindOriginUsedCount(GURL("http://a/"), |
| @@ -266,9 +338,7 @@ class QuotaDatabaseTest : public testing::Test { |
| &used_count)); |
| EXPECT_EQ(1, used_count); |
| - EXPECT_TRUE(db.RegisterOrigins(origins, |
| - kStorageTypeTemporary, |
| - base::Time())); |
| + EXPECT_TRUE(db.RegisterInitialOriginInfo(origins, kStorageTypeTemporary)); |
| used_count = -1; |
| EXPECT_TRUE(db.FindOriginUsedCount(GURL("http://a/"), |
| @@ -301,7 +371,9 @@ class QuotaDatabaseTest : public testing::Test { |
| QuotaTableEntry* end = kTableEntries + ARRAYSIZE_UNSAFE(kTableEntries); |
| QuotaDatabase db(kDbFile); |
| - EXPECT_TRUE(AssignQuotaTable(&db, begin, end)); |
| + EXPECT_TRUE(db.LazyOpen(true)); |
| + AssignQuotaTable(db.db_.get(), begin, end); |
| + db.Commit(); |
| typedef EntryVerifier<QuotaTableEntry> Verifier; |
| Verifier verifier(begin, end); |
| @@ -312,28 +384,105 @@ class QuotaDatabaseTest : public testing::Test { |
| EXPECT_TRUE(verifier.table.empty()); |
| } |
| - void DumpLastAccessTimeTable(const FilePath& kDbFile) { |
| + void DumpOriginInfoTable(const FilePath& kDbFile) { |
| base::Time now(base::Time::Now()); |
| - LastAccessTimeTableEntry kTableEntries[] = { |
| - {GURL("http://go/"), kStorageTypeTemporary, 2147483647, now}, |
| - {GURL("http://oo/"), kStorageTypeTemporary, 0, now}, |
| - {GURL("http://gle/"), kStorageTypeTemporary, 1, now}, |
| + OriginInfoTableEntry kTableEntries[] = { |
| + {GURL("http://go/"), kStorageTypeTemporary, 2147483647, now, now}, |
| + {GURL("http://oo/"), kStorageTypeTemporary, 0, now, now}, |
| + {GURL("http://gle/"), kStorageTypeTemporary, 1, now, now}, |
| }; |
| - LastAccessTimeTableEntry* begin = kTableEntries; |
| - LastAccessTimeTableEntry* end = kTableEntries + |
| - ARRAYSIZE_UNSAFE(kTableEntries); |
| + OriginInfoTableEntry* begin = kTableEntries; |
| + OriginInfoTableEntry* end = kTableEntries + ARRAYSIZE_UNSAFE(kTableEntries); |
| QuotaDatabase db(kDbFile); |
| - EXPECT_TRUE(AssignLastAccessTimeTable(&db, begin, end)); |
| + EXPECT_TRUE(db.LazyOpen(true)); |
| + AssignOriginInfoTable(db.db_.get(), begin, end); |
| + db.Commit(); |
| - typedef EntryVerifier<LastAccessTimeTableEntry> Verifier; |
| + typedef EntryVerifier<OriginInfoTableEntry> Verifier; |
| Verifier verifier(begin, end); |
| - EXPECT_TRUE(db.DumpLastAccessTimeTable( |
| - new LastAccessTimeTableCallback( |
| + EXPECT_TRUE(db.DumpOriginInfoTable( |
| + new OriginInfoTableCallback( |
| base::Bind(&Verifier::Run, |
| base::Unretained(&verifier))))); |
| EXPECT_TRUE(verifier.table.empty()); |
| } |
| + |
| + private: |
| + template <typename Iterator> |
| + void AssignQuotaTable(sql::Connection* db, Iterator itr, Iterator end) { |
| + ASSERT_NE(db, (sql::Connection*)NULL); |
| + for (; itr != end; ++itr) { |
| + const char* kSql = |
| + "INSERT INTO HostQuotaTable" |
| + " (host, type, quota)" |
| + " VALUES (?, ?, ?)"; |
| + sql::Statement statement; |
| + statement.Assign(db->GetCachedStatement(SQL_FROM_HERE, kSql)); |
| + ASSERT_TRUE(statement.is_valid()); |
| + |
| + statement.BindString(0, itr->host); |
| + statement.BindInt(1, static_cast<int>(itr->type)); |
| + statement.BindInt64(2, itr->quota); |
| + EXPECT_TRUE(statement.Run()); |
| + } |
| + } |
| + |
| + template <typename Iterator> |
| + void AssignOriginInfoTable(sql::Connection* db, Iterator itr, Iterator end) { |
| + ASSERT_NE(db, (sql::Connection*)NULL); |
| + for (; itr != end; ++itr) { |
| + const char* kSql = |
| + "INSERT INTO OriginInfoTable" |
| + " (origin, type, used_count, last_access_time, last_modified_time)" |
| + " VALUES (?, ?, ?, ?, ?)"; |
| + sql::Statement statement; |
| + statement.Assign(db->GetCachedStatement(SQL_FROM_HERE, kSql)); |
| + ASSERT_TRUE(statement.is_valid()); |
| + |
| + statement.BindString(0, itr->origin.spec()); |
| + statement.BindInt(1, static_cast<int>(itr->type)); |
| + statement.BindInt(2, itr->used_count); |
| + statement.BindInt64(3, itr->last_access_time.ToInternalValue()); |
| + statement.BindInt64(4, itr->last_modified_time.ToInternalValue()); |
| + EXPECT_TRUE(statement.Run()); |
| + } |
| + } |
| + |
| + bool OpenDatabase(sql::Connection* db, const FilePath& kDbFile) { |
| + if (kDbFile.empty()) { |
| + db->OpenInMemory(); |
| + return true; |
| + } |
| + if (!file_util::CreateDirectory(kDbFile.DirName())) |
| + return false; |
| + if (!db->Open(kDbFile)) |
| + return false; |
| + db->Preload(); |
| + return true; |
| + } |
| + |
| + // Create V2 database and populate some data. |
| + void CreateV2Database( |
| + const FilePath& kDbFile, |
| + const QuotaTableEntry* entries, |
| + size_t entries_size) { |
| + scoped_ptr<sql::Connection> db(new sql::Connection); |
| + scoped_ptr<sql::MetaTable> meta_table(new sql::MetaTable); |
| + |
| + ASSERT_TRUE(OpenDatabase(db.get(), kDbFile)); |
| + EXPECT_TRUE(QuotaDatabase::CreateSchema( |
| + db.get(), meta_table.get(), |
| + v2::kCurrentVersion, v2::kCompatibleVersion, |
| + v2::kTables, ARRAYSIZE_UNSAFE(v2::kTables), |
| + v2::kIndexes, ARRAYSIZE_UNSAFE(v2::kIndexes))); |
| + |
| + // V2 and V3 QuotaTable are compatible, so we can simply use |
| + // AssignQuotaTable to poplulate v2 database here. |
| + db->BeginTransaction(); |
| + AssignQuotaTable(db.get(), entries, entries + entries_size); |
| + db->CommitTransaction(); |
| + } |
| }; |
| TEST_F(QuotaDatabaseTest, LazyOpen) { |
| @@ -344,6 +493,13 @@ TEST_F(QuotaDatabaseTest, LazyOpen) { |
| LazyOpen(FilePath()); |
| } |
| +TEST_F(QuotaDatabaseTest, UpgradeSchema) { |
| + ScopedTempDir data_dir; |
| + ASSERT_TRUE(data_dir.CreateUniqueTempDir()); |
| + const FilePath kDbFile = data_dir.path().AppendASCII("quota_manager.db"); |
| + UpgradeSchema(kDbFile); |
| +} |
| + |
| TEST_F(QuotaDatabaseTest, HostQuota) { |
| ScopedTempDir data_dir; |
| ASSERT_TRUE(data_dir.CreateUniqueTempDir()); |
| @@ -368,6 +524,14 @@ TEST_F(QuotaDatabaseTest, OriginLastAccessTimeLRU) { |
| OriginLastAccessTimeLRU(FilePath()); |
| } |
| +TEST_F(QuotaDatabaseTest, OriginLastModifiedSince) { |
| + ScopedTempDir data_dir; |
| + ASSERT_TRUE(data_dir.CreateUniqueTempDir()); |
| + const FilePath kDbFile = data_dir.path().AppendASCII("quota_manager.db"); |
| + OriginLastModifiedSince(kDbFile); |
| + OriginLastModifiedSince(FilePath()); |
| +} |
| + |
| TEST_F(QuotaDatabaseTest, BootstrapFlag) { |
| ScopedTempDir data_dir; |
| ASSERT_TRUE(data_dir.CreateUniqueTempDir()); |
| @@ -382,12 +546,12 @@ TEST_F(QuotaDatabaseTest, BootstrapFlag) { |
| EXPECT_FALSE(db.IsOriginDatabaseBootstrapped()); |
| } |
| -TEST_F(QuotaDatabaseTest, RegisterOrigins) { |
| +TEST_F(QuotaDatabaseTest, RegisterInitialOriginInfo) { |
| ScopedTempDir data_dir; |
| ASSERT_TRUE(data_dir.CreateUniqueTempDir()); |
| const FilePath kDbFile = data_dir.path().AppendASCII("quota_manager.db"); |
| - RegisterOrigins(kDbFile); |
| - RegisterOrigins(FilePath()); |
| + RegisterInitialOriginInfo(kDbFile); |
| + RegisterInitialOriginInfo(FilePath()); |
| } |
| TEST_F(QuotaDatabaseTest, DumpQuotaTable) { |
| @@ -398,11 +562,11 @@ TEST_F(QuotaDatabaseTest, DumpQuotaTable) { |
| DumpQuotaTable(FilePath()); |
| } |
| -TEST_F(QuotaDatabaseTest, DumpLastAccessTimeTable) { |
| +TEST_F(QuotaDatabaseTest, DumpOriginInfoTable) { |
| ScopedTempDir data_dir; |
| ASSERT_TRUE(data_dir.CreateUniqueTempDir()); |
| const FilePath kDbFile = data_dir.path().AppendASCII("quota_manager.db"); |
| - DumpLastAccessTimeTable(kDbFile); |
| - DumpLastAccessTimeTable(FilePath()); |
| + DumpOriginInfoTable(kDbFile); |
| + DumpOriginInfoTable(FilePath()); |
| } |
| } // namespace quota |