1 // Copyright 2013 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 "content/browser/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/strings/utf_string_conversions.h" 17 #include "content/common/dom_storage/dom_storage_types.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 "url/gurl.h" 23 24 namespace content { 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 DOMStorageValuesMap& reference) const; 52 void CompareValuesMaps(const DOMStorageValuesMap& map1, 53 const DOMStorageValuesMap& map2) const; 54 void CheckNamespaceIds( 55 const std::set<std::string>& expected_namespace_ids) const; 56 void CheckOrigins( 57 const std::string& namespace_id, 58 const std::set<GURL>& expected_origins) const; 59 std::string GetMapForArea(const std::string& namespace_id, 60 const GURL& origin) const; 61 int64 GetMapRefCount(const std::string& map_id) const; 62 63 base::ScopedTempDir temp_dir_; 64 scoped_refptr<SessionStorageDatabase> db_; 65 66 // Test data. 67 const GURL kOrigin1; 68 const GURL kOrigin2; 69 const std::string kNamespace1; 70 const std::string kNamespace2; 71 const std::string kNamespaceClone; 72 const base::string16 kKey1; 73 const base::string16 kKey2; 74 const base::string16 kKey3; 75 const base::NullableString16 kValue1; 76 const base::NullableString16 kValue2; 77 const base::NullableString16 kValue3; 78 const base::NullableString16 kValue4; 79 const base::NullableString16 kValueNull; 80 81 DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabaseTest); 82 }; 83 84 SessionStorageDatabaseTest::SessionStorageDatabaseTest() 85 : kOrigin1("http://www.origin1.com"), 86 kOrigin2("http://www.origin2.com"), 87 kNamespace1("namespace1"), 88 kNamespace2("namespace2"), 89 kNamespaceClone("wascloned"), 90 kKey1(base::ASCIIToUTF16("key1")), 91 kKey2(base::ASCIIToUTF16("key2")), 92 kKey3(base::ASCIIToUTF16("key3")), 93 kValue1(base::ASCIIToUTF16("value1"), false), 94 kValue2(base::ASCIIToUTF16("value2"), false), 95 kValue3(base::ASCIIToUTF16("value3"), false), 96 kValue4(base::ASCIIToUTF16("value4"), false) { } 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 if (IsNamespaceKey(it->first, &namespace_id)) { 223 found_namespace_ids.insert(namespace_id); 224 ++valid_keys; 225 } else if (IsNamespaceOriginKey( 226 it->first, &namespace_id)) { 227 // Check that the corresponding "namespace-<namespaceid>-" key exists. It 228 // has been read by now, since the keys are stored in order. 229 ASSERT_TRUE(found_namespace_ids.find(namespace_id) != 230 found_namespace_ids.end()); 231 namespaces_with_areas.insert(namespace_id); 232 int64 map_id; 233 bool conversion_ok = base::StringToInt64(it->second, &map_id); 234 ASSERT_TRUE(conversion_ok); 235 ASSERT_GE(map_id, 0); 236 ++expected_map_refcounts[map_id]; 237 max_map_id = std::max(map_id, max_map_id); 238 ++valid_keys; 239 } 240 } 241 // Check that there are no leftover "namespace-namespaceid-" keys without 242 // associated areas. 243 ASSERT_EQ(found_namespace_ids.size(), namespaces_with_areas.size()); 244 245 if (max_map_id != -1) { 246 // The database contains maps. 247 ASSERT_TRUE(data.find(next_map_id_key) != data.end()); 248 int64 next_map_id; 249 bool conversion_ok = 250 base::StringToInt64(data[next_map_id_key], &next_map_id); 251 ASSERT_TRUE(conversion_ok); 252 ASSERT_GT(next_map_id, max_map_id); 253 } 254 255 // Iterate the "map-" keys. 256 std::set<int64> found_map_ids; 257 for (DataMap::const_iterator it = data.begin(); it != data.end(); ++it) { 258 int64 map_id; 259 if (IsMapRefCountKey(it->first, &map_id)) { 260 int64 ref_count; 261 bool conversion_ok = base::StringToInt64(it->second, &ref_count); 262 ASSERT_TRUE(conversion_ok); 263 // Check that the map is not stale. 264 ASSERT_GT(ref_count, 0); 265 ASSERT_TRUE(expected_map_refcounts.find(map_id) != 266 expected_map_refcounts.end()); 267 ASSERT_EQ(expected_map_refcounts[map_id], ref_count); 268 // Mark the map as existing. 269 expected_map_refcounts.erase(map_id); 270 found_map_ids.insert(map_id); 271 ++valid_keys; 272 } else if (IsMapValueKey(it->first, &map_id)) { 273 ASSERT_TRUE(found_map_ids.find(map_id) != found_map_ids.end()); 274 ++valid_keys; 275 } 276 } 277 // Check that all maps referred to exist. 278 ASSERT_TRUE(expected_map_refcounts.empty()); 279 280 if (data.find(next_map_id_key) != data.end()) 281 ++valid_keys; 282 283 ASSERT_EQ(data.size(), valid_keys); 284 } 285 286 void SessionStorageDatabaseTest::CheckEmptyDatabase() const { 287 DataMap data; 288 ReadData(&data); 289 size_t valid_keys = 0; 290 if (data.find(SessionStorageDatabase::NamespacePrefix()) != data.end()) 291 ++valid_keys; 292 if (data.find(SessionStorageDatabase::NextMapIdKey()) != data.end()) 293 ++valid_keys; 294 EXPECT_EQ(valid_keys, data.size()); 295 } 296 297 void SessionStorageDatabaseTest::DumpData() const { 298 LOG(WARNING) << "---- Session storage contents"; 299 scoped_ptr<leveldb::Iterator> it( 300 db_->db_->NewIterator(leveldb::ReadOptions())); 301 for (it->SeekToFirst(); it->Valid(); it->Next()) { 302 int64 dummy_map_id; 303 if (IsMapValueKey(it->key().ToString(), &dummy_map_id)) { 304 // Convert the value back to base::string16. 305 base::string16 value; 306 size_t len = it->value().size() / sizeof(base::char16); 307 value.resize(len); 308 value.assign( 309 reinterpret_cast<const base::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 DOMStorageValuesMap& reference) const { 321 DOMStorageValuesMap values; 322 db_->ReadAreaValues(namespace_id, origin, &values); 323 CompareValuesMaps(values, reference); 324 } 325 326 void SessionStorageDatabaseTest::CompareValuesMaps( 327 const DOMStorageValuesMap& map1, 328 const DOMStorageValuesMap& map2) const { 329 ASSERT_EQ(map2.size(), map1.size()); 330 for (DOMStorageValuesMap::const_iterator it = map1.begin(); 331 it != map1.end(); ++it) { 332 base::string16 key = it->first; 333 ASSERT_TRUE(map2.find(key) != map2.end()); 334 base::NullableString16 val1 = it->second; 335 base::NullableString16 val2 = map2.find(key)->second; 336 EXPECT_EQ(val2.is_null(), val1.is_null()); 337 EXPECT_EQ(val2.string(), val1.string()); 338 } 339 } 340 341 void SessionStorageDatabaseTest::CheckNamespaceIds( 342 const std::set<std::string>& expected_namespace_ids) const { 343 std::map<std::string, std::vector<GURL> > namespaces_and_origins; 344 EXPECT_TRUE(db_->ReadNamespacesAndOrigins(&namespaces_and_origins)); 345 EXPECT_EQ(expected_namespace_ids.size(), namespaces_and_origins.size()); 346 for (std::map<std::string, std::vector<GURL> >::const_iterator it = 347 namespaces_and_origins.begin(); 348 it != namespaces_and_origins.end(); ++it) { 349 EXPECT_TRUE(expected_namespace_ids.find(it->first) != 350 expected_namespace_ids.end()); 351 } 352 } 353 354 void SessionStorageDatabaseTest::CheckOrigins( 355 const std::string& namespace_id, 356 const std::set<GURL>& expected_origins) const { 357 std::map<std::string, std::vector<GURL> > namespaces_and_origins; 358 EXPECT_TRUE(db_->ReadNamespacesAndOrigins(&namespaces_and_origins)); 359 const std::vector<GURL>& origins = namespaces_and_origins[namespace_id]; 360 EXPECT_EQ(expected_origins.size(), origins.size()); 361 for (std::vector<GURL>::const_iterator it = origins.begin(); 362 it != origins.end(); ++it) { 363 EXPECT_TRUE(expected_origins.find(*it) != expected_origins.end()); 364 } 365 } 366 367 std::string SessionStorageDatabaseTest::GetMapForArea( 368 const std::string& namespace_id, const GURL& origin) const { 369 bool exists; 370 std::string map_id; 371 EXPECT_TRUE(db_->GetMapForArea(namespace_id, origin.spec(), 372 leveldb::ReadOptions(), &exists, &map_id)); 373 EXPECT_TRUE(exists); 374 return map_id; 375 } 376 377 int64 SessionStorageDatabaseTest::GetMapRefCount( 378 const std::string& map_id) const { 379 int64 ref_count; 380 EXPECT_TRUE(db_->GetMapRefCount(map_id, &ref_count)); 381 return ref_count; 382 } 383 384 TEST_F(SessionStorageDatabaseTest, EmptyDatabaseSanityCheck) { 385 // An empty database should be valid. 386 CheckDatabaseConsistency(); 387 } 388 389 TEST_F(SessionStorageDatabaseTest, WriteDataForOneOrigin) { 390 // Keep track on what the values should look like. 391 DOMStorageValuesMap reference; 392 // Write data. 393 { 394 DOMStorageValuesMap changes; 395 changes[kKey1] = kValue1; 396 changes[kKey2] = kValue2; 397 changes[kKey3] = kValue3; 398 reference[kKey1] = kValue1; 399 reference[kKey2] = kValue2; 400 reference[kKey3] = kValue3; 401 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes)); 402 } 403 CheckDatabaseConsistency(); 404 CheckAreaData(kNamespace1, kOrigin1, reference); 405 406 // Overwrite and delete values. 407 { 408 DOMStorageValuesMap changes; 409 changes[kKey1] = kValue4; 410 changes[kKey3] = kValueNull; 411 reference[kKey1] = kValue4; 412 reference.erase(kKey3); 413 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes)); 414 } 415 CheckDatabaseConsistency(); 416 CheckAreaData(kNamespace1, kOrigin1, reference); 417 418 // Clear data before writing. 419 { 420 DOMStorageValuesMap changes; 421 changes[kKey2] = kValue2; 422 reference.erase(kKey1); 423 reference[kKey2] = kValue2; 424 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, true, changes)); 425 } 426 CheckDatabaseConsistency(); 427 CheckAreaData(kNamespace1, kOrigin1, reference); 428 } 429 430 TEST_F(SessionStorageDatabaseTest, WriteDataForTwoOrigins) { 431 // Write data. 432 DOMStorageValuesMap data1; 433 data1[kKey1] = kValue1; 434 data1[kKey2] = kValue2; 435 data1[kKey3] = kValue3; 436 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 437 438 DOMStorageValuesMap data2; 439 data2[kKey1] = kValue4; 440 data2[kKey2] = kValue1; 441 data2[kKey3] = kValue2; 442 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); 443 444 CheckDatabaseConsistency(); 445 CheckAreaData(kNamespace1, kOrigin1, data1); 446 CheckAreaData(kNamespace1, kOrigin2, data2); 447 } 448 449 TEST_F(SessionStorageDatabaseTest, WriteDataForTwoNamespaces) { 450 // Write data. 451 DOMStorageValuesMap data11; 452 data11[kKey1] = kValue1; 453 data11[kKey2] = kValue2; 454 data11[kKey3] = kValue3; 455 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data11)); 456 DOMStorageValuesMap data12; 457 data12[kKey2] = kValue4; 458 data12[kKey3] = kValue3; 459 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data12)); 460 DOMStorageValuesMap data21; 461 data21[kKey1] = kValue2; 462 data21[kKey2] = kValue4; 463 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin1, false, data21)); 464 DOMStorageValuesMap data22; 465 data22[kKey2] = kValue1; 466 data22[kKey3] = kValue2; 467 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin2, false, data22)); 468 CheckDatabaseConsistency(); 469 CheckAreaData(kNamespace1, kOrigin1, data11); 470 CheckAreaData(kNamespace1, kOrigin2, data12); 471 CheckAreaData(kNamespace2, kOrigin1, data21); 472 CheckAreaData(kNamespace2, kOrigin2, data22); 473 } 474 475 TEST_F(SessionStorageDatabaseTest, ShallowCopy) { 476 // Write data for a namespace, for 2 origins. 477 DOMStorageValuesMap data1; 478 data1[kKey1] = kValue1; 479 data1[kKey2] = kValue2; 480 data1[kKey3] = kValue3; 481 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 482 DOMStorageValuesMap data2; 483 data2[kKey1] = kValue2; 484 data2[kKey3] = kValue1; 485 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); 486 // Make a shallow copy. 487 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); 488 // Now both namespaces should have the same data. 489 CheckDatabaseConsistency(); 490 CheckAreaData(kNamespace1, kOrigin1, data1); 491 CheckAreaData(kNamespace1, kOrigin2, data2); 492 CheckAreaData(kNamespaceClone, kOrigin1, data1); 493 CheckAreaData(kNamespaceClone, kOrigin2, data2); 494 // Both the namespaces refer to the same maps. 495 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), 496 GetMapForArea(kNamespaceClone, kOrigin1)); 497 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), 498 GetMapForArea(kNamespaceClone, kOrigin2)); 499 EXPECT_EQ(2, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin1))); 500 EXPECT_EQ(2, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin2))); 501 } 502 503 TEST_F(SessionStorageDatabaseTest, WriteIntoShallowCopy) { 504 DOMStorageValuesMap data1; 505 data1[kKey1] = kValue1; 506 data1[kKey2] = kValue2; 507 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 508 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); 509 510 // Write data into a shallow copy. 511 DOMStorageValuesMap changes; 512 DOMStorageValuesMap reference; 513 changes[kKey1] = kValueNull; 514 changes[kKey2] = kValue4; 515 changes[kKey3] = kValue4; 516 reference[kKey2] = kValue4; 517 reference[kKey3] = kValue4; 518 EXPECT_TRUE(db_->CommitAreaChanges(kNamespaceClone, kOrigin1, false, 519 changes)); 520 521 // Values in the original namespace were not changed. 522 CheckAreaData(kNamespace1, kOrigin1, data1); 523 // But values in the copy were. 524 CheckAreaData(kNamespaceClone, kOrigin1, reference); 525 526 // The namespaces no longer refer to the same map. 527 EXPECT_NE(GetMapForArea(kNamespace1, kOrigin1), 528 GetMapForArea(kNamespaceClone, kOrigin1)); 529 EXPECT_EQ(1, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin1))); 530 EXPECT_EQ(1, GetMapRefCount(GetMapForArea(kNamespaceClone, kOrigin1))); 531 } 532 533 TEST_F(SessionStorageDatabaseTest, ManyShallowCopies) { 534 // Write data for a namespace, for 2 origins. 535 DOMStorageValuesMap data1; 536 data1[kKey1] = kValue1; 537 data1[kKey2] = kValue2; 538 data1[kKey3] = kValue3; 539 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 540 DOMStorageValuesMap data2; 541 data2[kKey1] = kValue2; 542 data2[kKey3] = kValue1; 543 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); 544 545 // Make a two shallow copies. 546 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); 547 std::string another_clone("another_cloned"); 548 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, another_clone)); 549 550 // Make a shallow copy of a shallow copy. 551 std::string clone_of_clone("clone_of_clone"); 552 EXPECT_TRUE(db_->CloneNamespace(another_clone, clone_of_clone)); 553 554 // Now all namespaces should have the same data. 555 CheckDatabaseConsistency(); 556 CheckAreaData(kNamespace1, kOrigin1, data1); 557 CheckAreaData(kNamespaceClone, kOrigin1, data1); 558 CheckAreaData(another_clone, kOrigin1, data1); 559 CheckAreaData(clone_of_clone, kOrigin1, data1); 560 CheckAreaData(kNamespace1, kOrigin2, data2); 561 CheckAreaData(kNamespaceClone, kOrigin2, data2); 562 CheckAreaData(another_clone, kOrigin2, data2); 563 CheckAreaData(clone_of_clone, kOrigin2, data2); 564 565 // All namespaces refer to the same maps. 566 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), 567 GetMapForArea(kNamespaceClone, kOrigin1)); 568 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), 569 GetMapForArea(kNamespaceClone, kOrigin2)); 570 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), 571 GetMapForArea(another_clone, kOrigin1)); 572 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), 573 GetMapForArea(another_clone, kOrigin2)); 574 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin1), 575 GetMapForArea(clone_of_clone, kOrigin1)); 576 EXPECT_EQ(GetMapForArea(kNamespace1, kOrigin2), 577 GetMapForArea(clone_of_clone, kOrigin2)); 578 579 // Check the ref counts. 580 EXPECT_EQ(4, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin1))); 581 EXPECT_EQ(4, GetMapRefCount(GetMapForArea(kNamespace1, kOrigin2))); 582 } 583 584 TEST_F(SessionStorageDatabaseTest, DisassociateShallowCopy) { 585 DOMStorageValuesMap data1; 586 data1[kKey1] = kValue1; 587 data1[kKey2] = kValue2; 588 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 589 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); 590 591 // Disassoaciate the shallow copy. 592 EXPECT_TRUE(db_->DeleteArea(kNamespaceClone, kOrigin1)); 593 CheckDatabaseConsistency(); 594 595 // Now new data can be written to that map. 596 DOMStorageValuesMap reference; 597 DOMStorageValuesMap changes; 598 changes[kKey1] = kValueNull; 599 changes[kKey2] = kValue4; 600 changes[kKey3] = kValue4; 601 reference[kKey2] = kValue4; 602 reference[kKey3] = kValue4; 603 EXPECT_TRUE(db_->CommitAreaChanges(kNamespaceClone, kOrigin1, false, 604 changes)); 605 606 // Values in the original map were not changed. 607 CheckAreaData(kNamespace1, kOrigin1, data1); 608 609 // But values in the disassociated map were. 610 CheckAreaData(kNamespaceClone, kOrigin1, reference); 611 } 612 613 TEST_F(SessionStorageDatabaseTest, DeleteNamespace) { 614 DOMStorageValuesMap data1; 615 data1[kKey1] = kValue1; 616 data1[kKey2] = kValue2; 617 data1[kKey3] = kValue3; 618 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 619 DOMStorageValuesMap data2; 620 data2[kKey2] = kValue4; 621 data2[kKey3] = kValue3; 622 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); 623 EXPECT_TRUE(db_->DeleteNamespace(kNamespace1)); 624 CheckDatabaseConsistency(); 625 CheckEmptyDatabase(); 626 } 627 628 TEST_F(SessionStorageDatabaseTest, DeleteNamespaceWithShallowCopy) { 629 // Write data for a namespace, for 2 origins. 630 DOMStorageValuesMap data1; 631 data1[kKey1] = kValue1; 632 data1[kKey2] = kValue2; 633 data1[kKey3] = kValue3; 634 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 635 DOMStorageValuesMap data2; 636 data2[kKey1] = kValue2; 637 data2[kKey3] = kValue1; 638 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); 639 640 // Make a shallow copy and delete the original namespace. 641 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); 642 EXPECT_TRUE(db_->DeleteNamespace(kNamespace1)); 643 644 // The original namespace has no data. 645 CheckDatabaseConsistency(); 646 CheckAreaData(kNamespace1, kOrigin1, DOMStorageValuesMap()); 647 CheckAreaData(kNamespace1, kOrigin2, DOMStorageValuesMap()); 648 // But the copy persists. 649 CheckAreaData(kNamespaceClone, kOrigin1, data1); 650 CheckAreaData(kNamespaceClone, kOrigin2, data2); 651 } 652 653 TEST_F(SessionStorageDatabaseTest, DeleteArea) { 654 // Write data for a namespace, for 2 origins. 655 DOMStorageValuesMap data1; 656 data1[kKey1] = kValue1; 657 data1[kKey2] = kValue2; 658 data1[kKey3] = kValue3; 659 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 660 DOMStorageValuesMap data2; 661 data2[kKey1] = kValue2; 662 data2[kKey3] = kValue1; 663 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); 664 665 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin2)); 666 CheckDatabaseConsistency(); 667 // The data for the non-deleted origin persists. 668 CheckAreaData(kNamespace1, kOrigin1, data1); 669 // The data for the deleted origin is gone. 670 CheckAreaData(kNamespace1, kOrigin2, DOMStorageValuesMap()); 671 } 672 673 TEST_F(SessionStorageDatabaseTest, DeleteAreaWithShallowCopy) { 674 // Write data for a namespace, for 2 origins. 675 DOMStorageValuesMap data1; 676 data1[kKey1] = kValue1; 677 data1[kKey2] = kValue2; 678 data1[kKey3] = kValue3; 679 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 680 DOMStorageValuesMap data2; 681 data2[kKey1] = kValue2; 682 data2[kKey3] = kValue1; 683 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); 684 685 // Make a shallow copy and delete an origin from the original namespace. 686 EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); 687 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin1)); 688 CheckDatabaseConsistency(); 689 690 // The original namespace has data for only the non-deleted origin. 691 CheckAreaData(kNamespace1, kOrigin1, DOMStorageValuesMap()); 692 CheckAreaData(kNamespace1, kOrigin2, data2); 693 // But the copy persists. 694 CheckAreaData(kNamespaceClone, kOrigin1, data1); 695 CheckAreaData(kNamespaceClone, kOrigin2, data2); 696 } 697 698 TEST_F(SessionStorageDatabaseTest, WriteRawBytes) { 699 // Write data which is not valid utf8 and contains null bytes. 700 unsigned char raw_data[10] = {255, 0, 0, 0, 1, 2, 3, 4, 5, 0}; 701 DOMStorageValuesMap changes; 702 base::string16 string_with_raw_data; 703 string_with_raw_data.assign(reinterpret_cast<base::char16*>(raw_data), 5); 704 changes[kKey1] = base::NullableString16(string_with_raw_data, false); 705 EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes)); 706 CheckDatabaseConsistency(); 707 DOMStorageValuesMap values; 708 db_->ReadAreaValues(kNamespace1, kOrigin1, &values); 709 const unsigned char* data = 710 reinterpret_cast<const unsigned char*>(values[kKey1].string().data()); 711 for (int i = 0; i < 10; ++i) 712 EXPECT_EQ(raw_data[i], data[i]); 713 } 714 715 TEST_F(SessionStorageDatabaseTest, DeleteNamespaceConfusion) { 716 // Regression test for a bug where a namespace with id 10 prevented deleting 717 // the namespace with id 1. 718 719 DOMStorageValuesMap data1; 720 data1[kKey1] = kValue1; 721 ASSERT_TRUE(db_->CommitAreaChanges("foobar", kOrigin1, false, data1)); 722 ASSERT_TRUE(db_->CommitAreaChanges("foobarbaz", kOrigin1, false, data1)); 723 724 // Delete the namespace with ID 1. 725 EXPECT_TRUE(db_->DeleteNamespace("foobar")); 726 } 727 728 TEST_F(SessionStorageDatabaseTest, ReadNamespaceIds) { 729 DOMStorageValuesMap data1; 730 data1[kKey1] = kValue1; 731 data1[kKey2] = kValue2; 732 data1[kKey3] = kValue3; 733 std::set<std::string> expected_namespace_ids; 734 735 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 736 expected_namespace_ids.insert(kNamespace1); 737 CheckNamespaceIds(expected_namespace_ids); 738 739 ASSERT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); 740 expected_namespace_ids.insert(kNamespaceClone); 741 CheckNamespaceIds(expected_namespace_ids); 742 743 ASSERT_TRUE(db_->DeleteNamespace(kNamespace1)); 744 expected_namespace_ids.erase(kNamespace1); 745 CheckNamespaceIds(expected_namespace_ids); 746 747 CheckDatabaseConsistency(); 748 } 749 750 TEST_F(SessionStorageDatabaseTest, ReadNamespaceIdsInEmptyDatabase) { 751 std::set<std::string> expected_namespace_ids; 752 CheckNamespaceIds(expected_namespace_ids); 753 } 754 755 TEST_F(SessionStorageDatabaseTest, ReadOriginsInNamespace) { 756 DOMStorageValuesMap data1; 757 data1[kKey1] = kValue1; 758 data1[kKey2] = kValue2; 759 data1[kKey3] = kValue3; 760 761 std::set<GURL> expected_origins1; 762 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 763 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data1)); 764 expected_origins1.insert(kOrigin1); 765 expected_origins1.insert(kOrigin2); 766 CheckOrigins(kNamespace1, expected_origins1); 767 768 std::set<GURL> expected_origins2; 769 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin2, false, data1)); 770 expected_origins2.insert(kOrigin2); 771 CheckOrigins(kNamespace2, expected_origins2); 772 773 ASSERT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone)); 774 CheckOrigins(kNamespaceClone, expected_origins1); 775 776 ASSERT_TRUE(db_->DeleteArea(kNamespace1, kOrigin2)); 777 expected_origins1.erase(kOrigin2); 778 CheckOrigins(kNamespace1, expected_origins1); 779 780 CheckDatabaseConsistency(); 781 } 782 783 TEST_F(SessionStorageDatabaseTest, DeleteAllOrigins) { 784 // Write data for a namespace, for 2 origins. 785 DOMStorageValuesMap data1; 786 data1[kKey1] = kValue1; 787 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1)); 788 DOMStorageValuesMap data2; 789 data2[kKey1] = kValue2; 790 ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2)); 791 792 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin1)); 793 EXPECT_TRUE(db_->DeleteArea(kNamespace1, kOrigin2)); 794 // Check that also the namespace start key was deleted. 795 CheckDatabaseConsistency(); 796 } 797 798 799 } // namespace content 800