| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 | |
| 6 #include "webkit/dom_storage/session_storage_database.h" | |
| 7 | |
| 8 #include <algorithm> | |
| 9 #include <map> | |
| 10 #include <string> | |
| 11 | |
| 12 #include "base/file_util.h" | |
| 13 #include "base/files/scoped_temp_dir.h" | |
| 14 #include "base/logging.h" | |
| 15 #include "base/strings/string_number_conversions.h" | |
| 16 #include "base/utf_string_conversions.h" | |
| 17 #include "googleurl/src/gurl.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 #include "third_party/leveldatabase/src/include/leveldb/db.h" | |
| 20 #include "third_party/leveldatabase/src/include/leveldb/iterator.h" | |
| 21 #include "third_party/leveldatabase/src/include/leveldb/options.h" | |
| 22 #include "webkit/dom_storage/dom_storage_types.h" | |
| 23 | |
| 24 namespace dom_storage { | |
| 25 | |
| 26 class SessionStorageDatabaseTest : public testing::Test { | |
| 27 public: | |
| 28 SessionStorageDatabaseTest(); | |
| 29 virtual ~SessionStorageDatabaseTest(); | |
| 30 virtual void SetUp() OVERRIDE; | |
| 31 | |
| 32 protected: | |
| 33 typedef std::map<std::string, std::string> DataMap; | |
| 34 | |
| 35 // Helpers. | |
| 36 static bool IsNamespaceKey(const std::string& key, | |
| 37 std::string* namespace_id); | |
| 38 static bool IsNamespaceOriginKey(const std::string& key, | |
| 39 std::string* namespace_id); | |
| 40 static bool IsMapRefCountKey(const std::string& key, | |
| 41 int64* map_id); | |
| 42 static bool IsMapValueKey(const std::string& key, | |
| 43 int64* map_id); | |
| 44 void ResetDatabase(); | |
| 45 void ReadData(DataMap* data) const; | |
| 46 void CheckDatabaseConsistency() const; | |
| 47 void CheckEmptyDatabase() const; | |
| 48 void DumpData() const; | |
| 49 void CheckAreaData(const std::string& namespace_id, | |
| 50 const GURL& origin, | |
| 51 const ValuesMap& reference) const; | |
| 52 void CompareValuesMaps(const ValuesMap& map1, const ValuesMap& map2) const; | |
| 53 void CheckNamespaceIds( | |
| 54 const std::set<std::string>& expected_namespace_ids) const; | |
| 55 void CheckOrigins( | |
| 56 const std::string& namespace_id, | |
| 57 const std::set<GURL>& expected_origins) const; | |
| 58 std::string GetMapForArea(const std::string& namespace_id, | |
| 59 const GURL& origin) const; | |
| 60 int64 GetMapRefCount(const std::string& map_id) const; | |
| 61 | |
| 62 base::ScopedTempDir temp_dir_; | |
| 63 scoped_refptr<SessionStorageDatabase> db_; | |
| 64 | |
| 65 // Test data. | |
| 66 const GURL kOrigin1; | |
| 67 const GURL kOrigin2; | |
| 68 const std::string kNamespace1; | |
| 69 const std::string kNamespace2; | |
| 70 const std::string kNamespaceClone; | |
| 71 const base::string16 kKey1; | |
| 72 const base::string16 kKey2; | |
| 73 const base::string16 kKey3; | |
| 74 const NullableString16 kValue1; | |
| 75 const NullableString16 kValue2; | |
| 76 const NullableString16 kValue3; | |
| 77 const NullableString16 kValue4; | |
| 78 const NullableString16 kValueNull; | |
| 79 | |
| 80 DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabaseTest); | |
| 81 }; | |
| 82 | |
| 83 SessionStorageDatabaseTest::SessionStorageDatabaseTest() | |
| 84 : kOrigin1("http://www.origin1.com"), | |
| 85 kOrigin2("http://www.origin2.com"), | |
| 86 kNamespace1("namespace1"), | |
| 87 kNamespace2("namespace2"), | |
| 88 kNamespaceClone("wascloned"), | |
| 89 kKey1(ASCIIToUTF16("key1")), | |
| 90 kKey2(ASCIIToUTF16("key2")), | |
| 91 kKey3(ASCIIToUTF16("key3")), | |
| 92 kValue1(NullableString16(ASCIIToUTF16("value1"), false)), | |
| 93 kValue2(NullableString16(ASCIIToUTF16("value2"), false)), | |
| 94 kValue3(NullableString16(ASCIIToUTF16("value3"), false)), | |
| 95 kValue4(NullableString16(ASCIIToUTF16("value4"), false)), | |
| 96 kValueNull(NullableString16(true)) { } | |
| 97 | |
| 98 SessionStorageDatabaseTest::~SessionStorageDatabaseTest() { } | |
| 99 | |
| 100 void SessionStorageDatabaseTest::SetUp() { | |
| 101 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
| 102 ResetDatabase(); | |
| 103 } | |
| 104 | |
| 105 void SessionStorageDatabaseTest::ResetDatabase() { | |
| 106 db_ = new SessionStorageDatabase(temp_dir_.path()); | |
| 107 ASSERT_TRUE(db_->LazyOpen(true)); | |
| 108 } | |
| 109 | |
| 110 // static | |
| 111 bool SessionStorageDatabaseTest::IsNamespaceKey(const std::string& key, | |
| 112 std::string* namespace_id) { | |
| 113 std::string namespace_prefix = SessionStorageDatabase::NamespacePrefix(); | |
| 114 if (key.find(namespace_prefix) != 0) | |
| 115 return false; | |
| 116 if (key == namespace_prefix) | |
| 117 return false; | |
| 118 | |
| 119 size_t second_dash = key.find('-', namespace_prefix.length()); | |
| 120 if (second_dash != key.length() - 1) | |
| 121 return false; | |
| 122 | |
| 123 // Key is of the form "namespace-<namespaceid>-". | |
| 124 *namespace_id = key.substr( | |
| 125 namespace_prefix.length(), | |
| 126 second_dash - namespace_prefix.length()); | |
| 127 return true; | |
| 128 } | |
| 129 | |
| 130 // static | |
| 131 bool SessionStorageDatabaseTest::IsNamespaceOriginKey( | |
| 132 const std::string& key, | |
| 133 std::string* namespace_id) { | |
| 134 std::string namespace_prefix = SessionStorageDatabase::NamespacePrefix(); | |
| 135 if (key.find(namespace_prefix) != 0) | |
| 136 return false; | |
| 137 size_t second_dash = key.find('-', namespace_prefix.length()); | |
| 138 if (second_dash == std::string::npos || second_dash == key.length() - 1) | |
| 139 return false; | |
| 140 | |
| 141 // Key is of the form "namespace-<namespaceid>-<origin>", and the value | |
| 142 // is the map id. | |
| 143 *namespace_id = key.substr( | |
| 144 namespace_prefix.length(), | |
| 145 second_dash - namespace_prefix.length()); | |
| 146 return true; | |
| 147 } | |
| 148 | |
| 149 // static | |
| 150 bool SessionStorageDatabaseTest::IsMapRefCountKey(const std::string& key, | |
| 151 int64* map_id) { | |
| 152 std::string map_prefix = "map-"; | |
| 153 if (key.find(map_prefix) != 0) | |
| 154 return false; | |
| 155 size_t second_dash = key.find('-', map_prefix.length()); | |
| 156 if (second_dash != key.length() - 1) | |
| 157 return false; | |
| 158 // Key is of the form "map-<mapid>-" and the value is the ref count. | |
| 159 std::string map_id_str = key.substr(map_prefix.length(), | |
| 160 second_dash - map_prefix.length()); | |
| 161 bool conversion_ok = base::StringToInt64(map_id_str, map_id); | |
| 162 EXPECT_TRUE(conversion_ok); | |
| 163 return true; | |
| 164 } | |
| 165 | |
| 166 // static | |
| 167 bool SessionStorageDatabaseTest::IsMapValueKey(const std::string& key, | |
| 168 int64* map_id) { | |
| 169 std::string map_prefix = "map-"; | |
| 170 if (key.find(map_prefix) != 0) | |
| 171 return false; | |
| 172 size_t second_dash = key.find('-', map_prefix.length()); | |
| 173 if (second_dash == std::string::npos || second_dash == key.length() - 1) | |
| 174 return false; | |
| 175 // Key is of the form "map-<mapid>-key". | |
| 176 std::string map_id_str = key.substr(map_prefix.length(), | |
| 177 second_dash - map_prefix.length()); | |
| 178 bool conversion_ok = base::StringToInt64(map_id_str, map_id); | |
| 179 EXPECT_TRUE(conversion_ok); | |
| 180 return true; | |
| 181 } | |
| 182 | |
| 183 void SessionStorageDatabaseTest::ReadData(DataMap* data) const { | |
| 184 leveldb::DB* leveldb = db_->db_.get(); | |
| 185 scoped_ptr<leveldb::Iterator> it( | |
| 186 leveldb->NewIterator(leveldb::ReadOptions())); | |
| 187 for (it->SeekToFirst(); it->Valid(); it->Next()) { | |
| 188 (*data)[it->key().ToString()] = it->value().ToString(); | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 void SessionStorageDatabaseTest::CheckDatabaseConsistency() const { | |
| 193 DataMap data; | |
| 194 ReadData(&data); | |
| 195 // Empty db is ok. | |
| 196 if (data.empty()) | |
| 197 return; | |
| 198 | |
| 199 // For detecting rubbish keys. | |
| 200 size_t valid_keys = 0; | |
| 201 | |
| 202 std::string next_map_id_key = SessionStorageDatabase::NextMapIdKey(); | |
| 203 // Check the namespace start key. | |
| 204 if (data.find(SessionStorageDatabase::NamespacePrefix()) == data.end()) { | |
| 205 // If there is no namespace start key, the database may contain only counter | |
| 206 // keys. | |
| 207 for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) { | |
| 208 ASSERT_TRUE(it->first == next_map_id_key); | |
| 209 } | |
| 210 return; | |
| 211 } | |
| 212 ++valid_keys; | |
| 213 | |
| 214 // Iterate the "namespace-" keys. | |
| 215 std::set<std::string> found_namespace_ids; | |
| 216 std::set<std::string> namespaces_with_areas; | |
| 217 std::map<int64, int64> expected_map_refcounts; | |
| 218 int64 max_map_id = -1; | |
| 219 | |
| 220 for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) { | |
| 221 std::string namespace_id; | |
| 222 std::string origin; | |
| 223 if (IsNamespaceKey(it->first, &namespace_id)) { | |
| 224 found_namespace_ids.insert(namespace_id); | |
| 225 ++valid_keys; | |
| 226 } else if (IsNamespaceOriginKey( | |
| 227 it->first, &namespace_id)) { | |
| 228 // Check that the corresponding "namespace-<namespaceid>-" key exists. It | |
| 229 // has been read by now, since the keys are stored in order. | |
| 230 ASSERT_TRUE(found_namespace_ids.find(namespace_id) != | |
| 231 found_namespace_ids.end()); | |
| 232 namespaces_with_areas.insert(namespace_id); | |
| 233 int64 map_id; | |
| 234 bool conversion_ok = base::StringToInt64(it->second, &map_id); | |
| 235 ASSERT_TRUE(conversion_ok); | |
| 236 ASSERT_GE(map_id, 0); | |
| 237 ++expected_map_refcounts[map_id]; | |
| 238 max_map_id = std::max(map_id, max_map_id); | |
| 239 ++valid_keys; | |
| 240 } | |
| 241 } | |
| 242 // Check that there are no leftover "namespace-namespaceid-" keys without | |
| 243 // associated areas. | |
| 244 ASSERT_EQ(found_namespace_ids.size(), namespaces_with_areas.size()); | |
| 245 | |
| 246 if (max_map_id != -1) { | |
| 247 // The database contains maps. | |
| 248 ASSERT_TRUE(data.find(next_map_id_key) != data.end()); | |
| 249 int64 next_map_id; | |
| 250 bool conversion_ok = | |
| 251 base::StringToInt64(data[next_map_id_key], &next_map_id); | |
| 252 ASSERT_TRUE(conversion_ok); | |
| 253 ASSERT_GT(next_map_id, max_map_id); | |
| 254 } | |
| 255 | |
| 256 // Iterate the "map-" keys. | |
| 257 std::set<int64> found_map_ids; | |
| 258 for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) { | |
| 259 int64 map_id; | |
| 260 if (IsMapRefCountKey(it->first, &map_id)) { | |
| 261 int64 ref_count; | |
| 262 bool conversion_ok = base::StringToInt64(it->second, &ref_count); | |
| 263 ASSERT_TRUE(conversion_ok); | |
| 264 // Check that the map is not stale. | |
| 265 ASSERT_GT(ref_count, 0); | |
| 266 ASSERT_TRUE(expected_map_refcounts.find(map_id) != | |
| 267 expected_map_refcounts.end()); | |
| 268 ASSERT_EQ(expected_map_refcounts[map_id], ref_count); | |
| 269 // Mark the map as existing. | |
| 270 expected_map_refcounts.erase(map_id); | |
| 271 found_map_ids.insert(map_id); | |
| 272 ++valid_keys; | |
| 273 } else if (IsMapValueKey(it->first, &map_id)) { | |
| 274 ASSERT_TRUE(found_map_ids.find(map_id) != found_map_ids.end()); | |
| 275 ++valid_keys; | |
| 276 } | |
| 277 } | |
| 278 // Check that all maps referred to exist. | |
| 279 ASSERT_TRUE(expected_map_refcounts.empty()); | |
| 280 | |
| 281 if (data.find(next_map_id_key) != data.end()) | |
| 282 ++valid_keys; | |
| 283 | |
| 284 ASSERT_EQ(data.size(), valid_keys); | |
| 285 } | |
| 286 | |
| 287 void SessionStorageDatabaseTest::CheckEmptyDatabase() const { | |
| 288 DataMap data; | |
| 289 ReadData(&data); | |
| 290 size_t valid_keys = 0; | |
| 291 if (data.find(SessionStorageDatabase::NamespacePrefix()) != data.end()) | |
| 292 ++valid_keys; | |
| 293 if (data.find(SessionStorageDatabase::NextMapIdKey()) != data.end()) | |
| 294 ++valid_keys; | |
| 295 EXPECT_EQ(valid_keys, data.size()); | |
| 296 } | |
| 297 | |
| 298 void SessionStorageDatabaseTest::DumpData() const { | |
| 299 LOG(WARNING) << "---- Session storage contents"; | |
| 300 scoped_ptr<leveldb::Iterator> it( | |
| 301 db_->db_->NewIterator(leveldb::ReadOptions())); | |
| 302 for (it->SeekToFirst(); it->Valid(); it->Next()) { | |
| 303 int64 dummy_map_id; | |
| 304 if (IsMapValueKey(it->key().ToString(), &dummy_map_id)) { | |
| 305 // Convert the value back to base::string16. | |
| 306 base::string16 value; | |
| 307 size_t len = it->value().size() / sizeof(char16); | |
| 308 value.resize(len); | |
| 309 value.assign(reinterpret_cast<const char16*>(it->value().data()), len); | |
| 310 LOG(WARNING) << it->key().ToString() << ": " << value; | |
| 311 } else { | |
| 312 LOG(WARNING) << it->key().ToString() << ": " << it->value().ToString(); | |
| 313 } | |
| 314 } | |
| 315 LOG(WARNING) << "----"; | |
| 316 } | |
| 317 | |
| 318 void SessionStorageDatabaseTest::CheckAreaData( | |
| 319 const std::string& namespace_id, const GURL& origin, | |
| 320 const ValuesMap& reference) const { | |
| 321 ValuesMap values; | |
| 322 db_->ReadAreaValues(namespace_id, origin, &values); | |
| 323 CompareValuesMaps(values, reference); | |
| 324 } | |
| 325 | |
| 326 void SessionStorageDatabaseTest::CompareValuesMaps( | |
| 327 const ValuesMap& map1, | |
| 328 const ValuesMap& map2) const { | |
| 329 ASSERT_EQ(map2.size(), map1.size()); | |
| 330 for (ValuesMap::const_iterator it = map1.begin(); it != map1.end(); ++it) { | |
| 331 base::string16 key = it->first; | |
| 332 ASSERT_TRUE(map2.find(key) != map2.end()); | |
| 333 NullableString16 val1 = it->second; | |
| 334 NullableString16 val2 = map2.find(key)->second; | |
| 335 EXPECT_EQ(val2.is_null(), val1.is_null()); | |
| 336 EXPECT_EQ(val2.string(), val1.string()); | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 void SessionStorageDatabaseTest::CheckNamespaceIds( | |
| 341 const std::set<std::string>& expected_namespace_ids) const { | |
| 342 std::map<std::string, std::vector<GURL> > namespaces_and_origins; | |
| 343 EXPECT_TRUE(db_->ReadNamespacesAndOrigins(&namespaces_and_origins)); | |
| 344 EXPECT_EQ(expected_namespace_ids.size(), namespaces_and_origins.size()); | |
| 345 for (std::map<std::string, std::vector<GURL> >::const_iterator it = | |
| 346 namespaces_and_origins.begin(); | |
| 347 it != namespaces_and_origins.end(); ++it) { | |
| 348 EXPECT_TRUE(expected_namespace_ids.find(it->first) != | |
| 349 expected_namespace_ids.end()); | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 void SessionStorageDatabaseTest::CheckOrigins( | |
| 354 const std::string& namespace_id, | |
| 355 const std::set<GURL>& expected_origins) const { | |
| 356 std::map<std::string, std::vector<GURL> > namespaces_and_origins; | |
| 357 EXPECT_TRUE(db_->ReadNamespacesAndOrigins(&namespaces_and_origins)); | |
| 358 const std::vector<GURL>& origins = namespaces_and_origins[namespace_id]; | |
| 359 EXPECT_EQ(expected_origins.size(), origins.size()); | |
| 360 for (std::vector<GURL>::const_iterator it = origins.begin(); | |
| 361 it != origins.end(); ++it) { | |
| 362 EXPECT_TRUE(expected_origins.find(*it) != expected_origins.end()); | |
| 363 } | |
| 364 } | |
| 365 | |
| 366 std::string SessionStorageDatabaseTest::GetMapForArea( | |
| 367 const std::string& namespace_id, const GURL& origin) const { | |
| 368 bool exists; | |
| 369 std::string map_id; | |
| 370 EXPECT_TRUE(db_->GetMapForArea(namespace_id, origin.spec(), | |
| 371 leveldb::ReadOptions(), &exists, &map_id)); | |
| 372 EXPECT_TRUE(exists); | |
| 373 return map_id; | |
| 374 } | |
| 375 | |
| 376 int64 SessionStorageDatabaseTest::GetMapRefCount( | |
| 377 const std::string& map_id) const { | |
| 378 int64 ref_count; | |
| 379 EXPECT_TRUE(db_->GetMapRefCount(map_id, &ref_count)); | |
| 380 return ref_count; | |
| 381 } | |
| 382 | |
| 383 TEST_F(SessionStorageDatabaseTest, EmptyDatabaseSanityCheck) { | |
| 384 // An empty database should be valid. | |
| 385 CheckDatabaseConsistency(); | |
| 386 } | |
| 387 | |
| 388 TEST_F(SessionStorageDatabaseTest, WriteDataForOneOrigin) { | |
| 389 // Keep track on what the values should look like. | |
| 390 ValuesMap reference; | |
| 391 // Write data. | |
| 392 { | |
| 393 ValuesMap changes; | |
| 394 changes[kKey1] = kValue1; | |
| 395 changes[kKey2] = kValue2; | |
| 396 changes[kKey3] = kValue3; | |
| 397 reference[kKey1] = kValue1; | |
| 398 reference[kKey2] = kValue2; | |
| 399 reference[kKey3] = kValue3; | |
| 400 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes)); | |
| 401 } | |
| 402 CheckDatabaseConsistency(); | |
| 403 CheckAreaData(kNamespace1, kOrigin1, reference); | |
| 404 | |
| 405 // Overwrite and delete values. | |
| 406 { | |
| 407 ValuesMap changes; | |
| 408 changes[kKey1] = kValue4; | |
| 409 changes[kKey3] = kValueNull; | |
| 410 reference[kKey1] = kValue4; | |
| 411 reference.erase(kKey3); | |
| 412 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes)); | |
| 413 } | |
| 414 CheckDatabaseConsistency(); | |
| 415 CheckAreaData(kNamespace1, kOrigin1, reference); | |
| 416 | |
| 417 // Clear data before writing. | |
| 418 { | |
| 419 ValuesMap changes; | |
| 420 changes[kKey2] = kValue2; | |
| 421 reference.erase(kKey1); | |
| 422 reference[kKey2] = kValue2; | |
| 423 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, true, changes)); | |
| 424 } | |
| 425 CheckDatabaseConsistency(); | |
| 426 CheckAreaData(kNamespace1, kOrigin1, reference); | |
| 427 } | |
| 428 | |
| 429 TEST_F(SessionStorageDatabaseTest, WriteDataForTwoOrigins) { | |
| 430 // Write data. | |
| 431 ValuesMap data1; | |
| 432 data1[kKey1] = kValue1; | |
| 433 data1[kKey2] = kValue2; | |
| 434 data1[kKey3] = kValue3; | |
| 435 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 436 | |
| 437 ValuesMap data2; | |
| 438 data2[kKey1] = kValue4; | |
| 439 data2[kKey2] = kValue1; | |
| 440 data2[kKey3] = kValue2; | |
| 441 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
| 442 | |
| 443 CheckDatabaseConsistency(); | |
| 444 CheckAreaData(kNamespace1, kOrigin1, data1); | |
| 445 CheckAreaData(kNamespace1, kOrigin2, data2); | |
| 446 } | |
| 447 | |
| 448 TEST_F(SessionStorageDatabaseTest, WriteDataForTwoNamespaces) { | |
| 449 // Write data. | |
| 450 ValuesMap data11; | |
| 451 data11[kKey1] = kValue1; | |
| 452 data11[kKey2] = kValue2; | |
| 453 data11[kKey3] = kValue3; | |
| 454 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data11)); | |
| 455 ValuesMap data12; | |
| 456 data12[kKey2] = kValue4; | |
| 457 data12[kKey3] = kValue3; | |
| 458 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data12)); | |
| 459 ValuesMap data21; | |
| 460 data21[kKey1] = kValue2; | |
| 461 data21[kKey2] = kValue4; | |
| 462 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin1, false, data21)); | |
| 463 ValuesMap data22; | |
| 464 data22[kKey2] = kValue1; | |
| 465 data22[kKey3] = kValue2; | |
| 466 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin2, false, data22)); | |
| 467 CheckDatabaseConsistency(); | |
| 468 CheckAreaData(kNamespace1, kOrigin1, data11); | |
| 469 CheckAreaData(kNamespace1, kOrigin2, data12); | |
| 470 CheckAreaData(kNamespace2, kOrigin1, data21); | |
| 471 CheckAreaData(kNamespace2, kOrigin2, data22); | |
| 472 } | |
| 473 | |
| 474 TEST_F(SessionStorageDatabaseTest, ShallowCopy) { | |
| 475 // Write data for a namespace, for 2 origins. | |
| 476 ValuesMap data1; | |
| 477 data1[kKey1] = kValue1; | |
| 478 data1[kKey2] = kValue2; | |
| 479 data1[kKey3] = kValue3; | |
| 480 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 481 ValuesMap data2; | |
| 482 data2[kKey1] = kValue2; | |
| 483 data2[kKey3] = kValue1; | |
| 484 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
| 485 // Make a shallow copy. | |
| 486 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
| 487 // Now both namespaces should have the same data. | |
| 488 CheckDatabaseConsistency(); | |
| 489 CheckAreaData(kNamespace1, kOrigin1, data1); | |
| 490 CheckAreaData(kNamespace1, kOrigin2, data2); | |
| 491 CheckAreaData(kNamespaceClone, kOrigin1, data1); | |
| 492 CheckAreaData(kNamespaceClone, kOrigin2, data2); | |
| 493 // Both the namespaces refer to the same maps. | |
| 494 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), | |
| 495 GetMapForArea(kNamespaceClone, kOrigin1)); | |
| 496 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), | |
| 497 GetMapForArea(kNamespaceClone, kOrigin2)); | |
| 498 EXPECT_EQ(2, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin1))); | |
| 499 EXPECT_EQ(2, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin2))); | |
| 500 } | |
| 501 | |
| 502 TEST_F(SessionStorageDatabaseTest, WriteIntoShallowCopy) { | |
| 503 ValuesMap data1; | |
| 504 data1[kKey1] = kValue1; | |
| 505 data1[kKey2] = kValue2; | |
| 506 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 507 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
| 508 | |
| 509 // Write data into a shallow copy. | |
| 510 ValuesMap changes; | |
| 511 ValuesMap reference; | |
| 512 changes[kKey1] = kValueNull; | |
| 513 changes[kKey2] = kValue4; | |
| 514 changes[kKey3] = kValue4; | |
| 515 reference[kKey2] = kValue4; | |
| 516 reference[kKey3] = kValue4; | |
| 517 EXPECT_TRUE(db_->CommitAreaChanges(kNamespaceClone, kOrigin1, false, | |
| 518 changes)); | |
| 519 | |
| 520 // Values in the original namespace were not changed. | |
| 521 CheckAreaData(kNamespace1, kOrigin1, data1); | |
| 522 // But values in the copy were. | |
| 523 CheckAreaData(kNamespaceClone, kOrigin1, reference); | |
| 524 | |
| 525 // The namespaces no longer refer to the same map. | |
| 526 EXPECT_NE(GetMapForArea(kNamespace1, kOrigin1), | |
| 527 GetMapForArea(kNamespaceClone, kOrigin1)); | |
| 528 EXPECT_EQ(1, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin1))); | |
| 529 EXPECT_EQ(1, GetMapRefCount(GetMapForArea(kNamespaceClone, kOrigin1))); | |
| 530 } | |
| 531 | |
| 532 TEST_F(SessionStorageDatabaseTest, ManyShallowCopies) { | |
| 533 // Write data for a namespace, for 2 origins. | |
| 534 ValuesMap data1; | |
| 535 data1[kKey1] = kValue1; | |
| 536 data1[kKey2] = kValue2; | |
| 537 data1[kKey3] = kValue3; | |
| 538 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 539 ValuesMap data2; | |
| 540 data2[kKey1] = kValue2; | |
| 541 data2[kKey3] = kValue1; | |
| 542 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
| 543 | |
| 544 // Make a two shallow copies. | |
| 545 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
| 546 std::string another_clone("another_cloned"); | |
| 547 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, another_clone)); | |
| 548 | |
| 549 // Make a shallow copy of a shallow copy. | |
| 550 std::string clone_of_clone("clone_of_clone"); | |
| 551 EXPECT_TRUE(db_->CloneNamespace(another_clone, clone_of_clone)); | |
| 552 | |
| 553 // Now all namespaces should have the same data. | |
| 554 CheckDatabaseConsistency(); | |
| 555 CheckAreaData(kNamespace1, kOrigin1, data1); | |
| 556 CheckAreaData(kNamespaceClone, kOrigin1, data1); | |
| 557 CheckAreaData(another_clone, kOrigin1, data1); | |
| 558 CheckAreaData(clone_of_clone, kOrigin1, data1); | |
| 559 CheckAreaData(kNamespace1, kOrigin2, data2); | |
| 560 CheckAreaData(kNamespaceClone, kOrigin2, data2); | |
| 561 CheckAreaData(another_clone, kOrigin2, data2); | |
| 562 CheckAreaData(clone_of_clone, kOrigin2, data2); | |
| 563 | |
| 564 // All namespaces refer to the same maps. | |
| 565 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), | |
| 566 GetMapForArea(kNamespaceClone, kOrigin1)); | |
| 567 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), | |
| 568 GetMapForArea(kNamespaceClone, kOrigin2)); | |
| 569 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), | |
| 570 GetMapForArea(another_clone, kOrigin1)); | |
| 571 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), | |
| 572 GetMapForArea(another_clone, kOrigin2)); | |
| 573 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), | |
| 574 GetMapForArea(clone_of_clone, kOrigin1)); | |
| 575 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), | |
| 576 GetMapForArea(clone_of_clone, kOrigin2)); | |
| 577 | |
| 578 // Check the ref counts. | |
| 579 EXPECT_EQ(4, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin1))); | |
| 580 EXPECT_EQ(4, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin2))); | |
| 581 } | |
| 582 | |
| 583 TEST_F(SessionStorageDatabaseTest, DisassociateShallowCopy) { | |
| 584 ValuesMap data1; | |
| 585 data1[kKey1] = kValue1; | |
| 586 data1[kKey2] = kValue2; | |
| 587 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 588 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
| 589 | |
| 590 // Disassoaciate the shallow copy. | |
| 591 EXPECT_TRUE(db_->DeleteArea(kNamespaceClone, kOrigin1)); | |
| 592 CheckDatabaseConsistency(); | |
| 593 | |
| 594 // Now new data can be written to that map. | |
| 595 ValuesMap reference; | |
| 596 ValuesMap changes; | |
| 597 changes[kKey1] = kValueNull; | |
| 598 changes[kKey2] = kValue4; | |
| 599 changes[kKey3] = kValue4; | |
| 600 reference[kKey2] = kValue4; | |
| 601 reference[kKey3] = kValue4; | |
| 602 EXPECT_TRUE(db_->CommitAreaChanges(kNamespaceClone, kOrigin1, false, | |
| 603 changes)); | |
| 604 | |
| 605 // Values in the original map were not changed. | |
| 606 CheckAreaData(kNamespace1, kOrigin1, data1); | |
| 607 | |
| 608 // But values in the disassociated map were. | |
| 609 CheckAreaData(kNamespaceClone, kOrigin1, reference); | |
| 610 } | |
| 611 | |
| 612 TEST_F(SessionStorageDatabaseTest, DeleteNamespace) { | |
| 613 ValuesMap data1; | |
| 614 data1[kKey1] = kValue1; | |
| 615 data1[kKey2] = kValue2; | |
| 616 data1[kKey3] = kValue3; | |
| 617 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 618 ValuesMap data2; | |
| 619 data2[kKey2] = kValue4; | |
| 620 data2[kKey3] = kValue3; | |
| 621 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
| 622 EXPECT_TRUE(db_->DeleteNamespace(kNamespace1)); | |
| 623 CheckDatabaseConsistency(); | |
| 624 CheckEmptyDatabase(); | |
| 625 } | |
| 626 | |
| 627 TEST_F(SessionStorageDatabaseTest, DeleteNamespaceWithShallowCopy) { | |
| 628 // Write data for a namespace, for 2 origins. | |
| 629 ValuesMap data1; | |
| 630 data1[kKey1] = kValue1; | |
| 631 data1[kKey2] = kValue2; | |
| 632 data1[kKey3] = kValue3; | |
| 633 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 634 ValuesMap data2; | |
| 635 data2[kKey1] = kValue2; | |
| 636 data2[kKey3] = kValue1; | |
| 637 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
| 638 | |
| 639 // Make a shallow copy and delete the original namespace. | |
| 640 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
| 641 EXPECT_TRUE(db_->DeleteNamespace(kNamespace1)); | |
| 642 | |
| 643 // The original namespace has no data. | |
| 644 CheckDatabaseConsistency(); | |
| 645 CheckAreaData(kNamespace1, kOrigin1, ValuesMap()); | |
| 646 CheckAreaData(kNamespace1, kOrigin2, ValuesMap()); | |
| 647 // But the copy persists. | |
| 648 CheckAreaData(kNamespaceClone, kOrigin1, data1); | |
| 649 CheckAreaData(kNamespaceClone, kOrigin2, data2); | |
| 650 } | |
| 651 | |
| 652 TEST_F(SessionStorageDatabaseTest, DeleteArea) { | |
| 653 // Write data for a namespace, for 2 origins. | |
| 654 ValuesMap data1; | |
| 655 data1[kKey1] = kValue1; | |
| 656 data1[kKey2] = kValue2; | |
| 657 data1[kKey3] = kValue3; | |
| 658 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 659 ValuesMap data2; | |
| 660 data2[kKey1] = kValue2; | |
| 661 data2[kKey3] = kValue1; | |
| 662 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
| 663 | |
| 664 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin2)); | |
| 665 CheckDatabaseConsistency(); | |
| 666 // The data for the non-deleted origin persists. | |
| 667 CheckAreaData(kNamespace1, kOrigin1, data1); | |
| 668 // The data for the deleted origin is gone. | |
| 669 CheckAreaData(kNamespace1, kOrigin2, ValuesMap()); | |
| 670 } | |
| 671 | |
| 672 TEST_F(SessionStorageDatabaseTest, DeleteAreaWithShallowCopy) { | |
| 673 // Write data for a namespace, for 2 origins. | |
| 674 ValuesMap data1; | |
| 675 data1[kKey1] = kValue1; | |
| 676 data1[kKey2] = kValue2; | |
| 677 data1[kKey3] = kValue3; | |
| 678 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 679 ValuesMap data2; | |
| 680 data2[kKey1] = kValue2; | |
| 681 data2[kKey3] = kValue1; | |
| 682 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
| 683 | |
| 684 // Make a shallow copy and delete an origin from the original namespace. | |
| 685 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
| 686 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin1)); | |
| 687 CheckDatabaseConsistency(); | |
| 688 | |
| 689 // The original namespace has data for only the non-deleted origin. | |
| 690 CheckAreaData(kNamespace1, kOrigin1, ValuesMap()); | |
| 691 CheckAreaData(kNamespace1, kOrigin2, data2); | |
| 692 // But the copy persists. | |
| 693 CheckAreaData(kNamespaceClone, kOrigin1, data1); | |
| 694 CheckAreaData(kNamespaceClone, kOrigin2, data2); | |
| 695 } | |
| 696 | |
| 697 TEST_F(SessionStorageDatabaseTest, WriteRawBytes) { | |
| 698 // Write data which is not valid utf8 and contains null bytes. | |
| 699 unsigned char raw_data[10] = {255, 0, 0, 0, 1, 2, 3, 4, 5, 0}; | |
| 700 ValuesMap changes; | |
| 701 base::string16 string_with_raw_data; | |
| 702 string_with_raw_data.assign(reinterpret_cast<char16*>(raw_data), 5); | |
| 703 changes[kKey1] = NullableString16(string_with_raw_data, false); | |
| 704 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes)); | |
| 705 CheckDatabaseConsistency(); | |
| 706 ValuesMap values; | |
| 707 db_->ReadAreaValues(kNamespace1, kOrigin1, &values); | |
| 708 const unsigned char* data = | |
| 709 reinterpret_cast<const unsigned char*>(values[kKey1].string().data()); | |
| 710 for (int i = 0; i < 10; ++i) | |
| 711 EXPECT_EQ(raw_data[i], data[i]); | |
| 712 } | |
| 713 | |
| 714 TEST_F(SessionStorageDatabaseTest, DeleteNamespaceConfusion) { | |
| 715 // Regression test for a bug where a namespace with id 10 prevented deleting | |
| 716 // the namespace with id 1. | |
| 717 | |
| 718 ValuesMap data1; | |
| 719 data1[kKey1] = kValue1; | |
| 720 ASSERT_TRUE(db_->CommitAreaChanges("foobar", kOrigin1, false, data1)); | |
| 721 ASSERT_TRUE(db_->CommitAreaChanges("foobarbaz", kOrigin1, false, data1)); | |
| 722 | |
| 723 // Delete the namespace with ID 1. | |
| 724 EXPECT_TRUE(db_->DeleteNamespace("foobar")); | |
| 725 } | |
| 726 | |
| 727 TEST_F(SessionStorageDatabaseTest, ReadNamespaceIds) { | |
| 728 ValuesMap data1; | |
| 729 data1[kKey1] = kValue1; | |
| 730 data1[kKey2] = kValue2; | |
| 731 data1[kKey3] = kValue3; | |
| 732 std::set<std::string> expected_namespace_ids; | |
| 733 | |
| 734 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 735 expected_namespace_ids.insert(kNamespace1); | |
| 736 CheckNamespaceIds(expected_namespace_ids); | |
| 737 | |
| 738 ASSERT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
| 739 expected_namespace_ids.insert(kNamespaceClone); | |
| 740 CheckNamespaceIds(expected_namespace_ids); | |
| 741 | |
| 742 ASSERT_TRUE(db_->DeleteNamespace(kNamespace1)); | |
| 743 expected_namespace_ids.erase(kNamespace1); | |
| 744 CheckNamespaceIds(expected_namespace_ids); | |
| 745 | |
| 746 CheckDatabaseConsistency(); | |
| 747 } | |
| 748 | |
| 749 TEST_F(SessionStorageDatabaseTest, ReadNamespaceIdsInEmptyDatabase) { | |
| 750 std::set<std::string> expected_namespace_ids; | |
| 751 CheckNamespaceIds(expected_namespace_ids); | |
| 752 } | |
| 753 | |
| 754 TEST_F(SessionStorageDatabaseTest, ReadOriginsInNamespace) { | |
| 755 ValuesMap data1; | |
| 756 data1[kKey1] = kValue1; | |
| 757 data1[kKey2] = kValue2; | |
| 758 data1[kKey3] = kValue3; | |
| 759 | |
| 760 std::set<GURL> expected_origins1; | |
| 761 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 762 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data1)); | |
| 763 expected_origins1.insert(kOrigin1); | |
| 764 expected_origins1.insert(kOrigin2); | |
| 765 CheckOrigins(kNamespace1, expected_origins1); | |
| 766 | |
| 767 std::set<GURL> expected_origins2; | |
| 768 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin2, false, data1)); | |
| 769 expected_origins2.insert(kOrigin2); | |
| 770 CheckOrigins(kNamespace2, expected_origins2); | |
| 771 | |
| 772 ASSERT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); | |
| 773 CheckOrigins(kNamespaceClone, expected_origins1); | |
| 774 | |
| 775 ASSERT_TRUE(db_->DeleteArea(kNamespace1, kOrigin2)); | |
| 776 expected_origins1.erase(kOrigin2); | |
| 777 CheckOrigins(kNamespace1, expected_origins1); | |
| 778 | |
| 779 CheckDatabaseConsistency(); | |
| 780 } | |
| 781 | |
| 782 TEST_F(SessionStorageDatabaseTest, DeleteAllOrigins) { | |
| 783 // Write data for a namespace, for 2 origins. | |
| 784 ValuesMap data1; | |
| 785 data1[kKey1] = kValue1; | |
| 786 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); | |
| 787 ValuesMap data2; | |
| 788 data2[kKey1] = kValue2; | |
| 789 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); | |
| 790 | |
| 791 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin1)); | |
| 792 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin2)); | |
| 793 // Check that also the namespace start key was deleted. | |
| 794 CheckDatabaseConsistency(); | |
| 795 } | |
| 796 | |
| 797 | |
| 798 } // namespace dom_storage | |
| OLD | NEW |