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; |
michaeln
2012/04/26 05:07:43
can these all be const, and named as such, kFoo?
marja
2012/04/27 07:34:47
Done.
|
+ 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); |
michaeln
2012/04/26 22:07:02
do you also want to pull the origin out of 'key' a
marja
2012/04/27 07:34:47
Done (latter).
|
+ 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 { |
michaeln
2012/04/26 22:07:02
nit: to be more clear about the scope of what is b
marja
2012/04/27 07:34:47
Done.
|
+ 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; |
michaeln
2012/04/26 22:07:02
would 'expected_map_refcounts' be a more informati
marja
2012/04/27 07:34:47
Done.
|
+ 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; |
michaeln
2012/04/26 22:07:02
might be able to use std::max() here for better re
marja
2012/04/27 07:34:47
Done.
|
+ ++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; |
michaeln
2012/04/26 22:07:02
ditto std::max
marja
2012/04/27 07:34:47
Done.
|
+ ++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()); |
michaeln
2012/04/26 22:07:02
could use map.empty() here
marja
2012/04/27 07:34:47
Done.
|
+ |
+ // 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 { |
michaeln
2012/04/26 22:07:02
nit: CheckEmptyDatabase
marja
2012/04/27 07:34:47
Done.
|
+ 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, |
michaeln
2012/04/26 22:07:02
nit: CheckAreaData
marja
2012/04/27 07:34:47
Done.
|
+ 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 |