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/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
) 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_
;
172 std::vector
<int64
> removals_
;
174 DISALLOW_COPY_AND_ASSIGN(TestableIndexedDBBackingStore
);
177 class TestIDBFactory
: public IndexedDBFactoryImpl
{
179 explicit TestIDBFactory(IndexedDBContextImpl
* idb_context
)
180 : IndexedDBFactoryImpl(idb_context
) {}
182 scoped_refptr
<TestableIndexedDBBackingStore
> OpenBackingStoreForTest(
184 net::URLRequestContext
* url_request_context
) {
185 blink::WebIDBDataLoss data_loss
;
186 std::string data_loss_reason
;
188 leveldb::Status status
;
189 scoped_refptr
<IndexedDBBackingStore
> backing_store
=
190 OpenBackingStore(origin
,
191 context()->data_path(),
197 scoped_refptr
<TestableIndexedDBBackingStore
> testable_store
=
198 static_cast<TestableIndexedDBBackingStore
*>(backing_store
.get());
199 return testable_store
;
203 ~TestIDBFactory() override
{}
205 scoped_refptr
<IndexedDBBackingStore
> OpenBackingStoreHelper(
206 const GURL
& origin_url
,
207 const base::FilePath
& data_directory
,
208 net::URLRequestContext
* request_context
,
209 blink::WebIDBDataLoss
* data_loss
,
210 std::string
* data_loss_message
,
213 leveldb::Status
* status
) override
{
214 DefaultLevelDBFactory leveldb_factory
;
215 return TestableIndexedDBBackingStore::Open(this,
220 context()->TaskRunner(),
225 DISALLOW_COPY_AND_ASSIGN(TestIDBFactory
);
228 class IndexedDBBackingStoreTest
: public testing::Test
{
230 IndexedDBBackingStoreTest() {}
231 void SetUp() override
{
232 const GURL
origin("http://localhost:81");
233 task_runner_
= new base::TestSimpleTaskRunner();
234 special_storage_policy_
= new MockSpecialStoragePolicy();
235 special_storage_policy_
->SetAllUnlimited(true);
236 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
237 idb_context_
= new IndexedDBContextImpl(temp_dir_
.path(),
238 special_storage_policy_
.get(),
241 idb_factory_
= new TestIDBFactory(idb_context_
.get());
243 idb_factory_
->OpenBackingStoreForTest(origin
, &url_request_context_
);
245 // useful keys and values during tests
246 m_value1
= IndexedDBValue("value1", std::vector
<IndexedDBBlobInfo
>());
247 m_value2
= IndexedDBValue("value2", std::vector
<IndexedDBBlobInfo
>());
249 m_blob_info
.push_back(
250 IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1));
251 m_blob_info
.push_back(
252 IndexedDBBlobInfo("uuid 4",
253 base::FilePath(FILE_PATH_LITERAL("path/to/file")),
254 base::UTF8ToUTF16("file name"),
255 base::UTF8ToUTF16("file type")));
256 m_value3
= IndexedDBValue("value3", m_blob_info
);
258 m_key1
= IndexedDBKey(99, blink::WebIDBKeyTypeNumber
);
259 m_key2
= IndexedDBKey(ASCIIToUTF16("key2"));
260 m_key3
= IndexedDBKey(ASCIIToUTF16("key3"));
263 // This just checks the data that survive getting stored and recalled, e.g.
264 // the file path and UUID will change and thus aren't verified.
265 bool CheckBlobInfoMatches(const std::vector
<IndexedDBBlobInfo
>& reads
) const {
266 if (m_blob_info
.size() != reads
.size())
268 for (size_t i
= 0; i
< m_blob_info
.size(); ++i
) {
269 const IndexedDBBlobInfo
& a
= m_blob_info
[i
];
270 const IndexedDBBlobInfo
& b
= reads
[i
];
271 if (a
.is_file() != b
.is_file())
273 if (a
.type() != b
.type())
276 if (a
.file_name() != b
.file_name())
279 if (a
.size() != b
.size())
286 bool CheckBlobReadsMatchWrites(
287 const std::vector
<IndexedDBBlobInfo
>& reads
) const {
288 if (backing_store_
->writes().size() != reads
.size())
291 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
)
292 ids
.insert(backing_store_
->writes()[i
].key());
293 if (ids
.size() != backing_store_
->writes().size())
295 for (size_t i
= 0; i
< reads
.size(); ++i
) {
296 if (ids
.count(reads
[i
].key()) != 1)
302 bool CheckBlobWrites() const {
303 if (backing_store_
->writes().size() != m_blob_info
.size())
305 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
) {
306 const IndexedDBBackingStore::Transaction::WriteDescriptor
& desc
=
307 backing_store_
->writes()[i
];
308 const IndexedDBBlobInfo
& info
= m_blob_info
[i
];
309 if (desc
.is_file() != info
.is_file())
311 if (desc
.is_file()) {
312 if (desc
.file_path() != info
.file_path())
315 if (desc
.url() != GURL("blob:uuid/" + info
.uuid()))
322 bool CheckBlobRemovals() const {
323 if (backing_store_
->removals().size() != backing_store_
->writes().size())
325 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
) {
326 if (backing_store_
->writes()[i
].key() != backing_store_
->removals()[i
])
333 // Must be initialized before url_request_context_
334 content::TestBrowserThreadBundle thread_bundle_
;
336 base::ScopedTempDir temp_dir_
;
337 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner_
;
338 scoped_refptr
<MockSpecialStoragePolicy
> special_storage_policy_
;
339 scoped_refptr
<IndexedDBContextImpl
> idb_context_
;
340 scoped_refptr
<TestIDBFactory
> idb_factory_
;
341 net::TestURLRequestContext url_request_context_
;
343 scoped_refptr
<TestableIndexedDBBackingStore
> backing_store_
;
345 // Sample keys and values that are consistent.
349 IndexedDBValue m_value1
;
350 IndexedDBValue m_value2
;
351 IndexedDBValue m_value3
;
352 std::vector
<IndexedDBBlobInfo
> m_blob_info
;
355 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest
);
358 class TestCallback
: public IndexedDBBackingStore::BlobWriteCallback
{
360 TestCallback() : called(false), succeeded(false) {}
361 void Run(bool succeeded_in
) override
{
363 succeeded
= succeeded_in
;
369 ~TestCallback() override
{}
372 DISALLOW_COPY_AND_ASSIGN(TestCallback
);
375 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistency
) {
377 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
378 transaction1
.Begin();
379 ScopedVector
<storage::BlobDataHandle
> handles
;
380 IndexedDBBackingStore::RecordIdentifier record
;
381 leveldb::Status s
= backing_store_
->PutRecord(
382 &transaction1
, 1, 1, m_key1
, &m_value1
, &handles
, &record
);
384 scoped_refptr
<TestCallback
> callback(new TestCallback());
385 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
386 EXPECT_TRUE(callback
->called
);
387 EXPECT_TRUE(callback
->succeeded
);
388 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
392 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
393 transaction2
.Begin();
394 IndexedDBValue result_value
;
396 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key1
, &result_value
)
398 scoped_refptr
<TestCallback
> callback(new TestCallback());
399 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
400 EXPECT_TRUE(callback
->called
);
401 EXPECT_TRUE(callback
->succeeded
);
402 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
403 EXPECT_EQ(m_value1
.bits
, result_value
.bits
);
407 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistencyWithBlobs
) {
409 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
410 transaction1
.Begin();
411 ScopedVector
<storage::BlobDataHandle
> handles
;
412 IndexedDBBackingStore::RecordIdentifier record
;
413 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
420 scoped_refptr
<TestCallback
> callback(new TestCallback());
421 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
422 task_runner_
->RunUntilIdle();
423 EXPECT_TRUE(CheckBlobWrites());
424 EXPECT_TRUE(callback
->called
);
425 EXPECT_TRUE(callback
->succeeded
);
426 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
430 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
431 transaction2
.Begin();
432 IndexedDBValue result_value
;
434 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key3
, &result_value
)
436 scoped_refptr
<TestCallback
> callback(new TestCallback());
437 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
438 EXPECT_TRUE(callback
->called
);
439 EXPECT_TRUE(callback
->succeeded
);
440 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
441 EXPECT_EQ(m_value3
.bits
, result_value
.bits
);
442 EXPECT_TRUE(CheckBlobInfoMatches(result_value
.blob_info
));
443 EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value
.blob_info
));
447 IndexedDBBackingStore::Transaction
transaction3(backing_store_
.get());
448 transaction3
.Begin();
449 IndexedDBValue result_value
;
450 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
453 IndexedDBKeyRange(m_key3
)).ok());
454 scoped_refptr
<TestCallback
> callback(new TestCallback());
455 EXPECT_TRUE(transaction3
.CommitPhaseOne(callback
).ok());
456 task_runner_
->RunUntilIdle();
457 EXPECT_TRUE(callback
->called
);
458 EXPECT_TRUE(callback
->succeeded
);
459 EXPECT_TRUE(transaction3
.CommitPhaseTwo().ok());
460 EXPECT_TRUE(CheckBlobRemovals());
464 TEST_F(IndexedDBBackingStoreTest
, DeleteRange
) {
465 IndexedDBKey key0
= IndexedDBKey(ASCIIToUTF16("key0"));
466 IndexedDBKey key1
= IndexedDBKey(ASCIIToUTF16("key1"));
467 IndexedDBKey key2
= IndexedDBKey(ASCIIToUTF16("key2"));
468 IndexedDBKey key3
= IndexedDBKey(ASCIIToUTF16("key3"));
469 IndexedDBBlobInfo
blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
470 IndexedDBBlobInfo
blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
471 IndexedDBBlobInfo
blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
472 IndexedDBBlobInfo
blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
473 IndexedDBKeyRange ranges
[] = {IndexedDBKeyRange(key1
, key2
, false, false),
474 IndexedDBKeyRange(key1
, key2
, false, false),
475 IndexedDBKeyRange(key0
, key2
, true, false),
476 IndexedDBKeyRange(key1
, key3
, false, true),
477 IndexedDBKeyRange(key0
, key3
, true, true)};
479 for (unsigned i
= 0; i
< sizeof(ranges
) / sizeof(IndexedDBKeyRange
); ++i
) {
480 backing_store_
->ClearWrites();
481 backing_store_
->ClearRemovals();
484 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
486 blob_info0
.push_back(blob0
);
487 blob_info1
.push_back(blob1
);
488 blob_info2
.push_back(blob2
);
489 blob_info3
.push_back(blob3
);
490 IndexedDBValue value0
= IndexedDBValue("value0", blob_info0
);
491 IndexedDBValue value1
= IndexedDBValue("value1", blob_info1
);
492 IndexedDBValue value2
= IndexedDBValue("value2", blob_info2
);
493 IndexedDBValue value3
= IndexedDBValue("value3", blob_info3
);
494 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
495 transaction1
.Begin();
496 ScopedVector
<storage::BlobDataHandle
> handles
;
497 IndexedDBBackingStore::RecordIdentifier record
;
498 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
505 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
512 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
519 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
526 scoped_refptr
<TestCallback
> callback(new TestCallback());
527 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
528 task_runner_
->RunUntilIdle();
529 EXPECT_TRUE(callback
->called
);
530 EXPECT_TRUE(callback
->succeeded
);
531 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
535 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
536 transaction2
.Begin();
537 IndexedDBValue result_value
;
539 backing_store_
->DeleteRange(&transaction2
, 1, i
+ 1, ranges
[i
]).ok());
540 scoped_refptr
<TestCallback
> callback(new TestCallback());
541 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
542 task_runner_
->RunUntilIdle();
543 EXPECT_TRUE(callback
->called
);
544 EXPECT_TRUE(callback
->succeeded
);
545 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
546 EXPECT_EQ(2UL, backing_store_
->removals().size());
547 EXPECT_EQ(backing_store_
->writes()[1].key(),
548 backing_store_
->removals()[0]);
549 EXPECT_EQ(backing_store_
->writes()[2].key(),
550 backing_store_
->removals()[1]);
555 TEST_F(IndexedDBBackingStoreTest
, DeleteRangeEmptyRange
) {
556 IndexedDBKey key0
= IndexedDBKey(ASCIIToUTF16("key0"));
557 IndexedDBKey key1
= IndexedDBKey(ASCIIToUTF16("key1"));
558 IndexedDBKey key2
= IndexedDBKey(ASCIIToUTF16("key2"));
559 IndexedDBKey key3
= IndexedDBKey(ASCIIToUTF16("key3"));
560 IndexedDBKey key4
= IndexedDBKey(ASCIIToUTF16("key4"));
561 IndexedDBBlobInfo
blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
562 IndexedDBBlobInfo
blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
563 IndexedDBBlobInfo
blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
564 IndexedDBBlobInfo
blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
565 IndexedDBKeyRange ranges
[] = {IndexedDBKeyRange(key3
, key4
, true, false),
566 IndexedDBKeyRange(key2
, key1
, false, false),
567 IndexedDBKeyRange(key2
, key1
, true, true)};
569 for (unsigned i
= 0; i
< arraysize(ranges
); ++i
) {
570 backing_store_
->ClearWrites();
571 backing_store_
->ClearRemovals();
574 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
576 blob_info0
.push_back(blob0
);
577 blob_info1
.push_back(blob1
);
578 blob_info2
.push_back(blob2
);
579 blob_info3
.push_back(blob3
);
580 IndexedDBValue value0
= IndexedDBValue("value0", blob_info0
);
581 IndexedDBValue value1
= IndexedDBValue("value1", blob_info1
);
582 IndexedDBValue value2
= IndexedDBValue("value2", blob_info2
);
583 IndexedDBValue value3
= IndexedDBValue("value3", blob_info3
);
584 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
585 transaction1
.Begin();
586 ScopedVector
<storage::BlobDataHandle
> handles
;
587 IndexedDBBackingStore::RecordIdentifier record
;
588 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
595 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
602 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
609 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
616 scoped_refptr
<TestCallback
> callback(new TestCallback());
617 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
618 task_runner_
->RunUntilIdle();
619 EXPECT_TRUE(callback
->called
);
620 EXPECT_TRUE(callback
->succeeded
);
621 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
625 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
626 transaction2
.Begin();
627 IndexedDBValue result_value
;
629 backing_store_
->DeleteRange(&transaction2
, 1, i
+ 1, ranges
[i
]).ok());
630 scoped_refptr
<TestCallback
> callback(new TestCallback());
631 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
632 task_runner_
->RunUntilIdle();
633 EXPECT_TRUE(callback
->called
);
634 EXPECT_TRUE(callback
->succeeded
);
635 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
636 EXPECT_EQ(0UL, backing_store_
->removals().size());
641 TEST_F(IndexedDBBackingStoreTest
, LiveBlobJournal
) {
643 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
644 transaction1
.Begin();
645 ScopedVector
<storage::BlobDataHandle
> handles
;
646 IndexedDBBackingStore::RecordIdentifier record
;
647 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
654 scoped_refptr
<TestCallback
> callback(new TestCallback());
655 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
656 task_runner_
->RunUntilIdle();
657 EXPECT_TRUE(CheckBlobWrites());
658 EXPECT_TRUE(callback
->called
);
659 EXPECT_TRUE(callback
->succeeded
);
660 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
663 IndexedDBValue read_result_value
;
665 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
666 transaction2
.Begin();
668 backing_store_
->GetRecord(
669 &transaction2
, 1, 1, m_key3
, &read_result_value
)
671 scoped_refptr
<TestCallback
> callback(new TestCallback());
672 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
673 EXPECT_TRUE(callback
->called
);
674 EXPECT_TRUE(callback
->succeeded
);
675 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
676 EXPECT_EQ(m_value3
.bits
, read_result_value
.bits
);
677 EXPECT_TRUE(CheckBlobInfoMatches(read_result_value
.blob_info
));
678 EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value
.blob_info
));
679 for (size_t i
= 0; i
< read_result_value
.blob_info
.size(); ++i
) {
680 read_result_value
.blob_info
[i
].mark_used_callback().Run();
685 IndexedDBBackingStore::Transaction
transaction3(backing_store_
.get());
686 transaction3
.Begin();
687 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
690 IndexedDBKeyRange(m_key3
)).ok());
691 scoped_refptr
<TestCallback
> callback(new TestCallback());
692 EXPECT_TRUE(transaction3
.CommitPhaseOne(callback
).ok());
693 task_runner_
->RunUntilIdle();
694 EXPECT_TRUE(callback
->called
);
695 EXPECT_TRUE(callback
->succeeded
);
696 EXPECT_TRUE(transaction3
.CommitPhaseTwo().ok());
697 EXPECT_EQ(0U, backing_store_
->removals().size());
698 for (size_t i
= 0; i
< read_result_value
.blob_info
.size(); ++i
) {
699 read_result_value
.blob_info
[i
].release_callback().Run(
700 read_result_value
.blob_info
[i
].file_path());
702 task_runner_
->RunUntilIdle();
703 EXPECT_NE(0U, backing_store_
->removals().size());
704 EXPECT_TRUE(CheckBlobRemovals());
708 // Make sure that using very high ( more than 32 bit ) values for database_id
709 // and object_store_id still work.
710 TEST_F(IndexedDBBackingStoreTest
, HighIds
) {
711 const int64 high_database_id
= 1ULL << 35;
712 const int64 high_object_store_id
= 1ULL << 39;
713 // index_ids are capped at 32 bits for storage purposes.
714 const int64 high_index_id
= 1ULL << 29;
716 const int64 invalid_high_index_id
= 1ULL << 37;
718 const IndexedDBKey
& index_key
= m_key2
;
719 std::string index_key_raw
;
720 EncodeIDBKey(index_key
, &index_key_raw
);
722 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
723 transaction1
.Begin();
724 ScopedVector
<storage::BlobDataHandle
> handles
;
725 IndexedDBBackingStore::RecordIdentifier record
;
726 leveldb::Status s
= backing_store_
->PutRecord(&transaction1
,
728 high_object_store_id
,
735 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
737 high_object_store_id
,
738 invalid_high_index_id
,
741 EXPECT_FALSE(s
.ok());
743 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
745 high_object_store_id
,
751 scoped_refptr
<TestCallback
> callback(new TestCallback());
752 s
= transaction1
.CommitPhaseOne(callback
);
754 EXPECT_TRUE(callback
->called
);
755 EXPECT_TRUE(callback
->succeeded
);
756 s
= transaction1
.CommitPhaseTwo();
761 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
762 transaction2
.Begin();
763 IndexedDBValue result_value
;
764 leveldb::Status s
= backing_store_
->GetRecord(&transaction2
,
766 high_object_store_id
,
770 EXPECT_EQ(m_value1
.bits
, result_value
.bits
);
772 scoped_ptr
<IndexedDBKey
> new_primary_key
;
773 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
775 high_object_store_id
,
776 invalid_high_index_id
,
779 EXPECT_FALSE(s
.ok());
781 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
783 high_object_store_id
,
788 EXPECT_TRUE(new_primary_key
->Equals(m_key1
));
790 scoped_refptr
<TestCallback
> callback(new TestCallback());
791 s
= transaction2
.CommitPhaseOne(callback
);
793 EXPECT_TRUE(callback
->called
);
794 EXPECT_TRUE(callback
->succeeded
);
795 s
= transaction2
.CommitPhaseTwo();
800 // Make sure that other invalid ids do not crash.
801 TEST_F(IndexedDBBackingStoreTest
, InvalidIds
) {
802 // valid ids for use when testing invalid ids
803 const int64 database_id
= 1;
804 const int64 object_store_id
= 1;
805 const int64 index_id
= kMinimumIndexId
;
806 const int64 invalid_low_index_id
= 19; // index_ids must be > kMinimumIndexId
808 IndexedDBValue result_value
;
810 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
811 transaction1
.Begin();
813 ScopedVector
<storage::BlobDataHandle
> handles
;
814 IndexedDBBackingStore::RecordIdentifier record
;
815 leveldb::Status s
= backing_store_
->PutRecord(&transaction1
,
817 KeyPrefix::kInvalidId
,
822 EXPECT_FALSE(s
.ok());
823 s
= backing_store_
->PutRecord(
824 &transaction1
, database_id
, 0, m_key1
, &m_value1
, &handles
, &record
);
825 EXPECT_FALSE(s
.ok());
826 s
= backing_store_
->PutRecord(&transaction1
,
827 KeyPrefix::kInvalidId
,
833 EXPECT_FALSE(s
.ok());
834 s
= backing_store_
->PutRecord(
835 &transaction1
, 0, object_store_id
, m_key1
, &m_value1
, &handles
, &record
);
836 EXPECT_FALSE(s
.ok());
838 s
= backing_store_
->GetRecord(
839 &transaction1
, database_id
, KeyPrefix::kInvalidId
, m_key1
, &result_value
);
840 EXPECT_FALSE(s
.ok());
841 s
= backing_store_
->GetRecord(
842 &transaction1
, database_id
, 0, m_key1
, &result_value
);
843 EXPECT_FALSE(s
.ok());
844 s
= backing_store_
->GetRecord(&transaction1
,
845 KeyPrefix::kInvalidId
,
849 EXPECT_FALSE(s
.ok());
850 s
= backing_store_
->GetRecord(
851 &transaction1
, 0, object_store_id
, m_key1
, &result_value
);
852 EXPECT_FALSE(s
.ok());
854 scoped_ptr
<IndexedDBKey
> new_primary_key
;
855 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
858 KeyPrefix::kInvalidId
,
861 EXPECT_FALSE(s
.ok());
862 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
865 invalid_low_index_id
,
868 EXPECT_FALSE(s
.ok());
869 s
= backing_store_
->GetPrimaryKeyViaIndex(
870 &transaction1
, database_id
, object_store_id
, 0, m_key1
, &new_primary_key
);
871 EXPECT_FALSE(s
.ok());
873 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
874 KeyPrefix::kInvalidId
,
879 EXPECT_FALSE(s
.ok());
880 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
882 KeyPrefix::kInvalidId
,
886 EXPECT_FALSE(s
.ok());
889 TEST_F(IndexedDBBackingStoreTest
, CreateDatabase
) {
890 const base::string16
database_name(ASCIIToUTF16("db1"));
892 const base::string16
version(ASCIIToUTF16("old_string_version"));
893 const int64 int_version
= 9;
895 const int64 object_store_id
= 99;
896 const base::string16
object_store_name(ASCIIToUTF16("object_store1"));
897 const bool auto_increment
= true;
898 const IndexedDBKeyPath
object_store_key_path(
899 ASCIIToUTF16("object_store_key"));
901 const int64 index_id
= 999;
902 const base::string16
index_name(ASCIIToUTF16("index1"));
903 const bool unique
= true;
904 const bool multi_entry
= true;
905 const IndexedDBKeyPath
index_key_path(ASCIIToUTF16("index_key"));
908 leveldb::Status s
= backing_store_
->CreateIDBDatabaseMetaData(
909 database_name
, version
, int_version
, &database_id
);
911 EXPECT_GT(database_id
, 0);
913 IndexedDBBackingStore::Transaction
transaction(backing_store_
.get());
916 s
= backing_store_
->CreateObjectStore(&transaction
,
920 object_store_key_path
,
924 s
= backing_store_
->CreateIndex(&transaction
,
934 scoped_refptr
<TestCallback
> callback(new TestCallback());
935 s
= transaction
.CommitPhaseOne(callback
);
937 EXPECT_TRUE(callback
->called
);
938 EXPECT_TRUE(callback
->succeeded
);
939 s
= transaction
.CommitPhaseTwo();
944 IndexedDBDatabaseMetadata database
;
946 leveldb::Status s
= backing_store_
->GetIDBDatabaseMetaData(
947 database_name
, &database
, &found
);
951 // database.name is not filled in by the implementation.
952 EXPECT_EQ(version
, database
.version
);
953 EXPECT_EQ(int_version
, database
.int_version
);
954 EXPECT_EQ(database_id
, database
.id
);
956 s
= backing_store_
->GetObjectStores(database
.id
, &database
.object_stores
);
959 EXPECT_EQ(1UL, database
.object_stores
.size());
960 IndexedDBObjectStoreMetadata object_store
=
961 database
.object_stores
[object_store_id
];
962 EXPECT_EQ(object_store_name
, object_store
.name
);
963 EXPECT_EQ(object_store_key_path
, object_store
.key_path
);
964 EXPECT_EQ(auto_increment
, object_store
.auto_increment
);
966 EXPECT_EQ(1UL, object_store
.indexes
.size());
967 IndexedDBIndexMetadata index
= object_store
.indexes
[index_id
];
968 EXPECT_EQ(index_name
, index
.name
);
969 EXPECT_EQ(index_key_path
, index
.key_path
);
970 EXPECT_EQ(unique
, index
.unique
);
971 EXPECT_EQ(multi_entry
, index
.multi_entry
);
975 TEST_F(IndexedDBBackingStoreTest
, GetDatabaseNames
) {
976 const base::string16
string_version(ASCIIToUTF16("string_version"));
978 const base::string16
db1_name(ASCIIToUTF16("db1"));
979 const int64 db1_version
= 1LL;
982 // Database records with DEFAULT_INT_VERSION represent stale data,
983 // and should not be enumerated.
984 const base::string16
db2_name(ASCIIToUTF16("db2"));
985 const int64 db2_version
= IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
;
988 leveldb::Status s
= backing_store_
->CreateIDBDatabaseMetaData(
989 db1_name
, string_version
, db1_version
, &db1_id
);
991 EXPECT_GT(db1_id
, 0LL);
993 s
= backing_store_
->CreateIDBDatabaseMetaData(
994 db2_name
, string_version
, db2_version
, &db2_id
);
996 EXPECT_GT(db2_id
, db1_id
);
998 std::vector
<base::string16
> names
= backing_store_
->GetDatabaseNames(&s
);
1000 EXPECT_EQ(names
.size(), 1ULL);
1001 EXPECT_EQ(names
[0], db1_name
);
1006 } // namespace content