| Index: webkit/dom_storage/session_storage_database_unittest.cc
|
| diff --git a/webkit/dom_storage/session_storage_database_unittest.cc b/webkit/dom_storage/session_storage_database_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7753d633966ae9412ea2f857f1ce24d70ac0acb2
|
| --- /dev/null
|
| +++ b/webkit/dom_storage/session_storage_database_unittest.cc
|
| @@ -0,0 +1,867 @@
|
| +// Copyright (c) 2012 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 "webkit/dom_storage/session_storage_database.h"
|
| +
|
| +#include <map>
|
| +#include <string>
|
| +
|
| +#include "base/file_util.h"
|
| +#include "base/logging.h"
|
| +#include "base/scoped_temp_dir.h"
|
| +#include "base/string_number_conversions.h"
|
| +#include "base/utf_string_conversions.h"
|
| +#include "googleurl/src/gurl.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "third_party/leveldatabase/src/include/leveldb/db.h"
|
| +#include "third_party/leveldatabase/src/include/leveldb/iterator.h"
|
| +#include "third_party/leveldatabase/src/include/leveldb/options.h"
|
| +#include "webkit/dom_storage/dom_storage_types.h"
|
| +
|
| +namespace dom_storage {
|
| +
|
| +class SessionStorageDatabaseTest : public testing::Test {
|
| + public:
|
| + SessionStorageDatabaseTest();
|
| + virtual ~SessionStorageDatabaseTest();
|
| + virtual void SetUp() OVERRIDE;
|
| +
|
| + protected:
|
| + typedef std::map<std::string, std::string> DataMap;
|
| +
|
| + // Helpers.
|
| + static bool IsNamespaceKey(const std::string& key,
|
| + int64* namespace_id);
|
| + static bool IsNamespaceOriginKey(const std::string& key,
|
| + int64* namespace_id,
|
| + std::string* origin);
|
| + static bool IsMapRefCountKey(const std::string& key,
|
| + int64* map_id);
|
| + static bool IsMapValueKey(const std::string& key,
|
| + int64* map_id);
|
| + void ResetDatabase();
|
| + void ReadData(DataMap* data) const;
|
| + void CheckConsistency() const;
|
| + void CheckEmpty() const;
|
| + void DumpData() const;
|
| + void CheckData(int64 namespace_id,
|
| + const GURL& origin,
|
| + const ValuesMap& reference) const;
|
| + void CompareValuesMaps(const ValuesMap& map1, const ValuesMap& map2) const;
|
| + std::string GetMapForArea(int64 namespace_id,
|
| + const GURL& origin) const;
|
| + int64 GetMapRefCount(const std::string& map_id) const;
|
| + int64 NextNamespaceId() const;
|
| +
|
| + ScopedTempDir temp_dir_;
|
| + scoped_refptr<SessionStorageDatabase> db_;
|
| +
|
| + // Test data.
|
| + GURL origin1;
|
| + GURL origin2;
|
| + GURL origin3;
|
| + string16 key1;
|
| + string16 key2;
|
| + string16 key3;
|
| + string16 key4;
|
| + NullableString16 value1;
|
| + NullableString16 value2;
|
| + NullableString16 value3;
|
| + NullableString16 value4;
|
| + NullableString16 value5;
|
| + NullableString16 value_null;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabaseTest);
|
| +};
|
| +
|
| +SessionStorageDatabaseTest::SessionStorageDatabaseTest()
|
| + : origin1("http://www.origin1.com"),
|
| + origin2("http://www.origin2.com"),
|
| + origin3("http://www.origin3.com"),
|
| + key1(ASCIIToUTF16("key1")),
|
| + key2(ASCIIToUTF16("key2")),
|
| + key3(ASCIIToUTF16("key3")),
|
| + key4(ASCIIToUTF16("key4")),
|
| + value1(NullableString16(ASCIIToUTF16("value1"), false)),
|
| + value2(NullableString16(ASCIIToUTF16("value2"), false)),
|
| + value3(NullableString16(ASCIIToUTF16("value3"), false)),
|
| + value4(NullableString16(ASCIIToUTF16("value4"), false)),
|
| + value5(NullableString16(ASCIIToUTF16("value5"), false)),
|
| + value_null(NullableString16(true)) { }
|
| +
|
| +SessionStorageDatabaseTest::~SessionStorageDatabaseTest() { }
|
| +
|
| +void SessionStorageDatabaseTest::SetUp() {
|
| + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
|
| + ResetDatabase();
|
| +}
|
| +
|
| +void SessionStorageDatabaseTest::ResetDatabase() {
|
| + db_ = new SessionStorageDatabase(temp_dir_.path());
|
| + ASSERT_TRUE(db_->LazyOpen(true));
|
| +}
|
| +
|
| +// static
|
| +bool SessionStorageDatabaseTest::IsNamespaceKey(const std::string& key,
|
| + int64* namespace_id) {
|
| + std::string namespace_prefix = SessionStorageDatabase::NamespacePrefix();
|
| + if (key.find(namespace_prefix) != 0)
|
| + return false;
|
| + if (key == namespace_prefix)
|
| + return false;
|
| +
|
| + size_t second_dash = key.find('-', namespace_prefix.length());
|
| + if (second_dash != std::string::npos)
|
| + return false;
|
| +
|
| + // Key is of the form "namespace-<namespaceid>".
|
| + std::string namespace_id_str = key.substr(namespace_prefix.length());
|
| + bool conversion_ok = base::StringToInt64(namespace_id_str, namespace_id);
|
| + EXPECT_TRUE(conversion_ok);
|
| + return true;
|
| +}
|
| +
|
| +// static
|
| +bool SessionStorageDatabaseTest::IsNamespaceOriginKey(const std::string& key,
|
| + int64* namespace_id,
|
| + std::string* origin) {
|
| + std::string namespace_prefix = SessionStorageDatabase::NamespacePrefix();
|
| + if (key.find(namespace_prefix) != 0)
|
| + return false;
|
| + size_t second_dash = key.find('-', namespace_prefix.length());
|
| + if (second_dash == std::string::npos)
|
| + return false;
|
| + // Key is of the form "namespace-<namespaceid>-<origin>", and the value
|
| + // is the map id.
|
| + std::string namespace_id_str =
|
| + key.substr(namespace_prefix.length(),
|
| + second_dash - namespace_prefix.length());
|
| + bool conversion_ok = base::StringToInt64(namespace_id_str, namespace_id);
|
| + EXPECT_TRUE(conversion_ok);
|
| + return true;
|
| +}
|
| +
|
| +// static
|
| +bool SessionStorageDatabaseTest::IsMapRefCountKey(const std::string& key,
|
| + int64* map_id) {
|
| + std::string map_prefix = SessionStorageDatabase::MapPrefix();
|
| + if (key.find(map_prefix) != 0)
|
| + return false;
|
| + size_t second_dash = key.find('-', map_prefix.length());
|
| + if (second_dash != std::string::npos)
|
| + return false;
|
| + // Key is of the form "map-<mapid>" and the value is the ref count.
|
| + std::string map_id_str = key.substr(map_prefix.length(), second_dash);
|
| + bool conversion_ok = base::StringToInt64(map_id_str, map_id);
|
| + EXPECT_TRUE(conversion_ok);
|
| + return true;
|
| +}
|
| +
|
| +// static
|
| +bool SessionStorageDatabaseTest::IsMapValueKey(const std::string& key,
|
| + int64* map_id) {
|
| + std::string map_prefix = SessionStorageDatabase::MapPrefix();
|
| + if (key.find(map_prefix) != 0)
|
| + return false;
|
| + size_t second_dash = key.find('-', map_prefix.length());
|
| + if (second_dash == std::string::npos)
|
| + return false;
|
| + // Key is of the form "map-<mapid>-key".
|
| + std::string map_id_str =
|
| + key.substr(map_prefix.length(), second_dash - map_prefix.length());
|
| + bool conversion_ok = base::StringToInt64(map_id_str, map_id);
|
| + EXPECT_TRUE(conversion_ok);
|
| + return true;
|
| +}
|
| +
|
| +void SessionStorageDatabaseTest::ReadData(DataMap* data) const {
|
| + leveldb::DB* leveldb = db_->db_.get();
|
| + scoped_ptr<leveldb::Iterator> it(
|
| + leveldb->NewIterator(leveldb::ReadOptions()));
|
| + for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
| + (*data)[it->key().ToString()] = it->value().ToString();
|
| + }
|
| +}
|
| +
|
| +void SessionStorageDatabaseTest::CheckConsistency() const {
|
| + DataMap data;
|
| + ReadData(&data);
|
| + // Empty db is ok.
|
| + if (data.empty())
|
| + return;
|
| +
|
| + // For detecting rubbish keys.
|
| + size_t valid_keys = 0;
|
| +
|
| + std::string next_namespace_id_key =
|
| + SessionStorageDatabase::NextNamespaceIdKey();
|
| + std::string next_map_id_key = SessionStorageDatabase::NextMapIdKey();
|
| + // Check the namespace start key.
|
| + if (data.find(SessionStorageDatabase::NamespacePrefix()) == data.end()) {
|
| + // If there is no namespace start key, the database may contain only counter
|
| + // keys.
|
| + for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) {
|
| + ASSERT_TRUE(it->first == next_namespace_id_key ||
|
| + it->first == next_map_id_key);
|
| + }
|
| + return;
|
| + }
|
| + ++valid_keys;
|
| +
|
| + // Iterate the "namespace-" keys.
|
| + std::set<int64> found_namespace_ids;
|
| + int64 max_namespace_id = -1;
|
| + std::map<int64, int64> map_refcounts;
|
| + int64 max_map_id = -1;
|
| +
|
| + for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) {
|
| + int64 namespace_id;
|
| + std::string origin;
|
| + if (IsNamespaceKey(it->first, &namespace_id)) {
|
| + ASSERT_GT(namespace_id, 0);
|
| + found_namespace_ids.insert(namespace_id);
|
| + if (namespace_id > max_namespace_id)
|
| + max_namespace_id = namespace_id;
|
| + ++valid_keys;
|
| + } else if (IsNamespaceOriginKey(
|
| + it->first, &namespace_id, &origin)) {
|
| + // Check that the corresponding "namespace-<namespaceid>" key exists. It
|
| + // has been read by now, since the keys are stored in order.
|
| + ASSERT_TRUE(found_namespace_ids.find(namespace_id) !=
|
| + found_namespace_ids.end());
|
| + int64 map_id;
|
| + bool conversion_ok = base::StringToInt64(it->second, &map_id);
|
| + ASSERT_TRUE(conversion_ok);
|
| + ASSERT_GE(map_id, 0);
|
| + ++map_refcounts[map_id];
|
| + if (map_id > max_map_id)
|
| + max_map_id = map_id;
|
| + ++valid_keys;
|
| + }
|
| + }
|
| + if (max_namespace_id != -1) {
|
| + // The database contains namespaces.
|
| + ASSERT_TRUE(data.find(next_namespace_id_key) != data.end());
|
| + int64 next_namespace_id;
|
| + bool conversion_ok =
|
| + base::StringToInt64(data[next_namespace_id_key], &next_namespace_id);
|
| + ASSERT_TRUE(conversion_ok);
|
| + ASSERT_GT(next_namespace_id, max_namespace_id);
|
| + }
|
| + if (max_map_id != -1) {
|
| + // The database contains maps.
|
| + ASSERT_TRUE(data.find(next_map_id_key) != data.end());
|
| + int64 next_map_id;
|
| + bool conversion_ok =
|
| + base::StringToInt64(data[next_map_id_key], &next_map_id);
|
| + ASSERT_TRUE(conversion_ok);
|
| + ASSERT_GT(next_map_id, max_map_id);
|
| + }
|
| +
|
| + // Iterate the "map-" keys.
|
| + std::set<int64> found_map_ids;
|
| + for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) {
|
| + int64 map_id;
|
| + if (IsMapRefCountKey(it->first, &map_id)) {
|
| + int64 ref_count;
|
| + bool conversion_ok = base::StringToInt64(it->second, &ref_count);
|
| + ASSERT_TRUE(conversion_ok);
|
| + // Check that the map is not stale.
|
| + ASSERT_GT(ref_count, 0);
|
| + ASSERT_TRUE(map_refcounts.find(map_id) != map_refcounts.end());
|
| + ASSERT_EQ(map_refcounts[map_id], ref_count);
|
| + // Mark the map as existing.
|
| + map_refcounts.erase(map_id);
|
| + found_map_ids.insert(map_id);
|
| + ++valid_keys;
|
| + } else if (IsMapValueKey(it->first, &map_id)) {
|
| + ASSERT_TRUE(found_map_ids.find(map_id) != found_map_ids.end());
|
| + ++valid_keys;
|
| + }
|
| + }
|
| + // Check that all maps referred to exist.
|
| + ASSERT_EQ(0U, map_refcounts.size());
|
| +
|
| + // Count valid keys.
|
| + if (data.find(next_namespace_id_key) != data.end())
|
| + ++valid_keys;
|
| +
|
| + if (data.find(next_map_id_key) != data.end())
|
| + ++valid_keys;
|
| +
|
| + ASSERT_EQ(data.size(), valid_keys);
|
| +}
|
| +
|
| +void SessionStorageDatabaseTest::CheckEmpty() const {
|
| + DataMap data;
|
| + ReadData(&data);
|
| + size_t valid_keys = 0;
|
| + if (data.find(SessionStorageDatabase::NamespacePrefix()) != data.end())
|
| + ++valid_keys;
|
| + if (data.find(SessionStorageDatabase::NextNamespaceIdKey()) != data.end())
|
| + ++valid_keys;
|
| + if (data.find(SessionStorageDatabase::NextMapIdKey()) != data.end())
|
| + ++valid_keys;
|
| + EXPECT_EQ(valid_keys, data.size());
|
| +}
|
| +
|
| +void SessionStorageDatabaseTest::DumpData() const {
|
| + LOG(WARNING) << "---- Session storage contents";
|
| + scoped_ptr<leveldb::Iterator> it(
|
| + db_->db_->NewIterator(leveldb::ReadOptions()));
|
| + for (it->SeekToFirst(); it->Valid(); it->Next()) {
|
| + int64 dummy_map_id;
|
| + if (IsMapValueKey(it->key().ToString(), &dummy_map_id)) {
|
| + // Convert the value back to string16.
|
| + string16 value;
|
| + size_t len = it->value().size() / sizeof(char16);
|
| + value.resize(len);
|
| + value.assign(reinterpret_cast<const char16*>(it->value().data()), len);
|
| + LOG(WARNING) << it->key().ToString() << ": " << value;
|
| + } else {
|
| + LOG(WARNING) << it->key().ToString() << ": " << it->value().ToString();
|
| + }
|
| + }
|
| + LOG(WARNING) << "----";
|
| +}
|
| +
|
| +void SessionStorageDatabaseTest::CheckData(int64 namespace_id,
|
| + const GURL& origin,
|
| + const ValuesMap& reference) const {
|
| + ValuesMap values;
|
| + db_->ReadAreaValues(namespace_id, origin, &values);
|
| + CompareValuesMaps(values, reference);
|
| +}
|
| +
|
| +void SessionStorageDatabaseTest::CompareValuesMaps(
|
| + const ValuesMap& map1,
|
| + const ValuesMap& map2) const {
|
| + ASSERT_EQ(map2.size(), map1.size());
|
| + for (ValuesMap::const_iterator it = map1.begin(); it != map1.end(); ++it) {
|
| + string16 key = it->first;
|
| + ASSERT_TRUE(map2.find(key) != map2.end());
|
| + NullableString16 val1 = it->second;
|
| + NullableString16 val2 = map2.find(key)->second;
|
| + EXPECT_EQ(val2.is_null(), val1.is_null());
|
| + EXPECT_EQ(val2.string(), val1.string());
|
| + }
|
| +}
|
| +
|
| +std::string SessionStorageDatabaseTest::GetMapForArea(
|
| + int64 namespace_id, const GURL& origin) const {
|
| + bool exists;
|
| + std::string map_id;
|
| + EXPECT_TRUE(db_->GetMapForArea(namespace_id, origin,
|
| + &exists, &map_id));
|
| + EXPECT_TRUE(exists);
|
| + return map_id;
|
| +}
|
| +
|
| +int64 SessionStorageDatabaseTest::GetMapRefCount(
|
| + const std::string& map_id) const {
|
| + int64 ref_count;
|
| + EXPECT_TRUE(db_->GetMapRefCount(map_id, &ref_count));
|
| + return ref_count;
|
| +}
|
| +
|
| +int64 SessionStorageDatabaseTest::NextNamespaceId() const {
|
| + int64 next_namespace_id;
|
| + EXPECT_TRUE(db_->GetNextNamespaceId(&next_namespace_id));
|
| + return next_namespace_id;
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, EmptyDatabaseSanityCheck) {
|
| + // An empty database should be valid.
|
| + CheckConsistency();
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, WriteDataForOneOrigin) {
|
| + // Keep track on what the values should look like.
|
| + ValuesMap reference;
|
| + // Write data.
|
| + {
|
| + ValuesMap changes;
|
| + changes[key1] = value1;
|
| + changes[key2] = value2;
|
| + changes[key3] = value3;
|
| + reference[key1] = value1;
|
| + reference[key2] = value2;
|
| + reference[key3] = value3;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, changes));
|
| + }
|
| + CheckConsistency();
|
| + CheckData(1, origin1, reference);
|
| +
|
| + // Overwrite and delete values.
|
| + {
|
| + ValuesMap changes;
|
| + changes[key1] = value4;
|
| + changes[key3] = value_null;
|
| + reference[key1] = value4;
|
| + reference.erase(key3);
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, changes));
|
| + }
|
| + CheckConsistency();
|
| + CheckData(1, origin1, reference);
|
| +
|
| + // Clear data before writing.
|
| + {
|
| + ValuesMap changes;
|
| + changes[key2] = value2;
|
| + reference.erase(key1);
|
| + reference[key2] = value2;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, true, changes));
|
| + }
|
| + CheckConsistency();
|
| + CheckData(1, origin1, reference);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, WriteDataForTwoOrigins) {
|
| + // Write data.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + data1[key3] = value3;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| +
|
| + ValuesMap data2;
|
| + data2[key1] = value4;
|
| + data2[key2] = value1;
|
| + data2[key3] = value2;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin2, false, data2));
|
| +
|
| + CheckConsistency();
|
| + CheckData(1, origin1, data1);
|
| + CheckData(1, origin2, data2);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, WriteDataForTwoNamespaces) {
|
| + // Write data.
|
| + ValuesMap data11;
|
| + data11[key1] = value1;
|
| + data11[key2] = value2;
|
| + data11[key3] = value3;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, data11));
|
| + ValuesMap data12;
|
| + data12[key2] = value4;
|
| + data12[key3] = value3;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin2, false, data12));
|
| + ValuesMap data21;
|
| + data21[key1] = value2;
|
| + data21[key2] = value4;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(2, origin1, false, data21));
|
| + ValuesMap data22;
|
| + data22[key2] = value1;
|
| + data22[key3] = value2;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(2, origin2, false, data22));
|
| + CheckConsistency();
|
| + CheckData(1, origin1, data11);
|
| + CheckData(1, origin2, data12);
|
| + CheckData(2, origin1, data21);
|
| + CheckData(2, origin2, data22);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, ShallowCopy) {
|
| + // Write data for a namespace, for 2 origins.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + data1[key3] = value3;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| + ValuesMap data2;
|
| + data2[key1] = value2;
|
| + data2[key3] = value1;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin2, false, data2));
|
| + // Make a shallow copy.
|
| + EXPECT_TRUE(db_->CloneNamespace(1, 5));
|
| + // Now both namespaces should have the same data.
|
| + CheckConsistency();
|
| + CheckData(1, origin1, data1);
|
| + CheckData(1, origin2, data2);
|
| + CheckData(5, origin1, data1);
|
| + CheckData(5, origin2, data2);
|
| + // Both the namespaces refer to the same maps.
|
| + EXPECT_EQ(GetMapForArea(1, origin1), GetMapForArea(5, origin1));
|
| + EXPECT_EQ(GetMapForArea(1, origin2), GetMapForArea(5, origin2));
|
| + EXPECT_EQ(2, GetMapRefCount(GetMapForArea(1, origin1)));
|
| + EXPECT_EQ(2, GetMapRefCount(GetMapForArea(1, origin2)));
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, DeepCopy) {
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| + EXPECT_TRUE(db_->CloneNamespace(1, 5));
|
| +
|
| + // Make the shallow copy deep.
|
| + EXPECT_TRUE(db_->DeepCopyArea(5, origin1));
|
| +
|
| + // Write data into the deep copy.
|
| + ValuesMap changes;
|
| + ValuesMap reference;
|
| + changes[key1] = value_null;
|
| + changes[key2] = value4;
|
| + changes[key3] = value4;
|
| + reference[key2] = value4;
|
| + reference[key3] = value4;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(5, origin1, false, changes));
|
| +
|
| + // Values in the original namespace were not changed.
|
| + CheckData(1, origin1, data1);
|
| + // But values in the deep copy were.
|
| + CheckData(5, origin1, reference);
|
| +
|
| + // The namespaces no longer refer to the same map.
|
| + EXPECT_NE(GetMapForArea(1, origin1), GetMapForArea(5, origin1));
|
| + EXPECT_EQ(1, GetMapRefCount(GetMapForArea(1, origin1)));
|
| + EXPECT_EQ(1, GetMapRefCount(GetMapForArea(5, origin1)));
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, ManyShallowCopies) {
|
| + // Write data for a namespace, for 2 origins.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + data1[key3] = value3;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| + ValuesMap data2;
|
| + data2[key1] = value2;
|
| + data2[key3] = value1;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin2, false, data2));
|
| +
|
| + // Make a two shallow copies.
|
| + EXPECT_TRUE(db_->CloneNamespace(1, 5));
|
| + EXPECT_TRUE(db_->CloneNamespace(1, 6));
|
| +
|
| + // Make a shallow copy of a shallow copy.
|
| + EXPECT_TRUE(db_->CloneNamespace(6, 7));
|
| +
|
| + // Now all namespaces should have the same data.
|
| + CheckConsistency();
|
| + CheckData(1, origin1, data1);
|
| + CheckData(5, origin1, data1);
|
| + CheckData(6, origin1, data1);
|
| + CheckData(7, origin1, data1);
|
| + CheckData(1, origin2, data2);
|
| + CheckData(5, origin2, data2);
|
| + CheckData(6, origin2, data2);
|
| + CheckData(7, origin2, data2);
|
| +
|
| + // All namespaces refer to the same maps.
|
| + EXPECT_EQ(GetMapForArea(1, origin1), GetMapForArea(5, origin1));
|
| + EXPECT_EQ(GetMapForArea(1, origin2), GetMapForArea(5, origin2));
|
| + EXPECT_EQ(GetMapForArea(1, origin1), GetMapForArea(6, origin1));
|
| + EXPECT_EQ(GetMapForArea(1, origin2), GetMapForArea(6, origin2));
|
| + EXPECT_EQ(GetMapForArea(1, origin1), GetMapForArea(7, origin1));
|
| + EXPECT_EQ(GetMapForArea(1, origin2), GetMapForArea(7, origin2));
|
| +
|
| + // Check the ref counts.
|
| + EXPECT_EQ(4, GetMapRefCount(GetMapForArea(1, origin1)));
|
| + EXPECT_EQ(4, GetMapRefCount(GetMapForArea(1, origin2)));
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, DisassociateShallowCopy) {
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| + EXPECT_TRUE(db_->CloneNamespace(1, 5));
|
| +
|
| + // Disassoaciate the shallow copy.
|
| + EXPECT_TRUE(db_->DeleteArea(5, origin1));
|
| + CheckConsistency();
|
| +
|
| + // Now new data can be written to that map.
|
| + ValuesMap reference;
|
| + ValuesMap changes;
|
| + changes[key1] = value_null;
|
| + changes[key2] = value4;
|
| + changes[key3] = value4;
|
| + reference[key2] = value4;
|
| + reference[key3] = value4;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(5, origin1, false, changes));
|
| +
|
| + // Values in the original map were not changed.
|
| + CheckData(1, origin1, data1);
|
| +
|
| + // But values in the disassociated map were.
|
| + CheckData(5, origin1, reference);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, DeleteNamespace) {
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + data1[key3] = value3;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| + ValuesMap data2;
|
| + data2[key2] = value4;
|
| + data2[key3] = value3;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin2, false, data2));
|
| + EXPECT_TRUE(db_->DeleteNamespace(1));
|
| + CheckConsistency();
|
| + CheckEmpty();
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, DeleteNamespaceWithShallowCopy) {
|
| + // Write data for a namespace, for 2 origins.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + data1[key3] = value3;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| + ValuesMap data2;
|
| + data2[key1] = value2;
|
| + data2[key3] = value1;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin2, false, data2));
|
| +
|
| + // Make a shallow copy and delete the original namespace.
|
| + EXPECT_TRUE(db_->CloneNamespace(1, 5));;
|
| + EXPECT_TRUE(db_->DeleteNamespace(1));
|
| +
|
| + // The original namespace has no data.
|
| + CheckConsistency();
|
| + CheckData(1, origin1, ValuesMap());
|
| + CheckData(1, origin2, ValuesMap());
|
| + // But the copy persists.
|
| + CheckData(5, origin1, data1);
|
| + CheckData(5, origin2, data2);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, DeleteArea) {
|
| + // Write data for a namespace, for 2 origins.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + data1[key3] = value3;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| + ValuesMap data2;
|
| + data2[key1] = value2;
|
| + data2[key3] = value1;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin2, false, data2));
|
| +
|
| + EXPECT_TRUE(db_->DeleteArea(1, origin2));
|
| + CheckConsistency();
|
| + // The data for the non-deleted origin persists.
|
| + CheckData(1, origin1, data1);
|
| + // The data for the deleted origin is gone.
|
| + CheckData(1, origin2, ValuesMap());
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, DeleteAreaWithShallowCopy) {
|
| + // Write data for a namespace, for 2 origins.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + data1[key3] = value3;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| + ValuesMap data2;
|
| + data2[key1] = value2;
|
| + data2[key3] = value1;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin2, false, data2));
|
| +
|
| + // Make a shallow copy and delete an origin from the original namespace.
|
| + EXPECT_TRUE(db_->CloneNamespace(1, 5));
|
| + EXPECT_TRUE(db_->DeleteArea(1, origin1));
|
| + CheckConsistency();
|
| +
|
| + // The original namespace has data for only the non-deleted origin.
|
| + CheckData(1, origin1, ValuesMap());
|
| + CheckData(1, origin2, data2);
|
| + // But the copy persists.
|
| + CheckData(5, origin1, data1);
|
| + CheckData(5, origin2, data2);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, WriteRawBytes) {
|
| + // Write data which is not valid utf8 and contains null bytes.
|
| + unsigned char raw_data[10] = {255, 0, 0, 0, 1, 2, 3, 4, 5, 0};
|
| + ValuesMap changes;
|
| + string16 string_with_raw_data;
|
| + string_with_raw_data.assign(reinterpret_cast<char16*>(raw_data), 5);
|
| + changes[key1] = NullableString16(string_with_raw_data, false);
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, changes));
|
| + CheckConsistency();
|
| + ValuesMap values;
|
| + db_->ReadAreaValues(1, origin1, &values);
|
| + const unsigned char* data =
|
| + reinterpret_cast<const unsigned char*>(values[key1].string().data());
|
| + for (int i = 0; i < 10; ++i)
|
| + EXPECT_EQ(raw_data[i], data[i]);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, NextNamespaceId) {
|
| + // Create namespaces, check the next namespace id.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(10, origin1, false, data1));
|
| + EXPECT_EQ(10 + 1, NextNamespaceId());
|
| + ASSERT_TRUE(db_->CommitAreaChanges(343, origin1, false, data1));
|
| + EXPECT_EQ(343 + 1, NextNamespaceId());
|
| + ASSERT_TRUE(db_->CommitAreaChanges(99, origin1, false, data1));
|
| + EXPECT_EQ(343 + 1, NextNamespaceId());
|
| +
|
| + // Close the database and recreate it.
|
| + ResetDatabase();
|
| +
|
| + // The next namespace id is persisted.
|
| + EXPECT_EQ(344, NextNamespaceId());
|
| +
|
| + // Create more namespaces.
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| + EXPECT_EQ(344 + 1 + 1, NextNamespaceId());
|
| +
|
| + EXPECT_TRUE(db_->CommitAreaChanges(959, origin1, false, data1));
|
| + EXPECT_EQ(344 + 959 + 1, NextNamespaceId());
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, NamespaceOffset) {
|
| + // Create a namespace with id 1.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| +
|
| + // Close the database and recreate it.
|
| + ResetDatabase();
|
| +
|
| + // Create another namespace with id 1.
|
| + ValuesMap data2;
|
| + data2[key1] = value3;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, data2));
|
| +
|
| + // Now the values for namespace 1 are the new ones.
|
| + CheckData(1, origin1, data2);
|
| +
|
| + // The values for the old namespace 1 are still accessible via id -1.
|
| + CheckData(-1, origin1, data1);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, NamespaceOffsetCloneNamespace) {
|
| + // Create a namespace with id 1.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| +
|
| + // Close the database and recreate it.
|
| + ResetDatabase();
|
| +
|
| + // Create another namespace with id 1.
|
| + ValuesMap data2;
|
| + data2[key1] = value3;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, data2));
|
| +
|
| + // Make a shallow copy of the newly created namespace.
|
| + EXPECT_TRUE(db_->CloneNamespace(1, 20));
|
| +
|
| + // The clone contains values from the newly created namespace.
|
| + CheckData(20, origin1, data2);
|
| + CheckData(1, origin1, data2);
|
| +
|
| + // The values for the old namespace 1 are still accessible via id -1.
|
| + CheckData(-1, origin1, data1);
|
| +
|
| + // Close the database and recreate it.
|
| + ResetDatabase();
|
| +
|
| + // The namespace and the clone are still accessible.
|
| + CheckData(-1, origin1, data2);
|
| + CheckData(-20, origin1, data2);
|
| + CheckData(-22, origin1, data1);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, NamespaceOffsetDeepCopyArea) {
|
| + // Create a namespace with id 1.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| +
|
| + // Close the database and recreate it.
|
| + ResetDatabase();
|
| +
|
| + // Create another namespace with id 1.
|
| + ValuesMap data2;
|
| + data2[key1] = value3;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, data2));
|
| +
|
| + // Make a shallow copy of the newly created namespace.
|
| + EXPECT_TRUE(db_->CloneNamespace(1, 20));
|
| + // And make it deep.
|
| + EXPECT_TRUE(db_->DeepCopyArea(20, origin1));
|
| +
|
| + // Now the values can be altered in the deep copy.
|
| + ValuesMap data3;
|
| + data3[key1] = value2;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(20, origin1, false, data3));
|
| +
|
| + CheckData(20, origin1, data3);
|
| + CheckData(1, origin1, data2);
|
| +
|
| + // The values for the old namespace 1 are still accessible via id -1.
|
| + CheckData(-1, origin1, data1);
|
| +
|
| + // Close the database and recreate it.
|
| + ResetDatabase();
|
| +
|
| + // The namespace and the deep copy are still accessible.
|
| + CheckData(-1, origin1, data3);
|
| + CheckData(-20, origin1, data2);
|
| + CheckData(-22, origin1, data1);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, NamespaceOffsetDeleteArea) {
|
| + // Create a namespace with id 1.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| +
|
| + // Close the database and recreate it.
|
| + ResetDatabase();
|
| +
|
| + // Create another namespace with id 1.
|
| + ValuesMap data2;
|
| + data2[key1] = value3;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, data2));
|
| +
|
| + // Delete origin1 from the newly created namespace.
|
| + EXPECT_TRUE(db_->DeleteArea(1, origin1));
|
| +
|
| + // Namespace 1 is empty.
|
| + CheckData(1, origin1, ValuesMap());
|
| +
|
| + // The values for the old namespace 1 are still accessible via id -1.
|
| + CheckData(-1, origin1, data1);
|
| +}
|
| +
|
| +TEST_F(SessionStorageDatabaseTest, NamespaceOffsetDeleteNamespace) {
|
| + // Create a namespace with id 1.
|
| + ValuesMap data1;
|
| + data1[key1] = value1;
|
| + data1[key2] = value2;
|
| + ASSERT_TRUE(db_->CommitAreaChanges(1, origin1, false, data1));
|
| +
|
| + // Close the database and recreate it.
|
| + ResetDatabase();
|
| +
|
| + // Create another namespace with id 1.
|
| + ValuesMap data2;
|
| + data2[key1] = value3;
|
| + EXPECT_TRUE(db_->CommitAreaChanges(1, origin1, false, data2));
|
| +
|
| + // Delete the newly created namespace.
|
| + EXPECT_TRUE(db_->DeleteNamespace(1));
|
| +
|
| + // Namespace 1 is empty.
|
| + CheckData(1, origin1, ValuesMap());
|
| +
|
| + // The values for the old namespace 1 are still accessible via id -1.
|
| + CheckData(-1, origin1, data1);
|
| +}
|
| +
|
| +} // namespace dom_storage
|
|
|