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/strings/string16.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/task_runner.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 "net/url_request/url_request_test_util.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
25 #include "webkit/browser/blob/blob_data_handle.h"
26 #include "webkit/browser/quota/special_storage_policy.h"
28 using base::ASCIIToUTF16
;
34 class Comparator
: public LevelDBComparator
{
36 virtual int Compare(const base::StringPiece
& a
,
37 const base::StringPiece
& b
) const OVERRIDE
{
38 return content::Compare(a
, b
, false /*index_keys*/);
40 virtual const char* Name() const OVERRIDE
{ return "idb_cmp1"; }
43 class DefaultLevelDBFactory
: public LevelDBFactory
{
45 DefaultLevelDBFactory() {}
46 virtual leveldb::Status
OpenLevelDB(const base::FilePath
& file_name
,
47 const LevelDBComparator
* comparator
,
48 scoped_ptr
<LevelDBDatabase
>* db
,
49 bool* is_disk_full
) OVERRIDE
{
50 return LevelDBDatabase::Open(file_name
, comparator
, db
, is_disk_full
);
52 virtual leveldb::Status
DestroyLevelDB(
53 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::TaskRunner
* 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 virtual ~TestableIndexedDBBackingStore() {}
118 virtual bool WriteBlobFile(
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 virtual 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 virtual 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::TaskRunner
* 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 virtual ~TestIDBFactory() {}
205 virtual 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 virtual void SetUp() {
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(
238 temp_dir_
.path(), special_storage_policy_
, NULL
, task_runner_
);
239 idb_factory_
= new TestIDBFactory(idb_context_
);
241 idb_factory_
->OpenBackingStoreForTest(origin
, &url_request_context_
);
243 // useful keys and values during tests
244 m_value1
= IndexedDBValue("value1", std::vector
<IndexedDBBlobInfo
>());
245 m_value2
= IndexedDBValue("value2", std::vector
<IndexedDBBlobInfo
>());
247 m_blob_info
.push_back(
248 IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1));
249 m_blob_info
.push_back(
250 IndexedDBBlobInfo("uuid 4",
251 base::FilePath(FILE_PATH_LITERAL("path/to/file")),
252 base::UTF8ToUTF16("file name"),
253 base::UTF8ToUTF16("file type")));
254 m_value3
= IndexedDBValue("value3", m_blob_info
);
256 m_key1
= IndexedDBKey(99, blink::WebIDBKeyTypeNumber
);
257 m_key2
= IndexedDBKey(ASCIIToUTF16("key2"));
258 m_key3
= IndexedDBKey(ASCIIToUTF16("key3"));
261 // This just checks the data that survive getting stored and recalled, e.g.
262 // the file path and UUID will change and thus aren't verified.
263 bool CheckBlobInfoMatches(const std::vector
<IndexedDBBlobInfo
>& reads
) const {
264 if (m_blob_info
.size() != reads
.size())
266 for (size_t i
= 0; i
< m_blob_info
.size(); ++i
) {
267 const IndexedDBBlobInfo
& a
= m_blob_info
[i
];
268 const IndexedDBBlobInfo
& b
= reads
[i
];
269 if (a
.is_file() != b
.is_file())
271 if (a
.type() != b
.type())
274 if (a
.file_name() != b
.file_name())
277 if (a
.size() != b
.size())
284 bool CheckBlobReadsMatchWrites(
285 const std::vector
<IndexedDBBlobInfo
>& reads
) const {
286 if (backing_store_
->writes().size() != reads
.size())
289 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
)
290 ids
.insert(backing_store_
->writes()[i
].key());
291 if (ids
.size() != backing_store_
->writes().size())
293 for (size_t i
= 0; i
< reads
.size(); ++i
) {
294 if (ids
.count(reads
[i
].key()) != 1)
300 bool CheckBlobWrites() const {
301 if (backing_store_
->writes().size() != m_blob_info
.size())
303 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
) {
304 const IndexedDBBackingStore::Transaction::WriteDescriptor
& desc
=
305 backing_store_
->writes()[i
];
306 const IndexedDBBlobInfo
& info
= m_blob_info
[i
];
307 if (desc
.is_file() != info
.is_file())
309 if (desc
.is_file()) {
310 if (desc
.file_path() != info
.file_path())
313 if (desc
.url() != GURL("blob:uuid/" + info
.uuid()))
320 bool CheckBlobRemovals() const {
321 if (backing_store_
->removals().size() != backing_store_
->writes().size())
323 for (size_t i
= 0; i
< backing_store_
->writes().size(); ++i
) {
324 if (backing_store_
->writes()[i
].key() != backing_store_
->removals()[i
])
331 base::ScopedTempDir temp_dir_
;
332 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner_
;
333 scoped_refptr
<MockSpecialStoragePolicy
> special_storage_policy_
;
334 scoped_refptr
<IndexedDBContextImpl
> idb_context_
;
335 scoped_refptr
<TestIDBFactory
> idb_factory_
;
336 net::TestURLRequestContext url_request_context_
;
338 scoped_refptr
<TestableIndexedDBBackingStore
> backing_store_
;
340 // Sample keys and values that are consistent.
344 IndexedDBValue m_value1
;
345 IndexedDBValue m_value2
;
346 IndexedDBValue m_value3
;
347 std::vector
<IndexedDBBlobInfo
> m_blob_info
;
350 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest
);
353 class TestCallback
: public IndexedDBBackingStore::BlobWriteCallback
{
355 TestCallback() : called(false), succeeded(false) {}
356 virtual void Run(bool succeeded_in
) OVERRIDE
{
358 succeeded
= succeeded_in
;
364 virtual ~TestCallback() {}
367 DISALLOW_COPY_AND_ASSIGN(TestCallback
);
370 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistency
) {
372 IndexedDBBackingStore::Transaction
transaction1(backing_store_
);
373 transaction1
.Begin();
374 ScopedVector
<webkit_blob::BlobDataHandle
> handles
;
375 IndexedDBBackingStore::RecordIdentifier record
;
376 leveldb::Status s
= backing_store_
->PutRecord(
377 &transaction1
, 1, 1, m_key1
, &m_value1
, &handles
, &record
);
379 scoped_refptr
<TestCallback
> callback(new TestCallback());
380 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
381 EXPECT_TRUE(callback
->called
);
382 EXPECT_TRUE(callback
->succeeded
);
383 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
387 IndexedDBBackingStore::Transaction
transaction2(backing_store_
);
388 transaction2
.Begin();
389 IndexedDBValue result_value
;
391 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key1
, &result_value
)
393 scoped_refptr
<TestCallback
> callback(new TestCallback());
394 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
395 EXPECT_TRUE(callback
->called
);
396 EXPECT_TRUE(callback
->succeeded
);
397 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
398 EXPECT_EQ(m_value1
.bits
, result_value
.bits
);
402 TEST_F(IndexedDBBackingStoreTest
, PutGetConsistencyWithBlobs
) {
404 IndexedDBBackingStore::Transaction
transaction1(backing_store_
);
405 transaction1
.Begin();
406 ScopedVector
<webkit_blob::BlobDataHandle
> handles
;
407 IndexedDBBackingStore::RecordIdentifier record
;
408 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
415 scoped_refptr
<TestCallback
> callback(new TestCallback());
416 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
417 task_runner_
->RunUntilIdle();
418 EXPECT_TRUE(CheckBlobWrites());
419 EXPECT_TRUE(callback
->called
);
420 EXPECT_TRUE(callback
->succeeded
);
421 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
425 IndexedDBBackingStore::Transaction
transaction2(backing_store_
);
426 transaction2
.Begin();
427 IndexedDBValue result_value
;
429 backing_store_
->GetRecord(&transaction2
, 1, 1, m_key3
, &result_value
)
431 scoped_refptr
<TestCallback
> callback(new TestCallback());
432 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
433 EXPECT_TRUE(callback
->called
);
434 EXPECT_TRUE(callback
->succeeded
);
435 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
436 EXPECT_EQ(m_value3
.bits
, result_value
.bits
);
437 EXPECT_TRUE(CheckBlobInfoMatches(result_value
.blob_info
));
438 EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value
.blob_info
));
442 IndexedDBBackingStore::Transaction
transaction3(backing_store_
);
443 transaction3
.Begin();
444 IndexedDBValue result_value
;
445 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
448 IndexedDBKeyRange(m_key3
)).ok());
449 scoped_refptr
<TestCallback
> callback(new TestCallback());
450 EXPECT_TRUE(transaction3
.CommitPhaseOne(callback
).ok());
451 task_runner_
->RunUntilIdle();
452 EXPECT_TRUE(callback
->called
);
453 EXPECT_TRUE(callback
->succeeded
);
454 EXPECT_TRUE(transaction3
.CommitPhaseTwo().ok());
455 EXPECT_TRUE(CheckBlobRemovals());
459 TEST_F(IndexedDBBackingStoreTest
, DeleteRange
) {
460 IndexedDBKey key0
= IndexedDBKey(ASCIIToUTF16("key0"));
461 IndexedDBKey key1
= IndexedDBKey(ASCIIToUTF16("key1"));
462 IndexedDBKey key2
= IndexedDBKey(ASCIIToUTF16("key2"));
463 IndexedDBKey key3
= IndexedDBKey(ASCIIToUTF16("key3"));
464 IndexedDBBlobInfo
blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
465 IndexedDBBlobInfo
blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
466 IndexedDBBlobInfo
blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
467 IndexedDBBlobInfo
blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
468 IndexedDBKeyRange ranges
[] = {IndexedDBKeyRange(key1
, key2
, false, false),
469 IndexedDBKeyRange(key1
, key2
, false, false),
470 IndexedDBKeyRange(key0
, key2
, true, false),
471 IndexedDBKeyRange(key1
, key3
, false, true),
472 IndexedDBKeyRange(key0
, key3
, true, true)};
474 for (unsigned i
= 0; i
< sizeof(ranges
) / sizeof(IndexedDBKeyRange
); ++i
) {
475 backing_store_
->ClearWrites();
476 backing_store_
->ClearRemovals();
479 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
481 blob_info0
.push_back(blob0
);
482 blob_info1
.push_back(blob1
);
483 blob_info2
.push_back(blob2
);
484 blob_info3
.push_back(blob3
);
485 IndexedDBValue value0
= IndexedDBValue("value0", blob_info0
);
486 IndexedDBValue value1
= IndexedDBValue("value1", blob_info1
);
487 IndexedDBValue value2
= IndexedDBValue("value2", blob_info2
);
488 IndexedDBValue value3
= IndexedDBValue("value3", blob_info3
);
489 IndexedDBBackingStore::Transaction
transaction1(backing_store_
);
490 transaction1
.Begin();
491 ScopedVector
<webkit_blob::BlobDataHandle
> handles
;
492 IndexedDBBackingStore::RecordIdentifier record
;
493 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
500 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
507 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
514 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
521 scoped_refptr
<TestCallback
> callback(new TestCallback());
522 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
523 task_runner_
->RunUntilIdle();
524 EXPECT_TRUE(callback
->called
);
525 EXPECT_TRUE(callback
->succeeded
);
526 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
530 IndexedDBBackingStore::Transaction
transaction2(backing_store_
);
531 transaction2
.Begin();
532 IndexedDBValue result_value
;
534 backing_store_
->DeleteRange(&transaction2
, 1, i
+ 1, ranges
[i
]).ok());
535 scoped_refptr
<TestCallback
> callback(new TestCallback());
536 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
537 task_runner_
->RunUntilIdle();
538 EXPECT_TRUE(callback
->called
);
539 EXPECT_TRUE(callback
->succeeded
);
540 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
541 EXPECT_EQ(2UL, backing_store_
->removals().size());
542 EXPECT_EQ(backing_store_
->writes()[1].key(),
543 backing_store_
->removals()[0]);
544 EXPECT_EQ(backing_store_
->writes()[2].key(),
545 backing_store_
->removals()[1]);
550 TEST_F(IndexedDBBackingStoreTest
, DeleteRangeEmptyRange
) {
551 IndexedDBKey key0
= IndexedDBKey(ASCIIToUTF16("key0"));
552 IndexedDBKey key1
= IndexedDBKey(ASCIIToUTF16("key1"));
553 IndexedDBKey key2
= IndexedDBKey(ASCIIToUTF16("key2"));
554 IndexedDBKey key3
= IndexedDBKey(ASCIIToUTF16("key3"));
555 IndexedDBKey key4
= IndexedDBKey(ASCIIToUTF16("key4"));
556 IndexedDBBlobInfo
blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
557 IndexedDBBlobInfo
blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
558 IndexedDBBlobInfo
blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
559 IndexedDBBlobInfo
blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
560 IndexedDBKeyRange ranges
[] = {IndexedDBKeyRange(key3
, key4
, true, false),
561 IndexedDBKeyRange(key2
, key1
, false, false),
562 IndexedDBKeyRange(key2
, key1
, true, true)};
564 for (unsigned i
= 0; i
< arraysize(ranges
); ++i
) {
565 backing_store_
->ClearWrites();
566 backing_store_
->ClearRemovals();
569 std::vector
<IndexedDBBlobInfo
> blob_info0
, blob_info1
, blob_info2
,
571 blob_info0
.push_back(blob0
);
572 blob_info1
.push_back(blob1
);
573 blob_info2
.push_back(blob2
);
574 blob_info3
.push_back(blob3
);
575 IndexedDBValue value0
= IndexedDBValue("value0", blob_info0
);
576 IndexedDBValue value1
= IndexedDBValue("value1", blob_info1
);
577 IndexedDBValue value2
= IndexedDBValue("value2", blob_info2
);
578 IndexedDBValue value3
= IndexedDBValue("value3", blob_info3
);
579 IndexedDBBackingStore::Transaction
transaction1(backing_store_
);
580 transaction1
.Begin();
581 ScopedVector
<webkit_blob::BlobDataHandle
> handles
;
582 IndexedDBBackingStore::RecordIdentifier record
;
583 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
590 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
597 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
604 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
611 scoped_refptr
<TestCallback
> callback(new TestCallback());
612 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
613 task_runner_
->RunUntilIdle();
614 EXPECT_TRUE(callback
->called
);
615 EXPECT_TRUE(callback
->succeeded
);
616 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
620 IndexedDBBackingStore::Transaction
transaction2(backing_store_
);
621 transaction2
.Begin();
622 IndexedDBValue result_value
;
624 backing_store_
->DeleteRange(&transaction2
, 1, i
+ 1, ranges
[i
]).ok());
625 scoped_refptr
<TestCallback
> callback(new TestCallback());
626 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
627 task_runner_
->RunUntilIdle();
628 EXPECT_TRUE(callback
->called
);
629 EXPECT_TRUE(callback
->succeeded
);
630 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
631 EXPECT_EQ(0UL, backing_store_
->removals().size());
636 TEST_F(IndexedDBBackingStoreTest
, LiveBlobJournal
) {
638 IndexedDBBackingStore::Transaction
transaction1(backing_store_
);
639 transaction1
.Begin();
640 ScopedVector
<webkit_blob::BlobDataHandle
> handles
;
641 IndexedDBBackingStore::RecordIdentifier record
;
642 EXPECT_TRUE(backing_store_
->PutRecord(&transaction1
,
649 scoped_refptr
<TestCallback
> callback(new TestCallback());
650 EXPECT_TRUE(transaction1
.CommitPhaseOne(callback
).ok());
651 task_runner_
->RunUntilIdle();
652 EXPECT_TRUE(CheckBlobWrites());
653 EXPECT_TRUE(callback
->called
);
654 EXPECT_TRUE(callback
->succeeded
);
655 EXPECT_TRUE(transaction1
.CommitPhaseTwo().ok());
658 IndexedDBValue read_result_value
;
660 IndexedDBBackingStore::Transaction
transaction2(backing_store_
);
661 transaction2
.Begin();
663 backing_store_
->GetRecord(
664 &transaction2
, 1, 1, m_key3
, &read_result_value
)
666 scoped_refptr
<TestCallback
> callback(new TestCallback());
667 EXPECT_TRUE(transaction2
.CommitPhaseOne(callback
).ok());
668 EXPECT_TRUE(callback
->called
);
669 EXPECT_TRUE(callback
->succeeded
);
670 EXPECT_TRUE(transaction2
.CommitPhaseTwo().ok());
671 EXPECT_EQ(m_value3
.bits
, read_result_value
.bits
);
672 EXPECT_TRUE(CheckBlobInfoMatches(read_result_value
.blob_info
));
673 EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value
.blob_info
));
674 for (size_t i
= 0; i
< read_result_value
.blob_info
.size(); ++i
) {
675 read_result_value
.blob_info
[i
].mark_used_callback().Run();
680 IndexedDBBackingStore::Transaction
transaction3(backing_store_
);
681 transaction3
.Begin();
682 EXPECT_TRUE(backing_store_
->DeleteRange(&transaction3
,
685 IndexedDBKeyRange(m_key3
)).ok());
686 scoped_refptr
<TestCallback
> callback(new TestCallback());
687 EXPECT_TRUE(transaction3
.CommitPhaseOne(callback
).ok());
688 task_runner_
->RunUntilIdle();
689 EXPECT_TRUE(callback
->called
);
690 EXPECT_TRUE(callback
->succeeded
);
691 EXPECT_TRUE(transaction3
.CommitPhaseTwo().ok());
692 EXPECT_EQ(0U, backing_store_
->removals().size());
693 for (size_t i
= 0; i
< read_result_value
.blob_info
.size(); ++i
) {
694 read_result_value
.blob_info
[i
].release_callback().Run(
695 read_result_value
.blob_info
[i
].file_path());
697 task_runner_
->RunUntilIdle();
698 EXPECT_NE(0U, backing_store_
->removals().size());
699 EXPECT_TRUE(CheckBlobRemovals());
703 // Make sure that using very high ( more than 32 bit ) values for database_id
704 // and object_store_id still work.
705 TEST_F(IndexedDBBackingStoreTest
, HighIds
) {
706 const int64 high_database_id
= 1ULL << 35;
707 const int64 high_object_store_id
= 1ULL << 39;
708 // index_ids are capped at 32 bits for storage purposes.
709 const int64 high_index_id
= 1ULL << 29;
711 const int64 invalid_high_index_id
= 1ULL << 37;
713 const IndexedDBKey
& index_key
= m_key2
;
714 std::string index_key_raw
;
715 EncodeIDBKey(index_key
, &index_key_raw
);
717 IndexedDBBackingStore::Transaction
transaction1(backing_store_
);
718 transaction1
.Begin();
719 ScopedVector
<webkit_blob::BlobDataHandle
> handles
;
720 IndexedDBBackingStore::RecordIdentifier record
;
721 leveldb::Status s
= backing_store_
->PutRecord(&transaction1
,
723 high_object_store_id
,
730 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
732 high_object_store_id
,
733 invalid_high_index_id
,
736 EXPECT_FALSE(s
.ok());
738 s
= backing_store_
->PutIndexDataForRecord(&transaction1
,
740 high_object_store_id
,
746 scoped_refptr
<TestCallback
> callback(new TestCallback());
747 s
= transaction1
.CommitPhaseOne(callback
);
749 EXPECT_TRUE(callback
->called
);
750 EXPECT_TRUE(callback
->succeeded
);
751 s
= transaction1
.CommitPhaseTwo();
756 IndexedDBBackingStore::Transaction
transaction2(backing_store_
);
757 transaction2
.Begin();
758 IndexedDBValue result_value
;
759 leveldb::Status s
= backing_store_
->GetRecord(&transaction2
,
761 high_object_store_id
,
765 EXPECT_EQ(m_value1
.bits
, result_value
.bits
);
767 scoped_ptr
<IndexedDBKey
> new_primary_key
;
768 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
770 high_object_store_id
,
771 invalid_high_index_id
,
774 EXPECT_FALSE(s
.ok());
776 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction2
,
778 high_object_store_id
,
783 EXPECT_TRUE(new_primary_key
->Equals(m_key1
));
785 scoped_refptr
<TestCallback
> callback(new TestCallback());
786 s
= transaction2
.CommitPhaseOne(callback
);
788 EXPECT_TRUE(callback
->called
);
789 EXPECT_TRUE(callback
->succeeded
);
790 s
= transaction2
.CommitPhaseTwo();
795 // Make sure that other invalid ids do not crash.
796 TEST_F(IndexedDBBackingStoreTest
, InvalidIds
) {
797 // valid ids for use when testing invalid ids
798 const int64 database_id
= 1;
799 const int64 object_store_id
= 1;
800 const int64 index_id
= kMinimumIndexId
;
801 const int64 invalid_low_index_id
= 19; // index_ids must be > kMinimumIndexId
803 IndexedDBValue result_value
;
805 IndexedDBBackingStore::Transaction
transaction1(backing_store_
);
806 transaction1
.Begin();
808 ScopedVector
<webkit_blob::BlobDataHandle
> handles
;
809 IndexedDBBackingStore::RecordIdentifier record
;
810 leveldb::Status s
= backing_store_
->PutRecord(&transaction1
,
812 KeyPrefix::kInvalidId
,
817 EXPECT_FALSE(s
.ok());
818 s
= backing_store_
->PutRecord(
819 &transaction1
, database_id
, 0, m_key1
, &m_value1
, &handles
, &record
);
820 EXPECT_FALSE(s
.ok());
821 s
= backing_store_
->PutRecord(&transaction1
,
822 KeyPrefix::kInvalidId
,
828 EXPECT_FALSE(s
.ok());
829 s
= backing_store_
->PutRecord(
830 &transaction1
, 0, object_store_id
, m_key1
, &m_value1
, &handles
, &record
);
831 EXPECT_FALSE(s
.ok());
833 s
= backing_store_
->GetRecord(
834 &transaction1
, database_id
, KeyPrefix::kInvalidId
, m_key1
, &result_value
);
835 EXPECT_FALSE(s
.ok());
836 s
= backing_store_
->GetRecord(
837 &transaction1
, database_id
, 0, m_key1
, &result_value
);
838 EXPECT_FALSE(s
.ok());
839 s
= backing_store_
->GetRecord(&transaction1
,
840 KeyPrefix::kInvalidId
,
844 EXPECT_FALSE(s
.ok());
845 s
= backing_store_
->GetRecord(
846 &transaction1
, 0, object_store_id
, m_key1
, &result_value
);
847 EXPECT_FALSE(s
.ok());
849 scoped_ptr
<IndexedDBKey
> new_primary_key
;
850 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
853 KeyPrefix::kInvalidId
,
856 EXPECT_FALSE(s
.ok());
857 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
860 invalid_low_index_id
,
863 EXPECT_FALSE(s
.ok());
864 s
= backing_store_
->GetPrimaryKeyViaIndex(
865 &transaction1
, database_id
, object_store_id
, 0, m_key1
, &new_primary_key
);
866 EXPECT_FALSE(s
.ok());
868 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
869 KeyPrefix::kInvalidId
,
874 EXPECT_FALSE(s
.ok());
875 s
= backing_store_
->GetPrimaryKeyViaIndex(&transaction1
,
877 KeyPrefix::kInvalidId
,
881 EXPECT_FALSE(s
.ok());
884 TEST_F(IndexedDBBackingStoreTest
, CreateDatabase
) {
885 const base::string16
database_name(ASCIIToUTF16("db1"));
887 const base::string16
version(ASCIIToUTF16("old_string_version"));
888 const int64 int_version
= 9;
890 const int64 object_store_id
= 99;
891 const base::string16
object_store_name(ASCIIToUTF16("object_store1"));
892 const bool auto_increment
= true;
893 const IndexedDBKeyPath
object_store_key_path(
894 ASCIIToUTF16("object_store_key"));
896 const int64 index_id
= 999;
897 const base::string16
index_name(ASCIIToUTF16("index1"));
898 const bool unique
= true;
899 const bool multi_entry
= true;
900 const IndexedDBKeyPath
index_key_path(ASCIIToUTF16("index_key"));
903 leveldb::Status s
= backing_store_
->CreateIDBDatabaseMetaData(
904 database_name
, version
, int_version
, &database_id
);
906 EXPECT_GT(database_id
, 0);
908 IndexedDBBackingStore::Transaction
transaction(backing_store_
);
911 s
= backing_store_
->CreateObjectStore(&transaction
,
915 object_store_key_path
,
919 s
= backing_store_
->CreateIndex(&transaction
,
929 scoped_refptr
<TestCallback
> callback(new TestCallback());
930 s
= transaction
.CommitPhaseOne(callback
);
932 EXPECT_TRUE(callback
->called
);
933 EXPECT_TRUE(callback
->succeeded
);
934 s
= transaction
.CommitPhaseTwo();
939 IndexedDBDatabaseMetadata database
;
941 leveldb::Status s
= backing_store_
->GetIDBDatabaseMetaData(
942 database_name
, &database
, &found
);
946 // database.name is not filled in by the implementation.
947 EXPECT_EQ(version
, database
.version
);
948 EXPECT_EQ(int_version
, database
.int_version
);
949 EXPECT_EQ(database_id
, database
.id
);
951 s
= backing_store_
->GetObjectStores(database
.id
, &database
.object_stores
);
954 EXPECT_EQ(1UL, database
.object_stores
.size());
955 IndexedDBObjectStoreMetadata object_store
=
956 database
.object_stores
[object_store_id
];
957 EXPECT_EQ(object_store_name
, object_store
.name
);
958 EXPECT_EQ(object_store_key_path
, object_store
.key_path
);
959 EXPECT_EQ(auto_increment
, object_store
.auto_increment
);
961 EXPECT_EQ(1UL, object_store
.indexes
.size());
962 IndexedDBIndexMetadata index
= object_store
.indexes
[index_id
];
963 EXPECT_EQ(index_name
, index
.name
);
964 EXPECT_EQ(index_key_path
, index
.key_path
);
965 EXPECT_EQ(unique
, index
.unique
);
966 EXPECT_EQ(multi_entry
, index
.multi_entry
);
972 } // namespace content