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