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/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 "testing/gtest/include/gtest/gtest.h"
25 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
26 #include "webkit/browser/blob/blob_data_handle.h"
27 #include "webkit/browser/quota/special_storage_policy.h"
29 using base::ASCIIToUTF16
;
35 class Comparator
: public LevelDBComparator
{
37 virtual int Compare(const base::StringPiece
& a
,
38 const base::StringPiece
& b
) const OVERRIDE
{
39 return content::Compare(a
, b
, false /*index_keys*/);
41 virtual const char* Name() const OVERRIDE
{ return "idb_cmp1"; }
44 class DefaultLevelDBFactory
: public LevelDBFactory
{
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
);
53 virtual leveldb::Status
DestroyLevelDB(
54 const base::FilePath
& file_name
) OVERRIDE
{
55 return LevelDBDatabase::Destroy(file_name
);
59 DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory
);
62 class TestableIndexedDBBackingStore
: public IndexedDBBackingStore
{
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());
74 scoped_ptr
<LevelDBComparator
> comparator(new Comparator());
76 if (!base::CreateDirectory(path_base
)) {
77 *status
= leveldb::Status::IOError("Unable to create base dir");
78 return scoped_refptr
<TestableIndexedDBBackingStore
>();
81 const base::FilePath file_path
= path_base
.AppendASCII("test_db_path");
82 const base::FilePath blob_path
= path_base
.AppendASCII("test_blob_path");
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
);
89 if (!db
|| !status
->ok())
90 return scoped_refptr
<TestableIndexedDBBackingStore
>();
92 scoped_refptr
<TestableIndexedDBBackingStore
> backing_store(
93 new TestableIndexedDBBackingStore(indexed_db_factory
,
101 *status
= backing_store
->SetUpMetadata();
103 return scoped_refptr
<TestableIndexedDBBackingStore
>();
105 return backing_store
;
108 const std::vector
<IndexedDBBackingStore::Transaction::WriteDescriptor
>&
112 void ClearWrites() { writes_
.clear(); }
113 const std::vector
<int64
>& removals() const { return removals_
; }
114 void ClearRemovals() { removals_
.clear(); }
117 virtual ~TestableIndexedDBBackingStore() {}
119 virtual bool WriteBlobFile(
121 const Transaction::WriteDescriptor
& descriptor
,
122 Transaction::ChainedBlobWriter
* chained_blob_writer
) OVERRIDE
{
123 if (KeyPrefix::IsValidDatabaseId(database_id_
)) {
124 if (database_id_
!= database_id
) {
128 database_id_
= database_id
;
130 writes_
.push_back(descriptor
);
131 task_runner()->PostTask(
133 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion
,
140 virtual bool RemoveBlobFile(int64 database_id
, int64 key
) OVERRIDE
{
141 if (database_id_
!= database_id
||
142 !KeyPrefix::IsValidDatabaseId(database_id
)) {
145 removals_
.push_back(key
);
149 // Timers don't play nicely with unit tests.
150 virtual void StartJournalCleaningTimer() OVERRIDE
{
151 CleanPrimaryJournalIgnoreReturn();
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
,
172 std::vector
<Transaction::WriteDescriptor
> writes_
;
173 std::vector
<int64
> removals_
;
175 DISALLOW_COPY_AND_ASSIGN(TestableIndexedDBBackingStore
);
178 class TestIDBFactory
: public IndexedDBFactoryImpl
{
180 explicit TestIDBFactory(IndexedDBContextImpl
* idb_context
)
181 : IndexedDBFactoryImpl(idb_context
) {}
183 scoped_refptr
<TestableIndexedDBBackingStore
> OpenBackingStoreForTest(
185 net::URLRequestContext
* url_request_context
) {
186 blink::WebIDBDataLoss data_loss
;
187 std::string data_loss_reason
;
189 leveldb::Status status
;
190 scoped_refptr
<IndexedDBBackingStore
> backing_store
=
191 OpenBackingStore(origin
,
192 context()->data_path(),
198 scoped_refptr
<TestableIndexedDBBackingStore
> testable_store
=
199 static_cast<TestableIndexedDBBackingStore
*>(backing_store
.get());
200 return testable_store
;
204 virtual ~TestIDBFactory() {}
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
,
214 leveldb::Status
* status
) OVERRIDE
{
215 DefaultLevelDBFactory leveldb_factory
;
216 return TestableIndexedDBBackingStore::Open(this,
221 context()->TaskRunner(),
226 DISALLOW_COPY_AND_ASSIGN(TestIDBFactory
);
229 class IndexedDBBackingStoreTest
: public testing::Test
{
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(),
242 idb_factory_
= new TestIDBFactory(idb_context_
.get());
244 idb_factory_
->OpenBackingStoreForTest(origin
, &url_request_context_
);
246 // useful keys and values during tests
247 m_value1
= IndexedDBValue("value1", std::vector
<IndexedDBBlobInfo
>());
248 m_value2
= IndexedDBValue("value2", std::vector
<IndexedDBBlobInfo
>());
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
);
259 m_key1
= IndexedDBKey(99, blink::WebIDBKeyTypeNumber
);
260 m_key2
= IndexedDBKey(ASCIIToUTF16("key2"));
261 m_key3
= IndexedDBKey(ASCIIToUTF16("key3"));
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())
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())
274 if (a
.type() != b
.type())
277 if (a
.file_name() != b
.file_name())
280 if (a
.size() != b
.size())
287 bool CheckBlobReadsMatchWrites(
288 const std::vector
<IndexedDBBlobInfo
>& reads
) const {
289 if (backing_store_
->writes().size() != reads
.size())
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())
296 for (size_t i
= 0; i
< reads
.size(); ++i
) {
297 if (ids
.count(reads
[i
].key()) != 1)
303 bool CheckBlobWrites() const {
304 if (backing_store_
->writes().size() != m_blob_info
.size())
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())
312 if (desc
.is_file()) {
313 if (desc
.file_path() != info
.file_path())
316 if (desc
.url() != GURL("blob:uuid/" + info
.uuid()))
323 bool CheckBlobRemovals() const {
324 if (backing_store_
->removals().size() != backing_store_
->writes().size())
326 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
) {
327 if (backing_store_
->writes()[i
].key() != backing_store_
->removals()[i
])
334 // Must be initialized before url_request_context_
335 content::TestBrowserThreadBundle thread_bundle_
;
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_
;
344 scoped_refptr
<TestableIndexedDBBackingStore
> backing_store_
;
346 // Sample keys and values that are consistent.
350 IndexedDBValue m_value1
;
351 IndexedDBValue m_value2
;
352 IndexedDBValue m_value3
;
353 std::vector
<IndexedDBBlobInfo
> m_blob_info
;
356 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest
);
359 class TestCallback
: public IndexedDBBackingStore::BlobWriteCallback
{
361 TestCallback() : called(false), succeeded(false) {}
362 virtual void Run(bool succeeded_in
) OVERRIDE
{
364 succeeded
= succeeded_in
;
370 virtual ~TestCallback() {}
373 DISALLOW_COPY_AND_ASSIGN(TestCallback
);
376 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistency
) {
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
);
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());
393 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
394 transaction2
.Begin();
395 IndexedDBValue result_value
;
397 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key1
, &result_value
)
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
);
408 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistencyWithBlobs
) {
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
,
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());
431 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
432 transaction2
.Begin();
433 IndexedDBValue result_value
;
435 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key3
, &result_value
)
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
));
448 IndexedDBBackingStore::Transaction
transaction3(backing_store_
.get());
449 transaction3
.Begin();
450 IndexedDBValue result_value
;
451 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
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());
465 TEST_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)};
480 for (unsigned i
= 0; i
< sizeof(ranges
) / sizeof(IndexedDBKeyRange
); ++i
) {
481 backing_store_
->ClearWrites();
482 backing_store_
->ClearRemovals();
485 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
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
,
506 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
513 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
520 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
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());
536 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
537 transaction2
.Begin();
538 IndexedDBValue result_value
;
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]);
556 TEST_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)};
570 for (unsigned i
= 0; i
< arraysize(ranges
); ++i
) {
571 backing_store_
->ClearWrites();
572 backing_store_
->ClearRemovals();
575 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
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
,
596 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
603 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
610 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
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());
626 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
627 transaction2
.Begin();
628 IndexedDBValue result_value
;
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());
642 TEST_F(IndexedDBBackingStoreTest
, LiveBlobJournal
) {
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
,
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());
664 IndexedDBValue read_result_value
;
666 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
667 transaction2
.Begin();
669 backing_store_
->GetRecord(
670 &transaction2
, 1, 1, m_key3
, &read_result_value
)
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();
686 IndexedDBBackingStore::Transaction
transaction3(backing_store_
.get());
687 transaction3
.Begin();
688 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
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());
703 task_runner_
->RunUntilIdle();
704 EXPECT_NE(0U, backing_store_
->removals().size());
705 EXPECT_TRUE(CheckBlobRemovals());
709 // Make sure that using very high ( more than 32 bit ) values for database_id
710 // and object_store_id still work.
711 TEST_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;
717 const int64 invalid_high_index_id
= 1ULL << 37;
719 const IndexedDBKey
& index_key
= m_key2
;
720 std::string index_key_raw
;
721 EncodeIDBKey(index_key
, &index_key_raw
);
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
,
729 high_object_store_id
,
736 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
738 high_object_store_id
,
739 invalid_high_index_id
,
742 EXPECT_FALSE(s
.ok());
744 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
746 high_object_store_id
,
752 scoped_refptr
<TestCallback
> callback(new TestCallback());
753 s
= transaction1
.CommitPhaseOne(callback
);
755 EXPECT_TRUE(callback
->called
);
756 EXPECT_TRUE(callback
->succeeded
);
757 s
= transaction1
.CommitPhaseTwo();
762 IndexedDBBackingStore::Transaction
transaction2(backing_store_
.get());
763 transaction2
.Begin();
764 IndexedDBValue result_value
;
765 leveldb::Status s
= backing_store_
->GetRecord(&transaction2
,
767 high_object_store_id
,
771 EXPECT_EQ(m_value1
.bits
, result_value
.bits
);
773 scoped_ptr
<IndexedDBKey
> new_primary_key
;
774 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
776 high_object_store_id
,
777 invalid_high_index_id
,
780 EXPECT_FALSE(s
.ok());
782 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
784 high_object_store_id
,
789 EXPECT_TRUE(new_primary_key
->Equals(m_key1
));
791 scoped_refptr
<TestCallback
> callback(new TestCallback());
792 s
= transaction2
.CommitPhaseOne(callback
);
794 EXPECT_TRUE(callback
->called
);
795 EXPECT_TRUE(callback
->succeeded
);
796 s
= transaction2
.CommitPhaseTwo();
801 // Make sure that other invalid ids do not crash.
802 TEST_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
809 IndexedDBValue result_value
;
811 IndexedDBBackingStore::Transaction
transaction1(backing_store_
.get());
812 transaction1
.Begin();
814 ScopedVector
<storage::BlobDataHandle
> handles
;
815 IndexedDBBackingStore::RecordIdentifier record
;
816 leveldb::Status s
= backing_store_
->PutRecord(&transaction1
,
818 KeyPrefix::kInvalidId
,
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
,
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());
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
,
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());
855 scoped_ptr
<IndexedDBKey
> new_primary_key
;
856 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
859 KeyPrefix::kInvalidId
,
862 EXPECT_FALSE(s
.ok());
863 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
866 invalid_low_index_id
,
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());
874 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
875 KeyPrefix::kInvalidId
,
880 EXPECT_FALSE(s
.ok());
881 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
883 KeyPrefix::kInvalidId
,
887 EXPECT_FALSE(s
.ok());
890 TEST_F(IndexedDBBackingStoreTest
, CreateDatabase
) {
891 const base::string16
database_name(ASCIIToUTF16("db1"));
893 const base::string16
version(ASCIIToUTF16("old_string_version"));
894 const int64 int_version
= 9;
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"));
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"));
909 leveldb::Status s
= backing_store_
->CreateIDBDatabaseMetaData(
910 database_name
, version
, int_version
, &database_id
);
912 EXPECT_GT(database_id
, 0);
914 IndexedDBBackingStore::Transaction
transaction(backing_store_
.get());
917 s
= backing_store_
->CreateObjectStore(&transaction
,
921 object_store_key_path
,
925 s
= backing_store_
->CreateIndex(&transaction
,
935 scoped_refptr
<TestCallback
> callback(new TestCallback());
936 s
= transaction
.CommitPhaseOne(callback
);
938 EXPECT_TRUE(callback
->called
);
939 EXPECT_TRUE(callback
->succeeded
);
940 s
= transaction
.CommitPhaseTwo();
945 IndexedDBDatabaseMetadata database
;
947 leveldb::Status s
= backing_store_
->GetIDBDatabaseMetaData(
948 database_name
, &database
, &found
);
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
);
957 s
= backing_store_
->GetObjectStores(database
.id
, &database
.object_stores
);
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
);
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
);
976 TEST_F(IndexedDBBackingStoreTest
, GetDatabaseNames
) {
977 const base::string16
string_version(ASCIIToUTF16("string_version"));
979 const base::string16
db1_name(ASCIIToUTF16("db1"));
980 const int64 db1_version
= 1LL;
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
;
989 leveldb::Status s
= backing_store_
->CreateIDBDatabaseMetaData(
990 db1_name
, string_version
, db1_version
, &db1_id
);
992 EXPECT_GT(db1_id
, 0LL);
994 s
= backing_store_
->CreateIDBDatabaseMetaData(
995 db2_name
, string_version
, db2_version
, &db2_id
);
997 EXPECT_GT(db2_id
, db1_id
);
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
);
1007 } // namespace content