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_blob_info
.push_back(
257 IndexedDBBlobInfo("uuid 5",
259 base::UTF8ToUTF16("file name"),
260 base::UTF8ToUTF16("file type")));
261 m_value3
= IndexedDBValue("value3", m_blob_info
);
263 m_key1
= IndexedDBKey(99, blink::WebIDBKeyTypeNumber
);
264 m_key2
= IndexedDBKey(ASCIIToUTF16("key2"));
265 m_key3
= IndexedDBKey(ASCIIToUTF16("key3"));
268 // This just checks the data that survive getting stored and recalled, e.g.
269 // the file path and UUID will change and thus aren't verified.
270 bool CheckBlobInfoMatches(const std::vector
<IndexedDBBlobInfo
>& reads
) const {
271 if (m_blob_info
.size() != reads
.size())
273 for (size_t i
= 0; i
< m_blob_info
.size(); ++i
) {
274 const IndexedDBBlobInfo
& a
= m_blob_info
[i
];
275 const IndexedDBBlobInfo
& b
= reads
[i
];
276 if (a
.is_file() != b
.is_file())
278 if (a
.type() != b
.type())
281 if (a
.file_name() != b
.file_name())
284 if (a
.size() != b
.size())
291 bool CheckBlobReadsMatchWrites(
292 const std::vector
<IndexedDBBlobInfo
>& reads
) const {
293 if (backing_store_
->writes().size() != reads
.size())
296 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
)
297 ids
.insert(backing_store_
->writes()[i
].key());
298 if (ids
.size() != backing_store_
->writes().size())
300 for (size_t i
= 0; i
< reads
.size(); ++i
) {
301 if (ids
.count(reads
[i
].key()) != 1)
307 bool CheckBlobWrites() const {
308 if (backing_store_
->writes().size() != m_blob_info
.size())
310 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
) {
311 const IndexedDBBackingStore::Transaction::WriteDescriptor
& desc
=
312 backing_store_
->writes()[i
];
313 const IndexedDBBlobInfo
& info
= m_blob_info
[i
];
314 if (desc
.is_file() != info
.is_file()) {
315 if (!info
.is_file() || !info
.file_path().empty())
317 } else if (desc
.is_file()) {
318 if (desc
.file_path() != info
.file_path())
321 if (desc
.url() != GURL("blob:uuid/" + info
.uuid()))
328 bool CheckBlobRemovals() const {
329 if (backing_store_
->removals().size() != backing_store_
->writes().size())
331 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
) {
332 if (backing_store_
->writes()[i
].key() != backing_store_
->removals()[i
])
339 // Must be initialized before url_request_context_
340 content::TestBrowserThreadBundle thread_bundle_
;
342 base::ScopedTempDir temp_dir_
;
343 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner_
;
344 scoped_refptr
<MockSpecialStoragePolicy
> special_storage_policy_
;
345 scoped_refptr
<IndexedDBContextImpl
> idb_context_
;
346 scoped_refptr
<TestIDBFactory
> idb_factory_
;
347 net::TestURLRequestContext url_request_context_
;
349 scoped_refptr
<TestableIndexedDBBackingStore
> backing_store_
;
351 // Sample keys and values that are consistent.
355 IndexedDBValue m_value1
;
356 IndexedDBValue m_value2
;
357 IndexedDBValue m_value3
;
358 std::vector
<IndexedDBBlobInfo
> m_blob_info
;
361 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest
);
364 class TestCallback
: public IndexedDBBackingStore::BlobWriteCallback
{
366 TestCallback() : called(false), succeeded(false) {}
367 void Run(bool succeeded_in
) override
{
369 succeeded
= succeeded_in
;
375 ~TestCallback() override
{}
378 DISALLOW_COPY_AND_ASSIGN(TestCallback
);
381 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistency
) {
383 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
384 transaction1
.Begin();
385 ScopedVector
<storage::BlobDataHandle
> handles
;
386 IndexedDBBackingStore::RecordIdentifier record
;
387 leveldb::Status s
= backing_store_
->PutRecord(
388 &transaction1
, 1, 1, m_key1
, &m_value1
, &handles
, &record
);
390 scoped_refptr
<TestCallback
> callback(new TestCallback());
391 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
392 EXPECT_TRUE(callback
->called
);
393 EXPECT_TRUE(callback
->succeeded
);
394 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
398 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
399 transaction2
.Begin();
400 IndexedDBValue result_value
;
402 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key1
, &result_value
)
404 scoped_refptr
<TestCallback
> callback(new TestCallback());
405 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
406 EXPECT_TRUE(callback
->called
);
407 EXPECT_TRUE(callback
->succeeded
);
408 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
409 EXPECT_EQ(m_value1
.bits
, result_value
.bits
);
413 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistencyWithBlobs
) {
415 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
416 transaction1
.Begin();
417 ScopedVector
<storage::BlobDataHandle
> handles
;
418 IndexedDBBackingStore::RecordIdentifier record
;
419 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
426 scoped_refptr
<TestCallback
> callback(new TestCallback());
427 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
428 task_runner_
->RunUntilIdle();
429 EXPECT_TRUE(CheckBlobWrites());
430 EXPECT_TRUE(callback
->called
);
431 EXPECT_TRUE(callback
->succeeded
);
432 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
436 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
437 transaction2
.Begin();
438 IndexedDBValue result_value
;
440 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key3
, &result_value
)
442 scoped_refptr
<TestCallback
> callback(new TestCallback());
443 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
444 EXPECT_TRUE(callback
->called
);
445 EXPECT_TRUE(callback
->succeeded
);
446 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
447 EXPECT_EQ(m_value3
.bits
, result_value
.bits
);
448 EXPECT_TRUE(CheckBlobInfoMatches(result_value
.blob_info
));
449 EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value
.blob_info
));
453 IndexedDBBackingStore::Transaction
transaction3(backing_store_
.get());
454 transaction3
.Begin();
455 IndexedDBValue result_value
;
456 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
459 IndexedDBKeyRange(m_key3
)).ok());
460 scoped_refptr
<TestCallback
> callback(new TestCallback());
461 EXPECT_TRUE(transaction3
.CommitPhaseOne(callback
).ok());
462 task_runner_
->RunUntilIdle();
463 EXPECT_TRUE(callback
->called
);
464 EXPECT_TRUE(callback
->succeeded
);
465 EXPECT_TRUE(transaction3
.CommitPhaseTwo().ok());
466 EXPECT_TRUE(CheckBlobRemovals());
470 TEST_F(IndexedDBBackingStoreTest
, DeleteRange
) {
471 IndexedDBKey key0
= IndexedDBKey(ASCIIToUTF16("key0"));
472 IndexedDBKey key1
= IndexedDBKey(ASCIIToUTF16("key1"));
473 IndexedDBKey key2
= IndexedDBKey(ASCIIToUTF16("key2"));
474 IndexedDBKey key3
= IndexedDBKey(ASCIIToUTF16("key3"));
475 IndexedDBBlobInfo
blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
476 IndexedDBBlobInfo
blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
477 IndexedDBBlobInfo
blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
478 IndexedDBBlobInfo
blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
479 IndexedDBKeyRange ranges
[] = {IndexedDBKeyRange(key1
, key2
, false, false),
480 IndexedDBKeyRange(key1
, key2
, false, false),
481 IndexedDBKeyRange(key0
, key2
, true, false),
482 IndexedDBKeyRange(key1
, key3
, false, true),
483 IndexedDBKeyRange(key0
, key3
, true, true)};
485 for (unsigned i
= 0; i
< sizeof(ranges
) / sizeof(IndexedDBKeyRange
); ++i
) {
486 backing_store_
->ClearWrites();
487 backing_store_
->ClearRemovals();
490 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
492 blob_info0
.push_back(blob0
);
493 blob_info1
.push_back(blob1
);
494 blob_info2
.push_back(blob2
);
495 blob_info3
.push_back(blob3
);
496 IndexedDBValue value0
= IndexedDBValue("value0", blob_info0
);
497 IndexedDBValue value1
= IndexedDBValue("value1", blob_info1
);
498 IndexedDBValue value2
= IndexedDBValue("value2", blob_info2
);
499 IndexedDBValue value3
= IndexedDBValue("value3", blob_info3
);
500 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
501 transaction1
.Begin();
502 ScopedVector
<storage::BlobDataHandle
> handles
;
503 IndexedDBBackingStore::RecordIdentifier record
;
504 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
511 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
518 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
525 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
532 scoped_refptr
<TestCallback
> callback(new TestCallback());
533 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
534 task_runner_
->RunUntilIdle();
535 EXPECT_TRUE(callback
->called
);
536 EXPECT_TRUE(callback
->succeeded
);
537 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
541 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
542 transaction2
.Begin();
543 IndexedDBValue result_value
;
545 backing_store_
->DeleteRange(&transaction2
, 1, i
+ 1, ranges
[i
]).ok());
546 scoped_refptr
<TestCallback
> callback(new TestCallback());
547 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
548 task_runner_
->RunUntilIdle();
549 EXPECT_TRUE(callback
->called
);
550 EXPECT_TRUE(callback
->succeeded
);
551 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
552 EXPECT_EQ(2UL, backing_store_
->removals().size());
553 EXPECT_EQ(backing_store_
->writes()[1].key(),
554 backing_store_
->removals()[0]);
555 EXPECT_EQ(backing_store_
->writes()[2].key(),
556 backing_store_
->removals()[1]);
561 TEST_F(IndexedDBBackingStoreTest
, DeleteRangeEmptyRange
) {
562 IndexedDBKey key0
= IndexedDBKey(ASCIIToUTF16("key0"));
563 IndexedDBKey key1
= IndexedDBKey(ASCIIToUTF16("key1"));
564 IndexedDBKey key2
= IndexedDBKey(ASCIIToUTF16("key2"));
565 IndexedDBKey key3
= IndexedDBKey(ASCIIToUTF16("key3"));
566 IndexedDBKey key4
= IndexedDBKey(ASCIIToUTF16("key4"));
567 IndexedDBBlobInfo
blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
568 IndexedDBBlobInfo
blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
569 IndexedDBBlobInfo
blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
570 IndexedDBBlobInfo
blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
571 IndexedDBKeyRange ranges
[] = {IndexedDBKeyRange(key3
, key4
, true, false),
572 IndexedDBKeyRange(key2
, key1
, false, false),
573 IndexedDBKeyRange(key2
, key1
, true, true)};
575 for (unsigned i
= 0; i
< arraysize(ranges
); ++i
) {
576 backing_store_
->ClearWrites();
577 backing_store_
->ClearRemovals();
580 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
582 blob_info0
.push_back(blob0
);
583 blob_info1
.push_back(blob1
);
584 blob_info2
.push_back(blob2
);
585 blob_info3
.push_back(blob3
);
586 IndexedDBValue value0
= IndexedDBValue("value0", blob_info0
);
587 IndexedDBValue value1
= IndexedDBValue("value1", blob_info1
);
588 IndexedDBValue value2
= IndexedDBValue("value2", blob_info2
);
589 IndexedDBValue value3
= IndexedDBValue("value3", blob_info3
);
590 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
591 transaction1
.Begin();
592 ScopedVector
<storage::BlobDataHandle
> handles
;
593 IndexedDBBackingStore::RecordIdentifier record
;
594 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
601 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
608 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
615 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
622 scoped_refptr
<TestCallback
> callback(new TestCallback());
623 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
624 task_runner_
->RunUntilIdle();
625 EXPECT_TRUE(callback
->called
);
626 EXPECT_TRUE(callback
->succeeded
);
627 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
631 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
632 transaction2
.Begin();
633 IndexedDBValue result_value
;
635 backing_store_
->DeleteRange(&transaction2
, 1, i
+ 1, ranges
[i
]).ok());
636 scoped_refptr
<TestCallback
> callback(new TestCallback());
637 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
638 task_runner_
->RunUntilIdle();
639 EXPECT_TRUE(callback
->called
);
640 EXPECT_TRUE(callback
->succeeded
);
641 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
642 EXPECT_EQ(0UL, backing_store_
->removals().size());
647 TEST_F(IndexedDBBackingStoreTest
, LiveBlobJournal
) {
649 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
650 transaction1
.Begin();
651 ScopedVector
<storage::BlobDataHandle
> handles
;
652 IndexedDBBackingStore::RecordIdentifier record
;
653 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
660 scoped_refptr
<TestCallback
> callback(new TestCallback());
661 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
662 task_runner_
->RunUntilIdle();
663 EXPECT_TRUE(CheckBlobWrites());
664 EXPECT_TRUE(callback
->called
);
665 EXPECT_TRUE(callback
->succeeded
);
666 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
669 IndexedDBValue read_result_value
;
671 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
672 transaction2
.Begin();
674 backing_store_
->GetRecord(
675 &transaction2
, 1, 1, m_key3
, &read_result_value
)
677 scoped_refptr
<TestCallback
> callback(new TestCallback());
678 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
679 EXPECT_TRUE(callback
->called
);
680 EXPECT_TRUE(callback
->succeeded
);
681 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
682 EXPECT_EQ(m_value3
.bits
, read_result_value
.bits
);
683 EXPECT_TRUE(CheckBlobInfoMatches(read_result_value
.blob_info
));
684 EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value
.blob_info
));
685 for (size_t i
= 0; i
< read_result_value
.blob_info
.size(); ++i
) {
686 read_result_value
.blob_info
[i
].mark_used_callback().Run();
691 IndexedDBBackingStore::Transaction
transaction3(backing_store_
.get());
692 transaction3
.Begin();
693 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
696 IndexedDBKeyRange(m_key3
)).ok());
697 scoped_refptr
<TestCallback
> callback(new TestCallback());
698 EXPECT_TRUE(transaction3
.CommitPhaseOne(callback
).ok());
699 task_runner_
->RunUntilIdle();
700 EXPECT_TRUE(callback
->called
);
701 EXPECT_TRUE(callback
->succeeded
);
702 EXPECT_TRUE(transaction3
.CommitPhaseTwo().ok());
703 EXPECT_EQ(0U, backing_store_
->removals().size());
704 for (size_t i
= 0; i
< read_result_value
.blob_info
.size(); ++i
) {
705 read_result_value
.blob_info
[i
].release_callback().Run(
706 read_result_value
.blob_info
[i
].file_path());
708 task_runner_
->RunUntilIdle();
709 EXPECT_NE(0U, backing_store_
->removals().size());
710 EXPECT_TRUE(CheckBlobRemovals());
714 // Make sure that using very high ( more than 32 bit ) values for database_id
715 // and object_store_id still work.
716 TEST_F(IndexedDBBackingStoreTest
, HighIds
) {
717 const int64 high_database_id
= 1ULL << 35;
718 const int64 high_object_store_id
= 1ULL << 39;
719 // index_ids are capped at 32 bits for storage purposes.
720 const int64 high_index_id
= 1ULL << 29;
722 const int64 invalid_high_index_id
= 1ULL << 37;
724 const IndexedDBKey
& index_key
= m_key2
;
725 std::string index_key_raw
;
726 EncodeIDBKey(index_key
, &index_key_raw
);
728 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
729 transaction1
.Begin();
730 ScopedVector
<storage::BlobDataHandle
> handles
;
731 IndexedDBBackingStore::RecordIdentifier record
;
732 leveldb::Status s
= backing_store_
->PutRecord(&transaction1
,
734 high_object_store_id
,
741 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
743 high_object_store_id
,
744 invalid_high_index_id
,
747 EXPECT_FALSE(s
.ok());
749 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
751 high_object_store_id
,
757 scoped_refptr
<TestCallback
> callback(new TestCallback());
758 s
= transaction1
.CommitPhaseOne(callback
);
760 EXPECT_TRUE(callback
->called
);
761 EXPECT_TRUE(callback
->succeeded
);
762 s
= transaction1
.CommitPhaseTwo();
767 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
768 transaction2
.Begin();
769 IndexedDBValue result_value
;
770 leveldb::Status s
= backing_store_
->GetRecord(&transaction2
,
772 high_object_store_id
,
776 EXPECT_EQ(m_value1
.bits
, result_value
.bits
);
778 scoped_ptr
<IndexedDBKey
> new_primary_key
;
779 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
781 high_object_store_id
,
782 invalid_high_index_id
,
785 EXPECT_FALSE(s
.ok());
787 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
789 high_object_store_id
,
794 EXPECT_TRUE(new_primary_key
->Equals(m_key1
));
796 scoped_refptr
<TestCallback
> callback(new TestCallback());
797 s
= transaction2
.CommitPhaseOne(callback
);
799 EXPECT_TRUE(callback
->called
);
800 EXPECT_TRUE(callback
->succeeded
);
801 s
= transaction2
.CommitPhaseTwo();
806 // Make sure that other invalid ids do not crash.
807 TEST_F(IndexedDBBackingStoreTest
, InvalidIds
) {
808 // valid ids for use when testing invalid ids
809 const int64 database_id
= 1;
810 const int64 object_store_id
= 1;
811 const int64 index_id
= kMinimumIndexId
;
812 const int64 invalid_low_index_id
= 19; // index_ids must be > kMinimumIndexId
814 IndexedDBValue result_value
;
816 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
817 transaction1
.Begin();
819 ScopedVector
<storage::BlobDataHandle
> handles
;
820 IndexedDBBackingStore::RecordIdentifier record
;
821 leveldb::Status s
= backing_store_
->PutRecord(&transaction1
,
823 KeyPrefix::kInvalidId
,
828 EXPECT_FALSE(s
.ok());
829 s
= backing_store_
->PutRecord(
830 &transaction1
, database_id
, 0, m_key1
, &m_value1
, &handles
, &record
);
831 EXPECT_FALSE(s
.ok());
832 s
= backing_store_
->PutRecord(&transaction1
,
833 KeyPrefix::kInvalidId
,
839 EXPECT_FALSE(s
.ok());
840 s
= backing_store_
->PutRecord(
841 &transaction1
, 0, object_store_id
, m_key1
, &m_value1
, &handles
, &record
);
842 EXPECT_FALSE(s
.ok());
844 s
= backing_store_
->GetRecord(
845 &transaction1
, database_id
, KeyPrefix::kInvalidId
, m_key1
, &result_value
);
846 EXPECT_FALSE(s
.ok());
847 s
= backing_store_
->GetRecord(
848 &transaction1
, database_id
, 0, m_key1
, &result_value
);
849 EXPECT_FALSE(s
.ok());
850 s
= backing_store_
->GetRecord(&transaction1
,
851 KeyPrefix::kInvalidId
,
855 EXPECT_FALSE(s
.ok());
856 s
= backing_store_
->GetRecord(
857 &transaction1
, 0, object_store_id
, m_key1
, &result_value
);
858 EXPECT_FALSE(s
.ok());
860 scoped_ptr
<IndexedDBKey
> new_primary_key
;
861 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
864 KeyPrefix::kInvalidId
,
867 EXPECT_FALSE(s
.ok());
868 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
871 invalid_low_index_id
,
874 EXPECT_FALSE(s
.ok());
875 s
= backing_store_
->GetPrimaryKeyViaIndex(
876 &transaction1
, database_id
, object_store_id
, 0, m_key1
, &new_primary_key
);
877 EXPECT_FALSE(s
.ok());
879 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
880 KeyPrefix::kInvalidId
,
885 EXPECT_FALSE(s
.ok());
886 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
888 KeyPrefix::kInvalidId
,
892 EXPECT_FALSE(s
.ok());
895 TEST_F(IndexedDBBackingStoreTest
, CreateDatabase
) {
896 const base::string16
database_name(ASCIIToUTF16("db1"));
898 const base::string16
version(ASCIIToUTF16("old_string_version"));
899 const int64 int_version
= 9;
901 const int64 object_store_id
= 99;
902 const base::string16
object_store_name(ASCIIToUTF16("object_store1"));
903 const bool auto_increment
= true;
904 const IndexedDBKeyPath
object_store_key_path(
905 ASCIIToUTF16("object_store_key"));
907 const int64 index_id
= 999;
908 const base::string16
index_name(ASCIIToUTF16("index1"));
909 const bool unique
= true;
910 const bool multi_entry
= true;
911 const IndexedDBKeyPath
index_key_path(ASCIIToUTF16("index_key"));
914 leveldb::Status s
= backing_store_
->CreateIDBDatabaseMetaData(
915 database_name
, version
, int_version
, &database_id
);
917 EXPECT_GT(database_id
, 0);
919 IndexedDBBackingStore::Transaction
transaction(backing_store_
.get());
922 s
= backing_store_
->CreateObjectStore(&transaction
,
926 object_store_key_path
,
930 s
= backing_store_
->CreateIndex(&transaction
,
940 scoped_refptr
<TestCallback
> callback(new TestCallback());
941 s
= transaction
.CommitPhaseOne(callback
);
943 EXPECT_TRUE(callback
->called
);
944 EXPECT_TRUE(callback
->succeeded
);
945 s
= transaction
.CommitPhaseTwo();
950 IndexedDBDatabaseMetadata database
;
952 leveldb::Status s
= backing_store_
->GetIDBDatabaseMetaData(
953 database_name
, &database
, &found
);
957 // database.name is not filled in by the implementation.
958 EXPECT_EQ(version
, database
.version
);
959 EXPECT_EQ(int_version
, database
.int_version
);
960 EXPECT_EQ(database_id
, database
.id
);
962 s
= backing_store_
->GetObjectStores(database
.id
, &database
.object_stores
);
965 EXPECT_EQ(1UL, database
.object_stores
.size());
966 IndexedDBObjectStoreMetadata object_store
=
967 database
.object_stores
[object_store_id
];
968 EXPECT_EQ(object_store_name
, object_store
.name
);
969 EXPECT_EQ(object_store_key_path
, object_store
.key_path
);
970 EXPECT_EQ(auto_increment
, object_store
.auto_increment
);
972 EXPECT_EQ(1UL, object_store
.indexes
.size());
973 IndexedDBIndexMetadata index
= object_store
.indexes
[index_id
];
974 EXPECT_EQ(index_name
, index
.name
);
975 EXPECT_EQ(index_key_path
, index
.key_path
);
976 EXPECT_EQ(unique
, index
.unique
);
977 EXPECT_EQ(multi_entry
, index
.multi_entry
);
981 TEST_F(IndexedDBBackingStoreTest
, GetDatabaseNames
) {
982 const base::string16
string_version(ASCIIToUTF16("string_version"));
984 const base::string16
db1_name(ASCIIToUTF16("db1"));
985 const int64 db1_version
= 1LL;
988 // Database records with DEFAULT_INT_VERSION represent stale data,
989 // and should not be enumerated.
990 const base::string16
db2_name(ASCIIToUTF16("db2"));
991 const int64 db2_version
= IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION
;
994 leveldb::Status s
= backing_store_
->CreateIDBDatabaseMetaData(
995 db1_name
, string_version
, db1_version
, &db1_id
);
997 EXPECT_GT(db1_id
, 0LL);
999 s
= backing_store_
->CreateIDBDatabaseMetaData(
1000 db2_name
, string_version
, db2_version
, &db2_id
);
1001 EXPECT_TRUE(s
.ok());
1002 EXPECT_GT(db2_id
, db1_id
);
1004 std::vector
<base::string16
> names
= backing_store_
->GetDatabaseNames(&s
);
1005 EXPECT_TRUE(s
.ok());
1006 EXPECT_EQ(names
.size(), 1ULL);
1007 EXPECT_EQ(names
[0], db1_name
);
1012 } // namespace content