1 // Copyright (c) 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 #include "content/browser/indexed_db/indexed_db_backing_store.h" 6 7 #include "base/callback.h" 8 #include "base/file_util.h" 9 #include "base/files/scoped_temp_dir.h" 10 #include "base/logging.h" 11 #include "base/macros.h" 12 #include "base/strings/string16.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "base/task_runner.h" 15 #include "base/test/test_simple_task_runner.h" 16 #include "content/browser/indexed_db/indexed_db_context_impl.h" 17 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" 18 #include "content/browser/indexed_db/indexed_db_value.h" 19 #include "content/public/test/mock_special_storage_policy.h" 20 #include "net/url_request/url_request_test_util.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 #include "third_party/WebKit/public/platform/WebIDBTypes.h" 23 #include "webkit/browser/blob/blob_data_handle.h" 24 #include "webkit/browser/quota/special_storage_policy.h" 25 26 using base::ASCIIToUTF16; 27 28 namespace content { 29 30 namespace { 31 32 class Comparator : public LevelDBComparator { 33 public: 34 virtual int Compare(const base::StringPiece& a, 35 const base::StringPiece& b) const OVERRIDE { 36 return content::Compare(a, b, false /*index_keys*/); 37 } 38 virtual const char* Name() const OVERRIDE { return "idb_cmp1"; } 39 }; 40 41 class DefaultLevelDBFactory : public LevelDBFactory { 42 public: 43 DefaultLevelDBFactory() {} 44 virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, 45 const LevelDBComparator* comparator, 46 scoped_ptr<LevelDBDatabase>* db, 47 bool* is_disk_full) OVERRIDE { 48 return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full); 49 } 50 virtual leveldb::Status DestroyLevelDB( 51 const base::FilePath& file_name) OVERRIDE { 52 return LevelDBDatabase::Destroy(file_name); 53 } 54 55 private: 56 DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory); 57 }; 58 59 class TestableIndexedDBBackingStore : public IndexedDBBackingStore { 60 public: 61 static scoped_refptr<TestableIndexedDBBackingStore> Open( 62 IndexedDBFactory* indexed_db_factory, 63 const GURL& origin_url, 64 const base::FilePath& path_base, 65 net::URLRequestContext* request_context, 66 LevelDBFactory* leveldb_factory, 67 base::TaskRunner* task_runner) { 68 DCHECK(!path_base.empty()); 69 70 scoped_ptr<LevelDBComparator> comparator(new Comparator()); 71 72 if (!base::CreateDirectory(path_base)) 73 return scoped_refptr<TestableIndexedDBBackingStore>(); 74 75 const base::FilePath file_path = path_base.AppendASCII("test_db_path"); 76 const base::FilePath blob_path = path_base.AppendASCII("test_blob_path"); 77 78 scoped_ptr<LevelDBDatabase> db; 79 bool is_disk_full = false; 80 leveldb::Status status = leveldb_factory->OpenLevelDB( 81 file_path, comparator.get(), &db, &is_disk_full); 82 83 if (!db || !status.ok()) 84 return scoped_refptr<TestableIndexedDBBackingStore>(); 85 86 scoped_refptr<TestableIndexedDBBackingStore> backing_store( 87 new TestableIndexedDBBackingStore(indexed_db_factory, 88 origin_url, 89 blob_path, 90 request_context, 91 db.Pass(), 92 comparator.Pass(), 93 task_runner)); 94 95 if (!backing_store->SetUpMetadata()) 96 return scoped_refptr<TestableIndexedDBBackingStore>(); 97 98 return backing_store; 99 } 100 101 const std::vector<IndexedDBBackingStore::Transaction::WriteDescriptor>& 102 writes() const { 103 return writes_; 104 } 105 void ClearWrites() { writes_.clear(); } 106 const std::vector<int64>& removals() const { return removals_; } 107 void ClearRemovals() { removals_.clear(); } 108 109 protected: 110 virtual ~TestableIndexedDBBackingStore() {} 111 112 virtual bool WriteBlobFile( 113 int64 database_id, 114 const Transaction::WriteDescriptor& descriptor, 115 Transaction::ChainedBlobWriter* chained_blob_writer) OVERRIDE { 116 if (KeyPrefix::IsValidDatabaseId(database_id_)) { 117 if (database_id_ != database_id) { 118 return false; 119 } 120 } else { 121 database_id_ = database_id; 122 } 123 writes_.push_back(descriptor); 124 task_runner()->PostTask( 125 FROM_HERE, 126 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion, 127 chained_blob_writer, 128 true, 129 1)); 130 return true; 131 } 132 133 virtual bool RemoveBlobFile(int64 database_id, int64 key) OVERRIDE { 134 if (database_id_ != database_id || 135 !KeyPrefix::IsValidDatabaseId(database_id)) { 136 return false; 137 } 138 removals_.push_back(key); 139 return true; 140 } 141 142 // Timers don't play nicely with unit tests. 143 virtual void StartJournalCleaningTimer() OVERRIDE { 144 CleanPrimaryJournalIgnoreReturn(); 145 } 146 147 private: 148 TestableIndexedDBBackingStore(IndexedDBFactory* indexed_db_factory, 149 const GURL& origin_url, 150 const base::FilePath& blob_path, 151 net::URLRequestContext* request_context, 152 scoped_ptr<LevelDBDatabase> db, 153 scoped_ptr<LevelDBComparator> comparator, 154 base::TaskRunner* task_runner) 155 : IndexedDBBackingStore(indexed_db_factory, 156 origin_url, 157 blob_path, 158 request_context, 159 db.Pass(), 160 comparator.Pass(), 161 task_runner), 162 database_id_(0) {} 163 164 int64 database_id_; 165 std::vector<Transaction::WriteDescriptor> writes_; 166 std::vector<int64> removals_; 167 168 DISALLOW_COPY_AND_ASSIGN(TestableIndexedDBBackingStore); 169 }; 170 171 class TestIDBFactory : public IndexedDBFactory { 172 public: 173 explicit TestIDBFactory(IndexedDBContextImpl* idb_context) 174 : IndexedDBFactory(idb_context) {} 175 176 scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest( 177 const GURL& origin, 178 net::URLRequestContext* url_request_context) { 179 blink::WebIDBDataLoss data_loss; 180 std::string data_loss_reason; 181 bool disk_full; 182 scoped_refptr<IndexedDBBackingStore> backing_store = 183 OpenBackingStore(origin, 184 context()->data_path(), 185 url_request_context, 186 &data_loss, 187 &data_loss_reason, 188 &disk_full); 189 scoped_refptr<TestableIndexedDBBackingStore> testable_store = 190 static_cast<TestableIndexedDBBackingStore*>(backing_store.get()); 191 return testable_store; 192 } 193 194 protected: 195 virtual ~TestIDBFactory() {} 196 197 virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper( 198 const GURL& origin_url, 199 const base::FilePath& data_directory, 200 net::URLRequestContext* request_context, 201 blink::WebIDBDataLoss* data_loss, 202 std::string* data_loss_message, 203 bool* disk_full, 204 bool first_time) OVERRIDE { 205 DefaultLevelDBFactory leveldb_factory; 206 return TestableIndexedDBBackingStore::Open(this, 207 origin_url, 208 data_directory, 209 request_context, 210 &leveldb_factory, 211 context()->TaskRunner()); 212 } 213 214 private: 215 DISALLOW_COPY_AND_ASSIGN(TestIDBFactory); 216 }; 217 218 class IndexedDBBackingStoreTest : public testing::Test { 219 public: 220 IndexedDBBackingStoreTest() {} 221 virtual void SetUp() { 222 const GURL origin("http://localhost:81"); 223 task_runner_ = new base::TestSimpleTaskRunner(); 224 special_storage_policy_ = new MockSpecialStoragePolicy(); 225 special_storage_policy_->SetAllUnlimited(true); 226 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 227 idb_context_ = new IndexedDBContextImpl( 228 temp_dir_.path(), special_storage_policy_, NULL, task_runner_); 229 idb_factory_ = new TestIDBFactory(idb_context_); 230 backing_store_ = 231 idb_factory_->OpenBackingStoreForTest(origin, &url_request_context_); 232 233 // useful keys and values during tests 234 m_value1 = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>()); 235 m_value2 = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>()); 236 237 m_blob_info.push_back( 238 IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1)); 239 m_blob_info.push_back( 240 IndexedDBBlobInfo("uuid 4", 241 base::FilePath(FILE_PATH_LITERAL("path/to/file")), 242 base::UTF8ToUTF16("file name"), 243 base::UTF8ToUTF16("file type"))); 244 m_value3 = IndexedDBValue("value3", m_blob_info); 245 246 m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber); 247 m_key2 = IndexedDBKey(ASCIIToUTF16("key2")); 248 m_key3 = IndexedDBKey(ASCIIToUTF16("key3")); 249 } 250 251 // This just checks the data that survive getting stored and recalled, e.g. 252 // the file path and UUID will change and thus aren't verified. 253 bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const { 254 if (m_blob_info.size() != reads.size()) 255 return false; 256 for (size_t i = 0; i < m_blob_info.size(); ++i) { 257 const IndexedDBBlobInfo& a = m_blob_info[i]; 258 const IndexedDBBlobInfo& b = reads[i]; 259 if (a.is_file() != b.is_file()) 260 return false; 261 if (a.type() != b.type()) 262 return false; 263 if (a.is_file()) { 264 if (a.file_name() != b.file_name()) 265 return false; 266 } else { 267 if (a.size() != b.size()) 268 return false; 269 } 270 } 271 return true; 272 } 273 274 bool CheckBlobReadsMatchWrites( 275 const std::vector<IndexedDBBlobInfo>& reads) const { 276 if (backing_store_->writes().size() != reads.size()) 277 return false; 278 std::set<int64> ids; 279 for (size_t i = 0; i < backing_store_->writes().size(); ++i) 280 ids.insert(backing_store_->writes()[i].key()); 281 if (ids.size() != backing_store_->writes().size()) 282 return false; 283 for (size_t i = 0; i < reads.size(); ++i) { 284 if (ids.count(reads[i].key()) != 1) 285 return false; 286 } 287 return true; 288 } 289 290 bool CheckBlobWrites() const { 291 if (backing_store_->writes().size() != m_blob_info.size()) 292 return false; 293 for (size_t i = 0; i < backing_store_->writes().size(); ++i) { 294 const IndexedDBBackingStore::Transaction::WriteDescriptor& desc = 295 backing_store_->writes()[i]; 296 const IndexedDBBlobInfo& info = m_blob_info[i]; 297 if (desc.is_file() != info.is_file()) 298 return false; 299 if (desc.is_file()) { 300 if (desc.file_path() != info.file_path()) 301 return false; 302 } else { 303 if (desc.url() != GURL("blob:uuid/" + info.uuid())) 304 return false; 305 } 306 } 307 return true; 308 } 309 310 bool CheckBlobRemovals() const { 311 if (backing_store_->removals().size() != backing_store_->writes().size()) 312 return false; 313 for (size_t i = 0; i < backing_store_->writes().size(); ++i) { 314 if (backing_store_->writes()[i].key() != backing_store_->removals()[i]) 315 return false; 316 } 317 return true; 318 } 319 320 protected: 321 base::ScopedTempDir temp_dir_; 322 scoped_refptr<base::TestSimpleTaskRunner> task_runner_; 323 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_; 324 scoped_refptr<IndexedDBContextImpl> idb_context_; 325 scoped_refptr<TestIDBFactory> idb_factory_; 326 net::TestURLRequestContext url_request_context_; 327 328 scoped_refptr<TestableIndexedDBBackingStore> backing_store_; 329 330 // Sample keys and values that are consistent. 331 IndexedDBKey m_key1; 332 IndexedDBKey m_key2; 333 IndexedDBKey m_key3; 334 IndexedDBValue m_value1; 335 IndexedDBValue m_value2; 336 IndexedDBValue m_value3; 337 std::vector<IndexedDBBlobInfo> m_blob_info; 338 339 private: 340 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest); 341 }; 342 343 class TestCallback : public IndexedDBBackingStore::BlobWriteCallback { 344 public: 345 TestCallback() : called(false), succeeded(false) {} 346 virtual void Run(bool succeeded_in) OVERRIDE { 347 called = true; 348 succeeded = succeeded_in; 349 } 350 bool called; 351 bool succeeded; 352 353 protected: 354 virtual ~TestCallback() {} 355 356 private: 357 DISALLOW_COPY_AND_ASSIGN(TestCallback); 358 }; 359 360 TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) { 361 { 362 IndexedDBBackingStore::Transaction transaction1(backing_store_); 363 transaction1.Begin(); 364 ScopedVector<webkit_blob::BlobDataHandle> handles; 365 IndexedDBBackingStore::RecordIdentifier record; 366 leveldb::Status s = backing_store_->PutRecord( 367 &transaction1, 1, 1, m_key1, m_value1, &handles, &record); 368 EXPECT_TRUE(s.ok()); 369 scoped_refptr<TestCallback> callback(new TestCallback()); 370 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); 371 EXPECT_TRUE(callback->called); 372 EXPECT_TRUE(callback->succeeded); 373 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); 374 } 375 376 { 377 IndexedDBBackingStore::Transaction transaction2(backing_store_); 378 transaction2.Begin(); 379 IndexedDBValue result_value; 380 EXPECT_TRUE( 381 backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value) 382 .ok()); 383 scoped_refptr<TestCallback> callback(new TestCallback()); 384 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); 385 EXPECT_TRUE(callback->called); 386 EXPECT_TRUE(callback->succeeded); 387 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); 388 EXPECT_EQ(m_value1.bits, result_value.bits); 389 } 390 } 391 392 TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) { 393 { 394 IndexedDBBackingStore::Transaction transaction1(backing_store_); 395 transaction1.Begin(); 396 ScopedVector<webkit_blob::BlobDataHandle> handles; 397 IndexedDBBackingStore::RecordIdentifier record; 398 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 399 1, 400 1, 401 m_key3, 402 m_value3, 403 &handles, 404 &record).ok()); 405 scoped_refptr<TestCallback> callback(new TestCallback()); 406 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); 407 task_runner_->RunUntilIdle(); 408 EXPECT_TRUE(CheckBlobWrites()); 409 EXPECT_TRUE(callback->called); 410 EXPECT_TRUE(callback->succeeded); 411 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); 412 } 413 414 { 415 IndexedDBBackingStore::Transaction transaction2(backing_store_); 416 transaction2.Begin(); 417 IndexedDBValue result_value; 418 EXPECT_TRUE( 419 backing_store_->GetRecord(&transaction2, 1, 1, m_key3, &result_value) 420 .ok()); 421 scoped_refptr<TestCallback> callback(new TestCallback()); 422 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); 423 EXPECT_TRUE(callback->called); 424 EXPECT_TRUE(callback->succeeded); 425 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); 426 EXPECT_EQ(m_value3.bits, result_value.bits); 427 EXPECT_TRUE(CheckBlobInfoMatches(result_value.blob_info)); 428 EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value.blob_info)); 429 } 430 431 { 432 IndexedDBBackingStore::Transaction transaction3(backing_store_); 433 transaction3.Begin(); 434 IndexedDBValue result_value; 435 EXPECT_TRUE(backing_store_->DeleteRange(&transaction3, 436 1, 437 1, 438 IndexedDBKeyRange(m_key3)).ok()); 439 scoped_refptr<TestCallback> callback(new TestCallback()); 440 EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok()); 441 task_runner_->RunUntilIdle(); 442 EXPECT_TRUE(callback->called); 443 EXPECT_TRUE(callback->succeeded); 444 EXPECT_TRUE(transaction3.CommitPhaseTwo().ok()); 445 EXPECT_TRUE(CheckBlobRemovals()); 446 } 447 } 448 449 TEST_F(IndexedDBBackingStoreTest, DeleteRange) { 450 IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0")); 451 IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1")); 452 IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2")); 453 IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3")); 454 IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1); 455 IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1); 456 IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1); 457 IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1); 458 IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key1, key2, false, false), 459 IndexedDBKeyRange(key1, key2, false, false), 460 IndexedDBKeyRange(key0, key2, true, false), 461 IndexedDBKeyRange(key1, key3, false, true), 462 IndexedDBKeyRange(key0, key3, true, true)}; 463 464 for (unsigned i = 0; i < sizeof(ranges) / sizeof(IndexedDBKeyRange); ++i) { 465 backing_store_->ClearWrites(); 466 backing_store_->ClearRemovals(); 467 468 { 469 std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2, 470 blob_info3; 471 blob_info0.push_back(blob0); 472 blob_info1.push_back(blob1); 473 blob_info2.push_back(blob2); 474 blob_info3.push_back(blob3); 475 IndexedDBValue value0 = IndexedDBValue("value0", blob_info0); 476 IndexedDBValue value1 = IndexedDBValue("value1", blob_info1); 477 IndexedDBValue value2 = IndexedDBValue("value2", blob_info2); 478 IndexedDBValue value3 = IndexedDBValue("value3", blob_info3); 479 IndexedDBBackingStore::Transaction transaction1(backing_store_); 480 transaction1.Begin(); 481 ScopedVector<webkit_blob::BlobDataHandle> handles; 482 IndexedDBBackingStore::RecordIdentifier record; 483 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 484 1, 485 i + 1, 486 key0, 487 value0, 488 &handles, 489 &record).ok()); 490 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 491 1, 492 i + 1, 493 key1, 494 value1, 495 &handles, 496 &record).ok()); 497 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 498 1, 499 i + 1, 500 key2, 501 value2, 502 &handles, 503 &record).ok()); 504 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 505 1, 506 i + 1, 507 key3, 508 value3, 509 &handles, 510 &record).ok()); 511 scoped_refptr<TestCallback> callback(new TestCallback()); 512 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); 513 task_runner_->RunUntilIdle(); 514 EXPECT_TRUE(callback->called); 515 EXPECT_TRUE(callback->succeeded); 516 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); 517 } 518 519 { 520 IndexedDBBackingStore::Transaction transaction2(backing_store_); 521 transaction2.Begin(); 522 IndexedDBValue result_value; 523 EXPECT_TRUE( 524 backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok()); 525 scoped_refptr<TestCallback> callback(new TestCallback()); 526 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); 527 task_runner_->RunUntilIdle(); 528 EXPECT_TRUE(callback->called); 529 EXPECT_TRUE(callback->succeeded); 530 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); 531 EXPECT_EQ(2UL, backing_store_->removals().size()); 532 EXPECT_EQ(backing_store_->writes()[1].key(), 533 backing_store_->removals()[0]); 534 EXPECT_EQ(backing_store_->writes()[2].key(), 535 backing_store_->removals()[1]); 536 } 537 } 538 } 539 540 TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) { 541 IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0")); 542 IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1")); 543 IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2")); 544 IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3")); 545 IndexedDBKey key4 = IndexedDBKey(ASCIIToUTF16("key4")); 546 IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1); 547 IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1); 548 IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1); 549 IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1); 550 IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key3, key4, true, false), 551 IndexedDBKeyRange(key2, key1, false, false), 552 IndexedDBKeyRange(key2, key1, true, true)}; 553 554 for (unsigned i = 0; i < arraysize(ranges); ++i) { 555 backing_store_->ClearWrites(); 556 backing_store_->ClearRemovals(); 557 558 { 559 std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2, 560 blob_info3; 561 blob_info0.push_back(blob0); 562 blob_info1.push_back(blob1); 563 blob_info2.push_back(blob2); 564 blob_info3.push_back(blob3); 565 IndexedDBValue value0 = IndexedDBValue("value0", blob_info0); 566 IndexedDBValue value1 = IndexedDBValue("value1", blob_info1); 567 IndexedDBValue value2 = IndexedDBValue("value2", blob_info2); 568 IndexedDBValue value3 = IndexedDBValue("value3", blob_info3); 569 IndexedDBBackingStore::Transaction transaction1(backing_store_); 570 transaction1.Begin(); 571 ScopedVector<webkit_blob::BlobDataHandle> handles; 572 IndexedDBBackingStore::RecordIdentifier record; 573 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 574 1, 575 i + 1, 576 key0, 577 value0, 578 &handles, 579 &record).ok()); 580 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 581 1, 582 i + 1, 583 key1, 584 value1, 585 &handles, 586 &record).ok()); 587 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 588 1, 589 i + 1, 590 key2, 591 value2, 592 &handles, 593 &record).ok()); 594 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 595 1, 596 i + 1, 597 key3, 598 value3, 599 &handles, 600 &record).ok()); 601 scoped_refptr<TestCallback> callback(new TestCallback()); 602 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); 603 task_runner_->RunUntilIdle(); 604 EXPECT_TRUE(callback->called); 605 EXPECT_TRUE(callback->succeeded); 606 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); 607 } 608 609 { 610 IndexedDBBackingStore::Transaction transaction2(backing_store_); 611 transaction2.Begin(); 612 IndexedDBValue result_value; 613 EXPECT_TRUE( 614 backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok()); 615 scoped_refptr<TestCallback> callback(new TestCallback()); 616 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); 617 task_runner_->RunUntilIdle(); 618 EXPECT_TRUE(callback->called); 619 EXPECT_TRUE(callback->succeeded); 620 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); 621 EXPECT_EQ(0UL, backing_store_->removals().size()); 622 } 623 } 624 } 625 626 TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) { 627 { 628 IndexedDBBackingStore::Transaction transaction1(backing_store_); 629 transaction1.Begin(); 630 ScopedVector<webkit_blob::BlobDataHandle> handles; 631 IndexedDBBackingStore::RecordIdentifier record; 632 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 633 1, 634 1, 635 m_key3, 636 m_value3, 637 &handles, 638 &record).ok()); 639 scoped_refptr<TestCallback> callback(new TestCallback()); 640 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok()); 641 task_runner_->RunUntilIdle(); 642 EXPECT_TRUE(CheckBlobWrites()); 643 EXPECT_TRUE(callback->called); 644 EXPECT_TRUE(callback->succeeded); 645 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok()); 646 } 647 648 IndexedDBValue read_result_value; 649 { 650 IndexedDBBackingStore::Transaction transaction2(backing_store_); 651 transaction2.Begin(); 652 EXPECT_TRUE( 653 backing_store_->GetRecord( 654 &transaction2, 1, 1, m_key3, &read_result_value) 655 .ok()); 656 scoped_refptr<TestCallback> callback(new TestCallback()); 657 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok()); 658 EXPECT_TRUE(callback->called); 659 EXPECT_TRUE(callback->succeeded); 660 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok()); 661 EXPECT_EQ(m_value3.bits, read_result_value.bits); 662 EXPECT_TRUE(CheckBlobInfoMatches(read_result_value.blob_info)); 663 EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value.blob_info)); 664 for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) { 665 read_result_value.blob_info[i].mark_used_callback().Run(); 666 } 667 } 668 669 { 670 IndexedDBBackingStore::Transaction transaction3(backing_store_); 671 transaction3.Begin(); 672 EXPECT_TRUE(backing_store_->DeleteRange(&transaction3, 673 1, 674 1, 675 IndexedDBKeyRange(m_key3)).ok()); 676 scoped_refptr<TestCallback> callback(new TestCallback()); 677 EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok()); 678 task_runner_->RunUntilIdle(); 679 EXPECT_TRUE(callback->called); 680 EXPECT_TRUE(callback->succeeded); 681 EXPECT_TRUE(transaction3.CommitPhaseTwo().ok()); 682 EXPECT_EQ(0U, backing_store_->removals().size()); 683 for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) { 684 read_result_value.blob_info[i].release_callback().Run( 685 read_result_value.blob_info[i].file_path()); 686 } 687 task_runner_->RunUntilIdle(); 688 EXPECT_NE(0U, backing_store_->removals().size()); 689 EXPECT_TRUE(CheckBlobRemovals()); 690 } 691 } 692 693 // Make sure that using very high ( more than 32 bit ) values for database_id 694 // and object_store_id still work. 695 TEST_F(IndexedDBBackingStoreTest, HighIds) { 696 const int64 high_database_id = 1ULL << 35; 697 const int64 high_object_store_id = 1ULL << 39; 698 // index_ids are capped at 32 bits for storage purposes. 699 const int64 high_index_id = 1ULL << 29; 700 701 const int64 invalid_high_index_id = 1ULL << 37; 702 703 const IndexedDBKey& index_key = m_key2; 704 std::string index_key_raw; 705 EncodeIDBKey(index_key, &index_key_raw); 706 { 707 IndexedDBBackingStore::Transaction transaction1(backing_store_); 708 transaction1.Begin(); 709 ScopedVector<webkit_blob::BlobDataHandle> handles; 710 IndexedDBBackingStore::RecordIdentifier record; 711 leveldb::Status s = backing_store_->PutRecord(&transaction1, 712 high_database_id, 713 high_object_store_id, 714 m_key1, 715 m_value1, 716 &handles, 717 &record); 718 EXPECT_TRUE(s.ok()); 719 720 s = backing_store_->PutIndexDataForRecord(&transaction1, 721 high_database_id, 722 high_object_store_id, 723 invalid_high_index_id, 724 index_key, 725 record); 726 EXPECT_FALSE(s.ok()); 727 728 s = backing_store_->PutIndexDataForRecord(&transaction1, 729 high_database_id, 730 high_object_store_id, 731 high_index_id, 732 index_key, 733 record); 734 EXPECT_TRUE(s.ok()); 735 736 scoped_refptr<TestCallback> callback(new TestCallback()); 737 s = transaction1.CommitPhaseOne(callback); 738 EXPECT_TRUE(s.ok()); 739 EXPECT_TRUE(callback->called); 740 EXPECT_TRUE(callback->succeeded); 741 s = transaction1.CommitPhaseTwo(); 742 EXPECT_TRUE(s.ok()); 743 } 744 745 { 746 IndexedDBBackingStore::Transaction transaction2(backing_store_); 747 transaction2.Begin(); 748 IndexedDBValue result_value; 749 leveldb::Status s = backing_store_->GetRecord(&transaction2, 750 high_database_id, 751 high_object_store_id, 752 m_key1, 753 &result_value); 754 EXPECT_TRUE(s.ok()); 755 EXPECT_EQ(m_value1.bits, result_value.bits); 756 757 scoped_ptr<IndexedDBKey> new_primary_key; 758 s = backing_store_->GetPrimaryKeyViaIndex(&transaction2, 759 high_database_id, 760 high_object_store_id, 761 invalid_high_index_id, 762 index_key, 763 &new_primary_key); 764 EXPECT_FALSE(s.ok()); 765 766 s = backing_store_->GetPrimaryKeyViaIndex(&transaction2, 767 high_database_id, 768 high_object_store_id, 769 high_index_id, 770 index_key, 771 &new_primary_key); 772 EXPECT_TRUE(s.ok()); 773 EXPECT_TRUE(new_primary_key->Equals(m_key1)); 774 775 scoped_refptr<TestCallback> callback(new TestCallback()); 776 s = transaction2.CommitPhaseOne(callback); 777 EXPECT_TRUE(s.ok()); 778 EXPECT_TRUE(callback->called); 779 EXPECT_TRUE(callback->succeeded); 780 s = transaction2.CommitPhaseTwo(); 781 EXPECT_TRUE(s.ok()); 782 } 783 } 784 785 // Make sure that other invalid ids do not crash. 786 TEST_F(IndexedDBBackingStoreTest, InvalidIds) { 787 // valid ids for use when testing invalid ids 788 const int64 database_id = 1; 789 const int64 object_store_id = 1; 790 const int64 index_id = kMinimumIndexId; 791 const int64 invalid_low_index_id = 19; // index_ids must be > kMinimumIndexId 792 793 IndexedDBValue result_value; 794 795 IndexedDBBackingStore::Transaction transaction1(backing_store_); 796 transaction1.Begin(); 797 798 ScopedVector<webkit_blob::BlobDataHandle> handles; 799 IndexedDBBackingStore::RecordIdentifier record; 800 leveldb::Status s = backing_store_->PutRecord(&transaction1, 801 database_id, 802 KeyPrefix::kInvalidId, 803 m_key1, 804 m_value1, 805 &handles, 806 &record); 807 EXPECT_FALSE(s.ok()); 808 s = backing_store_->PutRecord( 809 &transaction1, database_id, 0, m_key1, m_value1, &handles, &record); 810 EXPECT_FALSE(s.ok()); 811 s = backing_store_->PutRecord(&transaction1, 812 KeyPrefix::kInvalidId, 813 object_store_id, 814 m_key1, 815 m_value1, 816 &handles, 817 &record); 818 EXPECT_FALSE(s.ok()); 819 s = backing_store_->PutRecord( 820 &transaction1, 0, object_store_id, m_key1, m_value1, &handles, &record); 821 EXPECT_FALSE(s.ok()); 822 823 s = backing_store_->GetRecord( 824 &transaction1, database_id, KeyPrefix::kInvalidId, m_key1, &result_value); 825 EXPECT_FALSE(s.ok()); 826 s = backing_store_->GetRecord( 827 &transaction1, database_id, 0, m_key1, &result_value); 828 EXPECT_FALSE(s.ok()); 829 s = backing_store_->GetRecord(&transaction1, 830 KeyPrefix::kInvalidId, 831 object_store_id, 832 m_key1, 833 &result_value); 834 EXPECT_FALSE(s.ok()); 835 s = backing_store_->GetRecord( 836 &transaction1, 0, object_store_id, m_key1, &result_value); 837 EXPECT_FALSE(s.ok()); 838 839 scoped_ptr<IndexedDBKey> new_primary_key; 840 s = backing_store_->GetPrimaryKeyViaIndex(&transaction1, 841 database_id, 842 object_store_id, 843 KeyPrefix::kInvalidId, 844 m_key1, 845 &new_primary_key); 846 EXPECT_FALSE(s.ok()); 847 s = backing_store_->GetPrimaryKeyViaIndex(&transaction1, 848 database_id, 849 object_store_id, 850 invalid_low_index_id, 851 m_key1, 852 &new_primary_key); 853 EXPECT_FALSE(s.ok()); 854 s = backing_store_->GetPrimaryKeyViaIndex( 855 &transaction1, database_id, object_store_id, 0, m_key1, &new_primary_key); 856 EXPECT_FALSE(s.ok()); 857 858 s = backing_store_->GetPrimaryKeyViaIndex(&transaction1, 859 KeyPrefix::kInvalidId, 860 object_store_id, 861 index_id, 862 m_key1, 863 &new_primary_key); 864 EXPECT_FALSE(s.ok()); 865 s = backing_store_->GetPrimaryKeyViaIndex(&transaction1, 866 database_id, 867 KeyPrefix::kInvalidId, 868 index_id, 869 m_key1, 870 &new_primary_key); 871 EXPECT_FALSE(s.ok()); 872 } 873 874 TEST_F(IndexedDBBackingStoreTest, CreateDatabase) { 875 const base::string16 database_name(ASCIIToUTF16("db1")); 876 int64 database_id; 877 const base::string16 version(ASCIIToUTF16("old_string_version")); 878 const int64 int_version = 9; 879 880 const int64 object_store_id = 99; 881 const base::string16 object_store_name(ASCIIToUTF16("object_store1")); 882 const bool auto_increment = true; 883 const IndexedDBKeyPath object_store_key_path( 884 ASCIIToUTF16("object_store_key")); 885 886 const int64 index_id = 999; 887 const base::string16 index_name(ASCIIToUTF16("index1")); 888 const bool unique = true; 889 const bool multi_entry = true; 890 const IndexedDBKeyPath index_key_path(ASCIIToUTF16("index_key")); 891 892 { 893 leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData( 894 database_name, version, int_version, &database_id); 895 EXPECT_TRUE(s.ok()); 896 EXPECT_GT(database_id, 0); 897 898 IndexedDBBackingStore::Transaction transaction(backing_store_); 899 transaction.Begin(); 900 901 s = backing_store_->CreateObjectStore(&transaction, 902 database_id, 903 object_store_id, 904 object_store_name, 905 object_store_key_path, 906 auto_increment); 907 EXPECT_TRUE(s.ok()); 908 909 s = backing_store_->CreateIndex(&transaction, 910 database_id, 911 object_store_id, 912 index_id, 913 index_name, 914 index_key_path, 915 unique, 916 multi_entry); 917 EXPECT_TRUE(s.ok()); 918 919 scoped_refptr<TestCallback> callback(new TestCallback()); 920 s = transaction.CommitPhaseOne(callback); 921 EXPECT_TRUE(s.ok()); 922 EXPECT_TRUE(callback->called); 923 EXPECT_TRUE(callback->succeeded); 924 s = transaction.CommitPhaseTwo(); 925 EXPECT_TRUE(s.ok()); 926 } 927 928 { 929 IndexedDBDatabaseMetadata database; 930 bool found; 931 leveldb::Status s = backing_store_->GetIDBDatabaseMetaData( 932 database_name, &database, &found); 933 EXPECT_TRUE(s.ok()); 934 EXPECT_TRUE(found); 935 936 // database.name is not filled in by the implementation. 937 EXPECT_EQ(version, database.version); 938 EXPECT_EQ(int_version, database.int_version); 939 EXPECT_EQ(database_id, database.id); 940 941 s = backing_store_->GetObjectStores(database.id, &database.object_stores); 942 EXPECT_TRUE(s.ok()); 943 944 EXPECT_EQ(1UL, database.object_stores.size()); 945 IndexedDBObjectStoreMetadata object_store = 946 database.object_stores[object_store_id]; 947 EXPECT_EQ(object_store_name, object_store.name); 948 EXPECT_EQ(object_store_key_path, object_store.key_path); 949 EXPECT_EQ(auto_increment, object_store.auto_increment); 950 951 EXPECT_EQ(1UL, object_store.indexes.size()); 952 IndexedDBIndexMetadata index = object_store.indexes[index_id]; 953 EXPECT_EQ(index_name, index.name); 954 EXPECT_EQ(index_key_path, index.key_path); 955 EXPECT_EQ(unique, index.unique); 956 EXPECT_EQ(multi_entry, index.multi_entry); 957 } 958 } 959 960 } // namespace 961 962 } // namespace content 963