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.
5 #include "content/browser/indexed_db/indexed_db_backing_store.h"
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/modules/indexeddb/WebIDBTypes.h"
29 using base::ASCIIToUTF16
;
35 class Comparator
: public LevelDBComparator
{
37 int Compare(const base::StringPiece
& a
,
38 const base::StringPiece
& b
) const override
{
39 return content::Compare(a
, b
, false /*index_keys*/);
41 const char* Name() const override
{ return "idb_cmp1"; }
44 class DefaultLevelDBFactory
: public LevelDBFactory
{
46 DefaultLevelDBFactory() {}
47 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
);
53 leveldb::Status
DestroyLevelDB(const base::FilePath
& file_name
) override
{
54 return LevelDBDatabase::Destroy(file_name
);
58 DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory
);
61 class TestableIndexedDBBackingStore
: public IndexedDBBackingStore
{
63 static scoped_refptr
<TestableIndexedDBBackingStore
> Open(
64 IndexedDBFactory
* indexed_db_factory
,
65 const GURL
& origin_url
,
66 const base::FilePath
& path_base
,
67 net::URLRequestContext
* request_context
,
68 LevelDBFactory
* leveldb_factory
,
69 base::SequencedTaskRunner
* task_runner
,
70 leveldb::Status
* status
) {
71 DCHECK(!path_base
.empty());
73 scoped_ptr
<LevelDBComparator
> comparator(new Comparator());
75 if (!base::CreateDirectory(path_base
)) {
76 *status
= leveldb::Status::IOError("Unable to create base dir");
77 return scoped_refptr
<TestableIndexedDBBackingStore
>();
80 const base::FilePath file_path
= path_base
.AppendASCII("test_db_path");
81 const base::FilePath blob_path
= path_base
.AppendASCII("test_blob_path");
83 scoped_ptr
<LevelDBDatabase
> db
;
84 bool is_disk_full
= false;
85 *status
= leveldb_factory
->OpenLevelDB(
86 file_path
, comparator
.get(), &db
, &is_disk_full
);
88 if (!db
|| !status
->ok())
89 return scoped_refptr
<TestableIndexedDBBackingStore
>();
91 scoped_refptr
<TestableIndexedDBBackingStore
> backing_store(
92 new TestableIndexedDBBackingStore(indexed_db_factory
,
100 *status
= backing_store
->SetUpMetadata();
102 return scoped_refptr
<TestableIndexedDBBackingStore
>();
104 return backing_store
;
107 const std::vector
<IndexedDBBackingStore::Transaction::WriteDescriptor
>&
111 void ClearWrites() { writes_
.clear(); }
112 const std::vector
<int64
>& removals() const { return removals_
; }
113 void ClearRemovals() { removals_
.clear(); }
116 ~TestableIndexedDBBackingStore() override
{}
120 const Transaction::WriteDescriptor
& descriptor
,
121 Transaction::ChainedBlobWriter
* chained_blob_writer
) override
{
122 if (KeyPrefix::IsValidDatabaseId(database_id_
)) {
123 if (database_id_
!= database_id
) {
127 database_id_
= database_id
;
129 writes_
.push_back(descriptor
);
130 task_runner()->PostTask(
132 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion
,
139 bool RemoveBlobFile(int64 database_id
, int64 key
) const override
{
140 if (database_id_
!= database_id
||
141 !KeyPrefix::IsValidDatabaseId(database_id
)) {
144 removals_
.push_back(key
);
148 // Timers don't play nicely with unit tests.
149 void StartJournalCleaningTimer() override
{
150 CleanPrimaryJournalIgnoreReturn();
154 TestableIndexedDBBackingStore(IndexedDBFactory
* indexed_db_factory
,
155 const GURL
& origin_url
,
156 const base::FilePath
& blob_path
,
157 net::URLRequestContext
* request_context
,
158 scoped_ptr
<LevelDBDatabase
> db
,
159 scoped_ptr
<LevelDBComparator
> comparator
,
160 base::SequencedTaskRunner
* task_runner
)
161 : IndexedDBBackingStore(indexed_db_factory
,
171 std::vector
<Transaction::WriteDescriptor
> writes_
;
173 // This is modified in an overridden virtual function that is properly const
174 // in the real implementation, therefore must be mutable here.
175 mutable std::vector
<int64
> removals_
;
177 DISALLOW_COPY_AND_ASSIGN(TestableIndexedDBBackingStore
);
180 class TestIDBFactory
: public IndexedDBFactoryImpl
{
182 explicit TestIDBFactory(IndexedDBContextImpl
* idb_context
)
183 : IndexedDBFactoryImpl(idb_context
) {}
185 scoped_refptr
<TestableIndexedDBBackingStore
> OpenBackingStoreForTest(
187 net::URLRequestContext
* url_request_context
) {
188 blink::WebIDBDataLoss data_loss
;
189 std::string data_loss_reason
;
191 leveldb::Status status
;
192 scoped_refptr
<IndexedDBBackingStore
> backing_store
=
193 OpenBackingStore(origin
,
194 context()->data_path(),
200 scoped_refptr
<TestableIndexedDBBackingStore
> testable_store
=
201 static_cast<TestableIndexedDBBackingStore
*>(backing_store
.get());
202 return testable_store
;
206 ~TestIDBFactory() override
{}
208 scoped_refptr
<IndexedDBBackingStore
> OpenBackingStoreHelper(
209 const GURL
& origin_url
,
210 const base::FilePath
& data_directory
,
211 net::URLRequestContext
* request_context
,
212 blink::WebIDBDataLoss
* data_loss
,
213 std::string
* data_loss_message
,
216 leveldb::Status
* status
) override
{
217 DefaultLevelDBFactory leveldb_factory
;
218 return TestableIndexedDBBackingStore::Open(this,
223 context()->TaskRunner(),
228 DISALLOW_COPY_AND_ASSIGN(TestIDBFactory
);
231 class IndexedDBBackingStoreTest
: public testing::Test
{
233 IndexedDBBackingStoreTest() {}
234 void SetUp() override
{
235 const GURL
origin("http://localhost:81");
236 task_runner_
= new base::TestSimpleTaskRunner();
237 special_storage_policy_
= new MockSpecialStoragePolicy();
238 special_storage_policy_
->SetAllUnlimited(true);
239 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
240 idb_context_
= new IndexedDBContextImpl(temp_dir_
.path(),
241 special_storage_policy_
.get(),
244 idb_factory_
= new TestIDBFactory(idb_context_
.get());
246 idb_factory_
->OpenBackingStoreForTest(origin
, &url_request_context_
);
248 // useful keys and values during tests
249 m_value1
= IndexedDBValue("value1", std::vector
<IndexedDBBlobInfo
>());
250 m_value2
= IndexedDBValue("value2", std::vector
<IndexedDBBlobInfo
>());
252 m_blob_info
.push_back(
253 IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1));
254 m_blob_info
.push_back(
255 IndexedDBBlobInfo("uuid 4",
256 base::FilePath(FILE_PATH_LITERAL("path/to/file")),
257 base::UTF8ToUTF16("file name"),
258 base::UTF8ToUTF16("file type")));
259 m_blob_info
.push_back(
260 IndexedDBBlobInfo("uuid 5",
262 base::UTF8ToUTF16("file name"),
263 base::UTF8ToUTF16("file type")));
264 m_value3
= IndexedDBValue("value3", m_blob_info
);
266 m_key1
= IndexedDBKey(99, blink::WebIDBKeyTypeNumber
);
267 m_key2
= IndexedDBKey(ASCIIToUTF16("key2"));
268 m_key3
= IndexedDBKey(ASCIIToUTF16("key3"));
271 // This just checks the data that survive getting stored and recalled, e.g.
272 // the file path and UUID will change and thus aren't verified.
273 bool CheckBlobInfoMatches(const std::vector
<IndexedDBBlobInfo
>& reads
) const {
274 if (m_blob_info
.size() != reads
.size())
276 for (size_t i
= 0; i
< m_blob_info
.size(); ++i
) {
277 const IndexedDBBlobInfo
& a
= m_blob_info
[i
];
278 const IndexedDBBlobInfo
& b
= reads
[i
];
279 if (a
.is_file() != b
.is_file())
281 if (a
.type() != b
.type())
284 if (a
.file_name() != b
.file_name())
287 if (a
.size() != b
.size())
294 bool CheckBlobReadsMatchWrites(
295 const std::vector
<IndexedDBBlobInfo
>& reads
) const {
296 if (backing_store_
->writes().size() != reads
.size())
299 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
)
300 ids
.insert(backing_store_
->writes()[i
].key());
301 if (ids
.size() != backing_store_
->writes().size())
303 for (size_t i
= 0; i
< reads
.size(); ++i
) {
304 if (ids
.count(reads
[i
].key()) != 1)
310 bool CheckBlobWrites() const {
311 if (backing_store_
->writes().size() != m_blob_info
.size())
313 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
) {
314 const IndexedDBBackingStore::Transaction::WriteDescriptor
& desc
=
315 backing_store_
->writes()[i
];
316 const IndexedDBBlobInfo
& info
= m_blob_info
[i
];
317 if (desc
.is_file() != info
.is_file()) {
318 if (!info
.is_file() || !info
.file_path().empty())
320 } else if (desc
.is_file()) {
321 if (desc
.file_path() != info
.file_path())
324 if (desc
.url() != GURL("blob:uuid/" + info
.uuid()))
331 bool CheckBlobRemovals() const {
332 if (backing_store_
->removals().size() != backing_store_
->writes().size())
334 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
) {
335 if (backing_store_
->writes()[i
].key() != backing_store_
->removals()[i
])
342 // Must be initialized before url_request_context_
343 content::TestBrowserThreadBundle thread_bundle_
;
345 base::ScopedTempDir temp_dir_
;
346 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner_
;
347 scoped_refptr
<MockSpecialStoragePolicy
> special_storage_policy_
;
348 scoped_refptr
<IndexedDBContextImpl
> idb_context_
;
349 scoped_refptr
<TestIDBFactory
> idb_factory_
;
350 net::TestURLRequestContext url_request_context_
;
352 scoped_refptr
<TestableIndexedDBBackingStore
> backing_store_
;
354 // Sample keys and values that are consistent.
358 IndexedDBValue m_value1
;
359 IndexedDBValue m_value2
;
360 IndexedDBValue m_value3
;
361 std::vector
<IndexedDBBlobInfo
> m_blob_info
;
364 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest
);
367 class TestCallback
: public IndexedDBBackingStore::BlobWriteCallback
{
369 TestCallback() : called(false), succeeded(false) {}
370 void Run(bool succeeded_in
) override
{
372 succeeded
= succeeded_in
;
378 ~TestCallback() override
{}
381 DISALLOW_COPY_AND_ASSIGN(TestCallback
);
384 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistency
) {
386 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
387 transaction1
.Begin();
388 ScopedVector
<storage::BlobDataHandle
> handles
;
389 IndexedDBBackingStore::RecordIdentifier record
;
390 leveldb::Status s
= backing_store_
->PutRecord(
391 &transaction1
, 1, 1, m_key1
, &m_value1
, &handles
, &record
);
393 scoped_refptr
<TestCallback
> callback(new TestCallback());
394 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
395 EXPECT_TRUE(callback
->called
);
396 EXPECT_TRUE(callback
->succeeded
);
397 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
401 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
402 transaction2
.Begin();
403 IndexedDBValue result_value
;
405 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key1
, &result_value
)
407 scoped_refptr
<TestCallback
> callback(new TestCallback());
408 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
409 EXPECT_TRUE(callback
->called
);
410 EXPECT_TRUE(callback
->succeeded
);
411 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
412 EXPECT_EQ(m_value1
.bits
, result_value
.bits
);
416 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistencyWithBlobs
) {
418 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
419 transaction1
.Begin();
420 ScopedVector
<storage::BlobDataHandle
> handles
;
421 IndexedDBBackingStore::RecordIdentifier record
;
422 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
429 scoped_refptr
<TestCallback
> callback(new TestCallback());
430 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
431 task_runner_
->RunUntilIdle();
432 EXPECT_TRUE(CheckBlobWrites());
433 EXPECT_TRUE(callback
->called
);
434 EXPECT_TRUE(callback
->succeeded
);
435 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
439 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
440 transaction2
.Begin();
441 IndexedDBValue result_value
;
443 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key3
, &result_value
)
445 scoped_refptr
<TestCallback
> callback(new TestCallback());
446 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
447 EXPECT_TRUE(callback
->called
);
448 EXPECT_TRUE(callback
->succeeded
);
449 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
450 EXPECT_EQ(m_value3
.bits
, result_value
.bits
);
451 EXPECT_TRUE(CheckBlobInfoMatches(result_value
.blob_info
));
452 EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value
.blob_info
));
456 IndexedDBBackingStore::Transaction
transaction3(backing_store_
.get());
457 transaction3
.Begin();
458 IndexedDBValue result_value
;
459 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
462 IndexedDBKeyRange(m_key3
)).ok());
463 scoped_refptr
<TestCallback
> callback(new TestCallback());
464 EXPECT_TRUE(transaction3
.CommitPhaseOne(callback
).ok());
465 task_runner_
->RunUntilIdle();
466 EXPECT_TRUE(callback
->called
);
467 EXPECT_TRUE(callback
->succeeded
);
468 EXPECT_TRUE(transaction3
.CommitPhaseTwo().ok());
469 EXPECT_TRUE(CheckBlobRemovals());
473 TEST_F(IndexedDBBackingStoreTest
, DeleteRange
) {
474 IndexedDBKey key0
= IndexedDBKey(ASCIIToUTF16("key0"));
475 IndexedDBKey key1
= IndexedDBKey(ASCIIToUTF16("key1"));
476 IndexedDBKey key2
= IndexedDBKey(ASCIIToUTF16("key2"));
477 IndexedDBKey key3
= IndexedDBKey(ASCIIToUTF16("key3"));
478 IndexedDBBlobInfo
blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
479 IndexedDBBlobInfo
blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
480 IndexedDBBlobInfo
blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
481 IndexedDBBlobInfo
blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
482 IndexedDBKeyRange ranges
[] = {IndexedDBKeyRange(key1
, key2
, false, false),
483 IndexedDBKeyRange(key1
, key2
, false, false),
484 IndexedDBKeyRange(key0
, key2
, true, false),
485 IndexedDBKeyRange(key1
, key3
, false, true),
486 IndexedDBKeyRange(key0
, key3
, true, true)};
488 for (unsigned i
= 0; i
< sizeof(ranges
) / sizeof(IndexedDBKeyRange
); ++i
) {
489 backing_store_
->ClearWrites();
490 backing_store_
->ClearRemovals();
493 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
495 blob_info0
.push_back(blob0
);
496 blob_info1
.push_back(blob1
);
497 blob_info2
.push_back(blob2
);
498 blob_info3
.push_back(blob3
);
499 IndexedDBValue value0
= IndexedDBValue("value0", blob_info0
);
500 IndexedDBValue value1
= IndexedDBValue("value1", blob_info1
);
501 IndexedDBValue value2
= IndexedDBValue("value2", blob_info2
);
502 IndexedDBValue value3
= IndexedDBValue("value3", blob_info3
);
503 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
504 transaction1
.Begin();
505 ScopedVector
<storage::BlobDataHandle
> handles
;
506 IndexedDBBackingStore::RecordIdentifier record
;
507 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
514 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
521 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
528 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
535 scoped_refptr
<TestCallback
> callback(new TestCallback());
536 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
537 task_runner_
->RunUntilIdle();
538 EXPECT_TRUE(callback
->called
);
539 EXPECT_TRUE(callback
->succeeded
);
540 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
544 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
545 transaction2
.Begin();
546 IndexedDBValue result_value
;
548 backing_store_
->DeleteRange(&transaction2
, 1, i
+ 1, ranges
[i
]).ok());
549 scoped_refptr
<TestCallback
> callback(new TestCallback());
550 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
551 task_runner_
->RunUntilIdle();
552 EXPECT_TRUE(callback
->called
);
553 EXPECT_TRUE(callback
->succeeded
);
554 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
555 EXPECT_EQ(2UL, backing_store_
->removals().size());
556 EXPECT_EQ(backing_store_
->writes()[1].key(),
557 backing_store_
->removals()[0]);
558 EXPECT_EQ(backing_store_
->writes()[2].key(),
559 backing_store_
->removals()[1]);
564 TEST_F(IndexedDBBackingStoreTest
, DeleteRangeEmptyRange
) {
565 IndexedDBKey key0
= IndexedDBKey(ASCIIToUTF16("key0"));
566 IndexedDBKey key1
= IndexedDBKey(ASCIIToUTF16("key1"));
567 IndexedDBKey key2
= IndexedDBKey(ASCIIToUTF16("key2"));
568 IndexedDBKey key3
= IndexedDBKey(ASCIIToUTF16("key3"));
569 IndexedDBKey key4
= IndexedDBKey(ASCIIToUTF16("key4"));
570 IndexedDBBlobInfo
blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
571 IndexedDBBlobInfo
blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
572 IndexedDBBlobInfo
blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
573 IndexedDBBlobInfo
blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
574 IndexedDBKeyRange ranges
[] = {IndexedDBKeyRange(key3
, key4
, true, false),
575 IndexedDBKeyRange(key2
, key1
, false, false),
576 IndexedDBKeyRange(key2
, key1
, true, true)};
578 for (unsigned i
= 0; i
< arraysize(ranges
); ++i
) {
579 backing_store_
->ClearWrites();
580 backing_store_
->ClearRemovals();
583 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
585 blob_info0
.push_back(blob0
);
586 blob_info1
.push_back(blob1
);
587 blob_info2
.push_back(blob2
);
588 blob_info3
.push_back(blob3
);
589 IndexedDBValue value0
= IndexedDBValue("value0", blob_info0
);
590 IndexedDBValue value1
= IndexedDBValue("value1", blob_info1
);
591 IndexedDBValue value2
= IndexedDBValue("value2", blob_info2
);
592 IndexedDBValue value3
= IndexedDBValue("value3", blob_info3
);
593 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
594 transaction1
.Begin();
595 ScopedVector
<storage::BlobDataHandle
> handles
;
596 IndexedDBBackingStore::RecordIdentifier record
;
597 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
604 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
611 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
618 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
625 scoped_refptr
<TestCallback
> callback(new TestCallback());
626 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
627 task_runner_
->RunUntilIdle();
628 EXPECT_TRUE(callback
->called
);
629 EXPECT_TRUE(callback
->succeeded
);
630 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
634 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
635 transaction2
.Begin();
636 IndexedDBValue result_value
;
638 backing_store_
->DeleteRange(&transaction2
, 1, i
+ 1, ranges
[i
]).ok());
639 scoped_refptr
<TestCallback
> callback(new TestCallback());
640 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
641 task_runner_
->RunUntilIdle();
642 EXPECT_TRUE(callback
->called
);
643 EXPECT_TRUE(callback
->succeeded
);
644 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
645 EXPECT_EQ(0UL, backing_store_
->removals().size());
650 TEST_F(IndexedDBBackingStoreTest
, BlobJournalInterleavedTransactions
) {
651 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
652 transaction1
.Begin();
653 ScopedVector
<storage::BlobDataHandle
> handles1
;
654 IndexedDBBackingStore::RecordIdentifier record1
;
655 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
, 1, 1, m_key3
, &m_value3
,
656 &handles1
, &record1
).ok());
657 scoped_refptr
<TestCallback
> callback1(new TestCallback());
658 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback1
).ok());
659 task_runner_
->RunUntilIdle();
660 EXPECT_TRUE(CheckBlobWrites());
661 EXPECT_TRUE(callback1
->called
);
662 EXPECT_TRUE(callback1
->succeeded
);
663 EXPECT_EQ(0U, backing_store_
->removals().size());
665 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
666 transaction2
.Begin();
667 ScopedVector
<storage::BlobDataHandle
> handles2
;
668 IndexedDBBackingStore::RecordIdentifier record2
;
669 EXPECT_TRUE(backing_store_
->PutRecord(&transaction2
, 1, 1, m_key1
, &m_value1
,
670 &handles2
, &record2
).ok());
671 scoped_refptr
<TestCallback
> callback2(new TestCallback());
672 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback2
).ok());
673 task_runner_
->RunUntilIdle();
674 EXPECT_TRUE(CheckBlobWrites());
675 EXPECT_TRUE(callback2
->called
);
676 EXPECT_TRUE(callback2
->succeeded
);
677 EXPECT_EQ(0U, backing_store_
->removals().size());
679 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
680 EXPECT_EQ(0U, backing_store_
->removals().size());
682 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
683 EXPECT_EQ(0U, backing_store_
->removals().size());
686 TEST_F(IndexedDBBackingStoreTest
, LiveBlobJournal
) {
688 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
689 transaction1
.Begin();
690 ScopedVector
<storage::BlobDataHandle
> handles
;
691 IndexedDBBackingStore::RecordIdentifier record
;
692 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
699 scoped_refptr
<TestCallback
> callback(new TestCallback());
700 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
701 task_runner_
->RunUntilIdle();
702 EXPECT_TRUE(CheckBlobWrites());
703 EXPECT_TRUE(callback
->called
);
704 EXPECT_TRUE(callback
->succeeded
);
705 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
708 IndexedDBValue read_result_value
;
710 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
711 transaction2
.Begin();
713 backing_store_
->GetRecord(
714 &transaction2
, 1, 1, m_key3
, &read_result_value
)
716 scoped_refptr
<TestCallback
> callback(new TestCallback());
717 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
718 EXPECT_TRUE(callback
->called
);
719 EXPECT_TRUE(callback
->succeeded
);
720 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
721 EXPECT_EQ(m_value3
.bits
, read_result_value
.bits
);
722 EXPECT_TRUE(CheckBlobInfoMatches(read_result_value
.blob_info
));
723 EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value
.blob_info
));
724 for (size_t i
= 0; i
< read_result_value
.blob_info
.size(); ++i
) {
725 read_result_value
.blob_info
[i
].mark_used_callback().Run();
730 IndexedDBBackingStore::Transaction
transaction3(backing_store_
.get());
731 transaction3
.Begin();
732 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
735 IndexedDBKeyRange(m_key3
)).ok());
736 scoped_refptr
<TestCallback
> callback(new TestCallback());
737 EXPECT_TRUE(transaction3
.CommitPhaseOne(callback
).ok());
738 task_runner_
->RunUntilIdle();
739 EXPECT_TRUE(callback
->called
);
740 EXPECT_TRUE(callback
->succeeded
);
741 EXPECT_TRUE(transaction3
.CommitPhaseTwo().ok());
742 EXPECT_EQ(0U, backing_store_
->removals().size());
743 for (size_t i
= 0; i
< read_result_value
.blob_info
.size(); ++i
) {
744 read_result_value
.blob_info
[i
].release_callback().Run(
745 read_result_value
.blob_info
[i
].file_path());
747 task_runner_
->RunUntilIdle();
748 EXPECT_NE(0U, backing_store_
->removals().size());
749 EXPECT_TRUE(CheckBlobRemovals());
753 // Make sure that using very high ( more than 32 bit ) values for database_id
754 // and object_store_id still work.
755 TEST_F(IndexedDBBackingStoreTest
, HighIds
) {
756 const int64 high_database_id
= 1ULL << 35;
757 const int64 high_object_store_id
= 1ULL << 39;
758 // index_ids are capped at 32 bits for storage purposes.
759 const int64 high_index_id
= 1ULL << 29;
761 const int64 invalid_high_index_id
= 1ULL << 37;
763 const IndexedDBKey
& index_key
= m_key2
;
764 std::string index_key_raw
;
765 EncodeIDBKey(index_key
, &index_key_raw
);
767 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
768 transaction1
.Begin();
769 ScopedVector
<storage::BlobDataHandle
> handles
;
770 IndexedDBBackingStore::RecordIdentifier record
;
771 leveldb::Status s
= backing_store_
->PutRecord(&transaction1
,
773 high_object_store_id
,
780 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
782 high_object_store_id
,
783 invalid_high_index_id
,
786 EXPECT_FALSE(s
.ok());
788 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
790 high_object_store_id
,
796 scoped_refptr
<TestCallback
> callback(new TestCallback());
797 s
= transaction1
.CommitPhaseOne(callback
);
799 EXPECT_TRUE(callback
->called
);
800 EXPECT_TRUE(callback
->succeeded
);
801 s
= transaction1
.CommitPhaseTwo();
806 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
807 transaction2
.Begin();
808 IndexedDBValue result_value
;
809 leveldb::Status s
= backing_store_
->GetRecord(&transaction2
,
811 high_object_store_id
,
815 EXPECT_EQ(m_value1
.bits
, result_value
.bits
);
817 scoped_ptr
<IndexedDBKey
> new_primary_key
;
818 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
820 high_object_store_id
,
821 invalid_high_index_id
,
824 EXPECT_FALSE(s
.ok());
826 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
828 high_object_store_id
,
833 EXPECT_TRUE(new_primary_key
->Equals(m_key1
));
835 scoped_refptr
<TestCallback
> callback(new TestCallback());
836 s
= transaction2
.CommitPhaseOne(callback
);
838 EXPECT_TRUE(callback
->called
);
839 EXPECT_TRUE(callback
->succeeded
);
840 s
= transaction2
.CommitPhaseTwo();
845 // Make sure that other invalid ids do not crash.
846 TEST_F(IndexedDBBackingStoreTest
, InvalidIds
) {
847 // valid ids for use when testing invalid ids
848 const int64 database_id
= 1;
849 const int64 object_store_id
= 1;
850 const int64 index_id
= kMinimumIndexId
;
851 const int64 invalid_low_index_id
= 19; // index_ids must be > kMinimumIndexId
853 IndexedDBValue result_value
;
855 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
856 transaction1
.Begin();
858 ScopedVector
<storage::BlobDataHandle
> handles
;
859 IndexedDBBackingStore::RecordIdentifier record
;
860 leveldb::Status s
= backing_store_
->PutRecord(&transaction1
,
862 KeyPrefix::kInvalidId
,
867 EXPECT_FALSE(s
.ok());
868 s
= backing_store_
->PutRecord(
869 &transaction1
, database_id
, 0, m_key1
, &m_value1
, &handles
, &record
);
870 EXPECT_FALSE(s
.ok());
871 s
= backing_store_
->PutRecord(&transaction1
,
872 KeyPrefix::kInvalidId
,
878 EXPECT_FALSE(s
.ok());
879 s
= backing_store_
->PutRecord(
880 &transaction1
, 0, object_store_id
, m_key1
, &m_value1
, &handles
, &record
);
881 EXPECT_FALSE(s
.ok());
883 s
= backing_store_
->GetRecord(
884 &transaction1
, database_id
, KeyPrefix::kInvalidId
, m_key1
, &result_value
);
885 EXPECT_FALSE(s
.ok());
886 s
= backing_store_
->GetRecord(
887 &transaction1
, database_id
, 0, m_key1
, &result_value
);
888 EXPECT_FALSE(s
.ok());
889 s
= backing_store_
->GetRecord(&transaction1
,
890 KeyPrefix::kInvalidId
,
894 EXPECT_FALSE(s
.ok());
895 s
= backing_store_
->GetRecord(
896 &transaction1
, 0, object_store_id
, m_key1
, &result_value
);
897 EXPECT_FALSE(s
.ok());
899 scoped_ptr
<IndexedDBKey
> new_primary_key
;
900 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
903 KeyPrefix::kInvalidId
,
906 EXPECT_FALSE(s
.ok());
907 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
910 invalid_low_index_id
,
913 EXPECT_FALSE(s
.ok());
914 s
= backing_store_
->GetPrimaryKeyViaIndex(
915 &transaction1
, database_id
, object_store_id
, 0, m_key1
, &new_primary_key
);
916 EXPECT_FALSE(s
.ok());
918 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
919 KeyPrefix::kInvalidId
,
924 EXPECT_FALSE(s
.ok());
925 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
927 KeyPrefix::kInvalidId
,
931 EXPECT_FALSE(s
.ok());
934 TEST_F(IndexedDBBackingStoreTest
, CreateDatabase
) {
935 const base::string16
database_name(ASCIIToUTF16("db1"));
937 const base::string16
version(ASCIIToUTF16("old_string_version"));
938 const int64 int_version
= 9;
940 const int64 object_store_id
= 99;
941 const base::string16
object_store_name(ASCIIToUTF16("object_store1"));
942 const bool auto_increment
= true;
943 const IndexedDBKeyPath
object_store_key_path(
944 ASCIIToUTF16("object_store_key"));
946 const int64 index_id
= 999;
947 const base::string16
index_name(ASCIIToUTF16("index1"));
948 const bool unique
= true;
949 const bool multi_entry
= true;
950 const IndexedDBKeyPath
index_key_path(ASCIIToUTF16("index_key"));
953 leveldb::Status s
= backing_store_
->CreateIDBDatabaseMetaData(
954 database_name
, version
, int_version
, &database_id
);
956 EXPECT_GT(database_id
, 0);
958 IndexedDBBackingStore::Transaction
transaction(backing_store_
.get());
961 s
= backing_store_
->CreateObjectStore(&transaction
,
965 object_store_key_path
,
969 s
= backing_store_
->CreateIndex(&transaction
,
979 scoped_refptr
<TestCallback
> callback(new TestCallback());
980 s
= transaction
.CommitPhaseOne(callback
);
982 EXPECT_TRUE(callback
->called
);
983 EXPECT_TRUE(callback
->succeeded
);
984 s
= transaction
.CommitPhaseTwo();
989 IndexedDBDatabaseMetadata database
;
991 leveldb::Status s
= backing_store_
->GetIDBDatabaseMetaData(
992 database_name
, &database
, &found
);
996 // database.name is not filled in by the implementation.
997 EXPECT_EQ(version
, database
.version
);
998 EXPECT_EQ(int_version
, database
.int_version
);
999 EXPECT_EQ(database_id
, database
.id
);
1001 s
= backing_store_
->GetObjectStores(database
.id
, &database
.object_stores
);
1002 EXPECT_TRUE(s
.ok());
1004 EXPECT_EQ(1UL, database
.object_stores
.size());
1005 IndexedDBObjectStoreMetadata object_store
=
1006 database
.object_stores
[object_store_id
];
1007 EXPECT_EQ(object_store_name
, object_store
.name
);
1008 EXPECT_EQ(object_store_key_path
, object_store
.key_path
);
1009 EXPECT_EQ(auto_increment
, object_store
.auto_increment
);
1011 EXPECT_EQ(1UL, object_store
.indexes
.size());
1012 IndexedDBIndexMetadata index
= object_store
.indexes
[index_id
];
1013 EXPECT_EQ(index_name
, index
.name
);
1014 EXPECT_EQ(index_key_path
, index
.key_path
);
1015 EXPECT_EQ(unique
, index
.unique
);
1016 EXPECT_EQ(multi_entry
, index
.multi_entry
);
1020 TEST_F(IndexedDBBackingStoreTest
, GetDatabaseNames
) {
1021 const base::string16
string_version(ASCIIToUTF16("string_version"));
1023 const base::string16
db1_name(ASCIIToUTF16("db1"));
1024 const int64 db1_version
= 1LL;
1027 // Database records with DEFAULT_INT_VERSION represent stale data,
1028 // and should not be enumerated.
1029 const base::string16
db2_name(ASCIIToUTF16("db2"));
1030 const int64 db2_version
= IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
;
1033 leveldb::Status s
= backing_store_
->CreateIDBDatabaseMetaData(
1034 db1_name
, string_version
, db1_version
, &db1_id
);
1035 EXPECT_TRUE(s
.ok());
1036 EXPECT_GT(db1_id
, 0LL);
1038 s
= backing_store_
->CreateIDBDatabaseMetaData(
1039 db2_name
, string_version
, db2_version
, &db2_id
);
1040 EXPECT_TRUE(s
.ok());
1041 EXPECT_GT(db2_id
, db1_id
);
1043 std::vector
<base::string16
> names
= backing_store_
->GetDatabaseNames(&s
);
1044 EXPECT_TRUE(s
.ok());
1045 EXPECT_EQ(names
.size(), 1ULL);
1046 EXPECT_EQ(names
[0], db1_name
);
1051 } // namespace content