| Index: content/browser/indexed_db/indexed_db_backing_store_unittest.cc
|
| diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e92b38c31a4fde35928146ea0bd2861b589b2c74
|
| --- /dev/null
|
| +++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
|
| @@ -0,0 +1,404 @@
|
| +// Copyright (c) 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 "content/browser/indexed_db/indexed_db_backing_store.h"
|
| +
|
| +#include "base/files/scoped_temp_dir.h"
|
| +#include "base/logging.h"
|
| +#include "base/string16.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "content/browser/indexed_db/indexed_db_factory_impl.h"
|
| +#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "third_party/WebKit/Source/Platform/chromium/public/WebData.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
|
| +
|
| +using WebKit::WebSecurityOrigin;
|
| +using WebKit::WebIDBKey;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +class IndexedDBBackingStoreTest : public testing::Test {
|
| + public:
|
| + IndexedDBBackingStoreTest() {}
|
| + virtual void SetUp() {
|
| + string16 file_identifier;
|
| + backing_store_ = IndexedDBBackingStore::OpenInMemory(file_identifier);
|
| +
|
| + // useful keys and values during tests
|
| + const char raw_value1[] = "value1";
|
| +
|
| + const char raw_value2[] = "value2";
|
| + const char raw_value3[] = "value3";
|
| + m_value1.insert(
|
| + m_value1.end(), &raw_value1[0], &raw_value1[0] + sizeof(raw_value1));
|
| + m_value2.insert(
|
| + m_value2.end(), &raw_value2[0], &raw_value2[0] + sizeof(raw_value2));
|
| + m_value3.insert(
|
| + m_value3.end(), &raw_value3[0], &raw_value3[0] + sizeof(raw_value3));
|
| + m_key1 = IndexedDBKey(99, WebIDBKey::NumberType);
|
| + m_key2 = IndexedDBKey(ASCIIToUTF16("key2"));
|
| + m_key3 = IndexedDBKey(ASCIIToUTF16("key3"));
|
| + }
|
| +
|
| + protected:
|
| + scoped_refptr<IndexedDBBackingStore> backing_store_;
|
| +
|
| + // Sample keys and values that are consistent.
|
| + IndexedDBKey m_key1;
|
| + IndexedDBKey m_key2;
|
| + IndexedDBKey m_key3;
|
| + std::vector<char> m_value1;
|
| + std::vector<char> m_value2;
|
| + std::vector<char> m_value3;
|
| +};
|
| +
|
| +TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
|
| + {
|
| + IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
|
| + transaction1.begin();
|
| + IndexedDBBackingStore::RecordIdentifier record;
|
| + bool ok = backing_store_->PutRecord(
|
| + &transaction1, 1, 1, m_key1, m_value1, &record);
|
| + EXPECT_TRUE(ok);
|
| + transaction1.Commit();
|
| + }
|
| +
|
| + {
|
| + IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
|
| + transaction2.begin();
|
| + std::vector<char> result_value;
|
| + bool ok =
|
| + backing_store_->GetRecord(&transaction2, 1, 1, m_key1, result_value);
|
| + transaction2.Commit();
|
| + EXPECT_TRUE(ok);
|
| + EXPECT_EQ(m_value1, result_value);
|
| + }
|
| +}
|
| +
|
| +// Make sure that using very high ( more than 32 bit ) values for database_id
|
| +// and object_store_id still work.
|
| +TEST_F(IndexedDBBackingStoreTest, HighIds) {
|
| + const int64_t high_database_id = 1ULL << 35;
|
| + const int64_t high_object_store_id = 1ULL << 39;
|
| + // index_ids are capped at 32 bits for storage purposes.
|
| + const int64_t high_index_id = 1ULL << 29;
|
| +
|
| + const int64_t invalid_high_index_id = 1ULL << 37;
|
| +
|
| + const IndexedDBKey& index_key = m_key2;
|
| + std::vector<char> index_key_raw = EncodeIDBKey(index_key);
|
| + {
|
| + IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
|
| + transaction1.begin();
|
| + IndexedDBBackingStore::RecordIdentifier record;
|
| + bool ok = backing_store_->PutRecord(&transaction1,
|
| + high_database_id,
|
| + high_object_store_id,
|
| + m_key1,
|
| + m_value1,
|
| + &record);
|
| + EXPECT_TRUE(ok);
|
| +
|
| + ok = backing_store_->PutIndexDataForRecord(&transaction1,
|
| + high_database_id,
|
| + high_object_store_id,
|
| + invalid_high_index_id,
|
| + index_key,
|
| + record);
|
| + EXPECT_FALSE(ok);
|
| +
|
| + ok = backing_store_->PutIndexDataForRecord(&transaction1,
|
| + high_database_id,
|
| + high_object_store_id,
|
| + high_index_id,
|
| + index_key,
|
| + record);
|
| + EXPECT_TRUE(ok);
|
| +
|
| + ok = transaction1.Commit();
|
| + EXPECT_TRUE(ok);
|
| + }
|
| +
|
| + {
|
| + IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
|
| + transaction2.begin();
|
| + std::vector<char> result_value;
|
| + bool ok = backing_store_->GetRecord(&transaction2,
|
| + high_database_id,
|
| + high_object_store_id,
|
| + m_key1,
|
| + result_value);
|
| + EXPECT_TRUE(ok);
|
| + EXPECT_EQ(m_value1, result_value);
|
| +
|
| + scoped_ptr<IndexedDBKey> new_primary_key;
|
| + ok = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
|
| + high_database_id,
|
| + high_object_store_id,
|
| + invalid_high_index_id,
|
| + index_key,
|
| + &new_primary_key);
|
| + EXPECT_FALSE(ok);
|
| +
|
| + ok = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
|
| + high_database_id,
|
| + high_object_store_id,
|
| + high_index_id,
|
| + index_key,
|
| + &new_primary_key);
|
| + EXPECT_TRUE(ok);
|
| + EXPECT_TRUE(new_primary_key->IsEqual(m_key1));
|
| +
|
| + ok = transaction2.Commit();
|
| + EXPECT_TRUE(ok);
|
| + }
|
| +}
|
| +
|
| +// Make sure that other invalid ids do not crash.
|
| +TEST_F(IndexedDBBackingStoreTest, InvalidIds) {
|
| + // valid ids for use when testing invalid ids
|
| + const int64_t database_id = 1;
|
| + const int64_t object_store_id = 1;
|
| + const int64_t index_id = kMinimumIndexId;
|
| + const int64_t invalid_low_index_id =
|
| + 19; // index_ids must be > kMinimumIndexId
|
| +
|
| + std::vector<char> result_value;
|
| +
|
| + IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
|
| + transaction1.begin();
|
| +
|
| + IndexedDBBackingStore::RecordIdentifier record;
|
| + bool ok = backing_store_->PutRecord(&transaction1,
|
| + database_id,
|
| + KeyPrefix::kInvalidId,
|
| + m_key1,
|
| + m_value1,
|
| + &record);
|
| + EXPECT_FALSE(ok);
|
| + ok = backing_store_->PutRecord(
|
| + &transaction1, database_id, 0, m_key1, m_value1, &record);
|
| + EXPECT_FALSE(ok);
|
| + ok = backing_store_->PutRecord(&transaction1,
|
| + KeyPrefix::kInvalidId,
|
| + object_store_id,
|
| + m_key1,
|
| + m_value1,
|
| + &record);
|
| + EXPECT_FALSE(ok);
|
| + ok = backing_store_->PutRecord(
|
| + &transaction1, 0, object_store_id, m_key1, m_value1, &record);
|
| + EXPECT_FALSE(ok);
|
| +
|
| + ok = backing_store_->GetRecord(
|
| + &transaction1, database_id, KeyPrefix::kInvalidId, m_key1, result_value);
|
| + EXPECT_FALSE(ok);
|
| + ok = backing_store_->GetRecord(
|
| + &transaction1, database_id, 0, m_key1, result_value);
|
| + EXPECT_FALSE(ok);
|
| + ok = backing_store_->GetRecord(&transaction1,
|
| + KeyPrefix::kInvalidId,
|
| + object_store_id,
|
| + m_key1,
|
| + result_value);
|
| + EXPECT_FALSE(ok);
|
| + ok = backing_store_->GetRecord(
|
| + &transaction1, 0, object_store_id, m_key1, result_value);
|
| + EXPECT_FALSE(ok);
|
| +
|
| + scoped_ptr<IndexedDBKey> new_primary_key;
|
| + ok = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
|
| + database_id,
|
| + object_store_id,
|
| + KeyPrefix::kInvalidId,
|
| + m_key1,
|
| + &new_primary_key);
|
| + EXPECT_FALSE(ok);
|
| + ok = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
|
| + database_id,
|
| + object_store_id,
|
| + invalid_low_index_id,
|
| + m_key1,
|
| + &new_primary_key);
|
| + EXPECT_FALSE(ok);
|
| + ok = backing_store_->GetPrimaryKeyViaIndex(
|
| + &transaction1, database_id, object_store_id, 0, m_key1, &new_primary_key);
|
| + EXPECT_FALSE(ok);
|
| +
|
| + ok = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
|
| + KeyPrefix::kInvalidId,
|
| + object_store_id,
|
| + index_id,
|
| + m_key1,
|
| + &new_primary_key);
|
| + EXPECT_FALSE(ok);
|
| + ok = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
|
| + database_id,
|
| + KeyPrefix::kInvalidId,
|
| + index_id,
|
| + m_key1,
|
| + &new_primary_key);
|
| + EXPECT_FALSE(ok);
|
| +}
|
| +
|
| +TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
|
| + const string16 database_name(ASCIIToUTF16("db1"));
|
| + int64_t database_id;
|
| + const string16 version(ASCIIToUTF16("old_string_version"));
|
| + const int64_t int_version = 9;
|
| +
|
| + const int64_t object_store_id = 99;
|
| + const string16 object_store_name(ASCIIToUTF16("object_store1"));
|
| + const bool auto_increment = true;
|
| + const IndexedDBKeyPath object_store_key_path(
|
| + ASCIIToUTF16("object_store_key"));
|
| +
|
| + const int64_t index_id = 999;
|
| + const string16 index_name(ASCIIToUTF16("index1"));
|
| + const bool unique = true;
|
| + const bool multi_entry = true;
|
| + const IndexedDBKeyPath index_key_path(ASCIIToUTF16("index_key"));
|
| +
|
| + {
|
| + bool ok = backing_store_->CreateIDBDatabaseMetaData(
|
| + database_name, version, int_version, database_id);
|
| + EXPECT_TRUE(ok);
|
| + EXPECT_GT(database_id, 0);
|
| +
|
| + IndexedDBBackingStore::Transaction transaction(backing_store_.get());
|
| + transaction.begin();
|
| +
|
| + ok = backing_store_->CreateObjectStore(&transaction,
|
| + database_id,
|
| + object_store_id,
|
| + object_store_name,
|
| + object_store_key_path,
|
| + auto_increment);
|
| + EXPECT_TRUE(ok);
|
| +
|
| + ok = backing_store_->CreateIndex(&transaction,
|
| + database_id,
|
| + object_store_id,
|
| + index_id,
|
| + index_name,
|
| + index_key_path,
|
| + unique,
|
| + multi_entry);
|
| + EXPECT_TRUE(ok);
|
| +
|
| + ok = transaction.Commit();
|
| + EXPECT_TRUE(ok);
|
| + }
|
| +
|
| + {
|
| + IndexedDBDatabaseMetadata database;
|
| + bool found;
|
| + bool ok =
|
| + backing_store_->GetIDBDatabaseMetaData(database_name, &database, found);
|
| + EXPECT_TRUE(ok);
|
| + EXPECT_TRUE(found);
|
| +
|
| + // database.name is not filled in by the implementation.
|
| + EXPECT_EQ(version, database.version);
|
| + EXPECT_EQ(int_version, database.int_version);
|
| + EXPECT_EQ(database_id, database.id);
|
| +
|
| + ok = backing_store_->GetObjectStores(database.id, &database.object_stores);
|
| + EXPECT_TRUE(ok);
|
| +
|
| + EXPECT_EQ(1UL, database.object_stores.size());
|
| + IndexedDBObjectStoreMetadata object_store =
|
| + database.object_stores[object_store_id];
|
| + EXPECT_EQ(object_store_name, object_store.name);
|
| + EXPECT_EQ(object_store_key_path, object_store.key_path);
|
| + EXPECT_EQ(auto_increment, object_store.auto_increment);
|
| +
|
| + EXPECT_EQ(1UL, object_store.indexes.size());
|
| + IndexedDBIndexMetadata index = object_store.indexes[index_id];
|
| + EXPECT_EQ(index_name, index.name);
|
| + EXPECT_EQ(index_key_path, index.key_path);
|
| + EXPECT_EQ(unique, index.unique);
|
| + EXPECT_EQ(multi_entry, index.multi_entry);
|
| + }
|
| +}
|
| +
|
| +class MockIDBFactory : public IndexedDBFactoryImpl {
|
| + public:
|
| + static scoped_refptr<MockIDBFactory> Create() {
|
| + return make_scoped_refptr(new MockIDBFactory());
|
| + }
|
| +
|
| + scoped_refptr<IndexedDBBackingStore> TestOpenBackingStore(
|
| + const WebSecurityOrigin& origin,
|
| + const base::FilePath& data_directory) {
|
| + string16 path = UTF8ToUTF16(data_directory.AsUTF8Unsafe());
|
| + return OpenBackingStore(origin.databaseIdentifier(), path);
|
| + }
|
| +
|
| + private:
|
| + virtual ~MockIDBFactory() {}
|
| +};
|
| +
|
| +TEST(IndexedDBFactoryTest, BackingStoreLifetime) {
|
| + WebSecurityOrigin origin1 =
|
| + WebSecurityOrigin::createFromString("http://localhost:81");
|
| + WebSecurityOrigin origin2 =
|
| + WebSecurityOrigin::createFromString("http://localhost:82");
|
| +
|
| + scoped_refptr<MockIDBFactory> factory = MockIDBFactory::Create();
|
| +
|
| + base::ScopedTempDir temp_directory;
|
| + DCHECK(temp_directory.CreateUniqueTempDir());
|
| + scoped_refptr<IndexedDBBackingStore> disk_store1 =
|
| + factory->TestOpenBackingStore(origin1, temp_directory.path());
|
| + EXPECT_TRUE(disk_store1->HasOneRef());
|
| +
|
| + scoped_refptr<IndexedDBBackingStore> disk_store2 =
|
| + factory->TestOpenBackingStore(origin1, temp_directory.path());
|
| + EXPECT_EQ(disk_store1.get(), disk_store2.get());
|
| + // TODO(alecflett): Verify refcount indirectly.
|
| + // EXPECT_EQ(2, disk_store2->RefCount());
|
| +
|
| + scoped_refptr<IndexedDBBackingStore> disk_store3 =
|
| + factory->TestOpenBackingStore(origin2, temp_directory.path());
|
| + EXPECT_TRUE(disk_store3->HasOneRef());
|
| + // TODO(alecflett): Verify refcount indirectly.
|
| + // EXPECT_EQ(2, disk_store1->RefCount());
|
| +}
|
| +
|
| +TEST(IndexedDBFactoryTest, MemoryBackingStoreLifetime) {
|
| + WebSecurityOrigin origin1 =
|
| + WebSecurityOrigin::createFromString("http://localhost:81");
|
| + WebSecurityOrigin origin2 =
|
| + WebSecurityOrigin::createFromString("http://localhost:82");
|
| +
|
| + scoped_refptr<MockIDBFactory> factory = MockIDBFactory::Create();
|
| + scoped_refptr<IndexedDBBackingStore> mem_store1 =
|
| + factory->TestOpenBackingStore(origin1, base::FilePath());
|
| + // TODO(alecflett): Verify refcount indirectly.
|
| + // EXPECT_EQ(2, mem_store1->RefCount());
|
| + scoped_refptr<IndexedDBBackingStore> mem_store2 =
|
| + factory->TestOpenBackingStore(origin1, base::FilePath());
|
| + EXPECT_EQ(mem_store1.get(), mem_store2.get());
|
| + // TODO(alecflett): Verify refcount indirectly.
|
| + // EXPECT_EQ(3, mem_store2->RefCount());
|
| +
|
| + scoped_refptr<IndexedDBBackingStore> mem_store3 =
|
| + factory->TestOpenBackingStore(origin2, base::FilePath());
|
| + // TODO(alecflett): Verify refcount indirectly.
|
| + // EXPECT_EQ(2, mem_store3->RefCount());
|
| + // EXPECT_EQ(3, mem_store1->RefCount());
|
| +
|
| + factory = NULL;
|
| + // TODO(alecflett): Verify refcount indirectly.
|
| + // EXPECT_EQ(2, mem_store1->RefCount());
|
| + // EXPECT_EQ(1, mem_store3->RefCount());
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +} // namespace content
|
|
|