Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_backing_store_unittest.cc
blob09f1fa2e039b7a043a0fdb4b0eb61e418ed2c865
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/indexed_db/indexed_db_backing_store.h"
7 #include "base/callback.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/test/test_simple_task_runner.h"
16 #include "content/browser/indexed_db/indexed_db_context_impl.h"
17 #include "content/browser/indexed_db/indexed_db_factory_impl.h"
18 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
19 #include "content/browser/indexed_db/indexed_db_value.h"
20 #include "content/browser/indexed_db/leveldb/leveldb_factory.h"
21 #include "content/public/test/mock_special_storage_policy.h"
22 #include "content/public/test/test_browser_thread_bundle.h"
23 #include "net/url_request/url_request_test_util.h"
24 #include "storage/browser/blob/blob_data_handle.h"
25 #include "storage/browser/quota/special_storage_policy.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBTypes.h"
29 using base::ASCIIToUTF16;
31 namespace content {
33 namespace {
35 class Comparator : public LevelDBComparator {
36 public:
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 {
45 public:
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);
57 private:
58 DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory);
61 class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
62 public:
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,
93 origin_url,
94 blob_path,
95 request_context,
96 db.Pass(),
97 comparator.Pass(),
98 task_runner));
100 *status = backing_store->SetUpMetadata();
101 if (!status->ok())
102 return scoped_refptr<TestableIndexedDBBackingStore>();
104 return backing_store;
107 const std::vector<IndexedDBBackingStore::Transaction::WriteDescriptor>&
108 writes() const {
109 return writes_;
111 void ClearWrites() { writes_.clear(); }
112 const std::vector<int64>& removals() const { return removals_; }
113 void ClearRemovals() { removals_.clear(); }
115 protected:
116 ~TestableIndexedDBBackingStore() override {}
118 bool WriteBlobFile(
119 int64 database_id,
120 const Transaction::WriteDescriptor& descriptor,
121 Transaction::ChainedBlobWriter* chained_blob_writer) override {
122 if (KeyPrefix::IsValidDatabaseId(database_id_)) {
123 if (database_id_ != database_id) {
124 return false;
126 } else {
127 database_id_ = database_id;
129 writes_.push_back(descriptor);
130 task_runner()->PostTask(
131 FROM_HERE,
132 base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion,
133 chained_blob_writer,
134 true,
135 1));
136 return true;
139 bool RemoveBlobFile(int64 database_id, int64 key) const override {
140 if (database_id_ != database_id ||
141 !KeyPrefix::IsValidDatabaseId(database_id)) {
142 return false;
144 removals_.push_back(key);
145 return true;
148 // Timers don't play nicely with unit tests.
149 void StartJournalCleaningTimer() override {
150 CleanPrimaryJournalIgnoreReturn();
153 private:
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,
162 origin_url,
163 blob_path,
164 request_context,
165 db.Pass(),
166 comparator.Pass(),
167 task_runner),
168 database_id_(0) {}
170 int64 database_id_;
171 std::vector<Transaction::WriteDescriptor> writes_;
173 // This is modified in an overridden virtual function that is properly const
174 // in the real implementation, therefore must be mutable here.
175 mutable std::vector<int64> removals_;
177 DISALLOW_COPY_AND_ASSIGN(TestableIndexedDBBackingStore);
180 class TestIDBFactory : public IndexedDBFactoryImpl {
181 public:
182 explicit TestIDBFactory(IndexedDBContextImpl* idb_context)
183 : IndexedDBFactoryImpl(idb_context) {}
185 scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest(
186 const GURL& origin,
187 net::URLRequestContext* url_request_context) {
188 blink::WebIDBDataLoss data_loss;
189 std::string data_loss_reason;
190 bool disk_full;
191 leveldb::Status status;
192 scoped_refptr<IndexedDBBackingStore> backing_store =
193 OpenBackingStore(origin,
194 context()->data_path(),
195 url_request_context,
196 &data_loss,
197 &data_loss_reason,
198 &disk_full,
199 &status);
200 scoped_refptr<TestableIndexedDBBackingStore> testable_store =
201 static_cast<TestableIndexedDBBackingStore*>(backing_store.get());
202 return testable_store;
205 protected:
206 ~TestIDBFactory() override {}
208 scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper(
209 const GURL& origin_url,
210 const base::FilePath& data_directory,
211 net::URLRequestContext* request_context,
212 blink::WebIDBDataLoss* data_loss,
213 std::string* data_loss_message,
214 bool* disk_full,
215 bool first_time,
216 leveldb::Status* status) override {
217 DefaultLevelDBFactory leveldb_factory;
218 return TestableIndexedDBBackingStore::Open(this,
219 origin_url,
220 data_directory,
221 request_context,
222 &leveldb_factory,
223 context()->TaskRunner(),
224 status);
227 private:
228 DISALLOW_COPY_AND_ASSIGN(TestIDBFactory);
231 class IndexedDBBackingStoreTest : public testing::Test {
232 public:
233 IndexedDBBackingStoreTest() {}
234 void SetUp() override {
235 const GURL origin("http://localhost:81");
236 task_runner_ = new base::TestSimpleTaskRunner();
237 special_storage_policy_ = new MockSpecialStoragePolicy();
238 special_storage_policy_->SetAllUnlimited(true);
239 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
240 idb_context_ = new IndexedDBContextImpl(temp_dir_.path(),
241 special_storage_policy_.get(),
242 NULL,
243 task_runner_.get());
244 idb_factory_ = new TestIDBFactory(idb_context_.get());
245 backing_store_ =
246 idb_factory_->OpenBackingStoreForTest(origin, &url_request_context_);
248 // useful keys and values during tests
249 m_value1 = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>());
250 m_value2 = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>());
252 m_blob_info.push_back(
253 IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1));
254 m_blob_info.push_back(
255 IndexedDBBlobInfo("uuid 4",
256 base::FilePath(FILE_PATH_LITERAL("path/to/file")),
257 base::UTF8ToUTF16("file name"),
258 base::UTF8ToUTF16("file type")));
259 m_blob_info.push_back(
260 IndexedDBBlobInfo("uuid 5",
261 base::FilePath(),
262 base::UTF8ToUTF16("file name"),
263 base::UTF8ToUTF16("file type")));
264 m_value3 = IndexedDBValue("value3", m_blob_info);
266 m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber);
267 m_key2 = IndexedDBKey(ASCIIToUTF16("key2"));
268 m_key3 = IndexedDBKey(ASCIIToUTF16("key3"));
271 // This just checks the data that survive getting stored and recalled, e.g.
272 // the file path and UUID will change and thus aren't verified.
273 bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const {
274 if (m_blob_info.size() != reads.size())
275 return false;
276 for (size_t i = 0; i < m_blob_info.size(); ++i) {
277 const IndexedDBBlobInfo& a = m_blob_info[i];
278 const IndexedDBBlobInfo& b = reads[i];
279 if (a.is_file() != b.is_file())
280 return false;
281 if (a.type() != b.type())
282 return false;
283 if (a.is_file()) {
284 if (a.file_name() != b.file_name())
285 return false;
286 } else {
287 if (a.size() != b.size())
288 return false;
291 return true;
294 bool CheckBlobReadsMatchWrites(
295 const std::vector<IndexedDBBlobInfo>& reads) const {
296 if (backing_store_->writes().size() != reads.size())
297 return false;
298 std::set<int64> ids;
299 for (size_t i = 0; i < backing_store_->writes().size(); ++i)
300 ids.insert(backing_store_->writes()[i].key());
301 if (ids.size() != backing_store_->writes().size())
302 return false;
303 for (size_t i = 0; i < reads.size(); ++i) {
304 if (ids.count(reads[i].key()) != 1)
305 return false;
307 return true;
310 bool CheckBlobWrites() const {
311 if (backing_store_->writes().size() != m_blob_info.size())
312 return false;
313 for (size_t i = 0; i < backing_store_->writes().size(); ++i) {
314 const IndexedDBBackingStore::Transaction::WriteDescriptor& desc =
315 backing_store_->writes()[i];
316 const IndexedDBBlobInfo& info = m_blob_info[i];
317 if (desc.is_file() != info.is_file()) {
318 if (!info.is_file() || !info.file_path().empty())
319 return false;
320 } else if (desc.is_file()) {
321 if (desc.file_path() != info.file_path())
322 return false;
323 } else {
324 if (desc.url() != GURL("blob:uuid/" + info.uuid()))
325 return false;
328 return true;
331 bool CheckBlobRemovals() const {
332 if (backing_store_->removals().size() != backing_store_->writes().size())
333 return false;
334 for (size_t i = 0; i < backing_store_->writes().size(); ++i) {
335 if (backing_store_->writes()[i].key() != backing_store_->removals()[i])
336 return false;
338 return true;
341 protected:
342 // Must be initialized before url_request_context_
343 content::TestBrowserThreadBundle thread_bundle_;
345 base::ScopedTempDir temp_dir_;
346 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
347 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
348 scoped_refptr<IndexedDBContextImpl> idb_context_;
349 scoped_refptr<TestIDBFactory> idb_factory_;
350 net::TestURLRequestContext url_request_context_;
352 scoped_refptr<TestableIndexedDBBackingStore> backing_store_;
354 // Sample keys and values that are consistent.
355 IndexedDBKey m_key1;
356 IndexedDBKey m_key2;
357 IndexedDBKey m_key3;
358 IndexedDBValue m_value1;
359 IndexedDBValue m_value2;
360 IndexedDBValue m_value3;
361 std::vector<IndexedDBBlobInfo> m_blob_info;
363 private:
364 DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest);
367 class TestCallback : public IndexedDBBackingStore::BlobWriteCallback {
368 public:
369 TestCallback() : called(false), succeeded(false) {}
370 void Run(bool succeeded_in) override {
371 called = true;
372 succeeded = succeeded_in;
374 bool called;
375 bool succeeded;
377 protected:
378 ~TestCallback() override {}
380 private:
381 DISALLOW_COPY_AND_ASSIGN(TestCallback);
384 TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
386 IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
387 transaction1.Begin();
388 ScopedVector<storage::BlobDataHandle> handles;
389 IndexedDBBackingStore::RecordIdentifier record;
390 leveldb::Status s = backing_store_->PutRecord(
391 &transaction1, 1, 1, m_key1, &m_value1, &handles, &record);
392 EXPECT_TRUE(s.ok());
393 scoped_refptr<TestCallback> callback(new TestCallback());
394 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
395 EXPECT_TRUE(callback->called);
396 EXPECT_TRUE(callback->succeeded);
397 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
401 IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
402 transaction2.Begin();
403 IndexedDBValue result_value;
404 EXPECT_TRUE(
405 backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value)
406 .ok());
407 scoped_refptr<TestCallback> callback(new TestCallback());
408 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
409 EXPECT_TRUE(callback->called);
410 EXPECT_TRUE(callback->succeeded);
411 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
412 EXPECT_EQ(m_value1.bits, result_value.bits);
416 TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) {
418 IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
419 transaction1.Begin();
420 ScopedVector<storage::BlobDataHandle> handles;
421 IndexedDBBackingStore::RecordIdentifier record;
422 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
425 m_key3,
426 &m_value3,
427 &handles,
428 &record).ok());
429 scoped_refptr<TestCallback> callback(new TestCallback());
430 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
431 task_runner_->RunUntilIdle();
432 EXPECT_TRUE(CheckBlobWrites());
433 EXPECT_TRUE(callback->called);
434 EXPECT_TRUE(callback->succeeded);
435 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
439 IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
440 transaction2.Begin();
441 IndexedDBValue result_value;
442 EXPECT_TRUE(
443 backing_store_->GetRecord(&transaction2, 1, 1, m_key3, &result_value)
444 .ok());
445 scoped_refptr<TestCallback> callback(new TestCallback());
446 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
447 EXPECT_TRUE(callback->called);
448 EXPECT_TRUE(callback->succeeded);
449 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
450 EXPECT_EQ(m_value3.bits, result_value.bits);
451 EXPECT_TRUE(CheckBlobInfoMatches(result_value.blob_info));
452 EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value.blob_info));
456 IndexedDBBackingStore::Transaction transaction3(backing_store_.get());
457 transaction3.Begin();
458 IndexedDBValue result_value;
459 EXPECT_TRUE(backing_store_->DeleteRange(&transaction3,
462 IndexedDBKeyRange(m_key3)).ok());
463 scoped_refptr<TestCallback> callback(new TestCallback());
464 EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok());
465 task_runner_->RunUntilIdle();
466 EXPECT_TRUE(callback->called);
467 EXPECT_TRUE(callback->succeeded);
468 EXPECT_TRUE(transaction3.CommitPhaseTwo().ok());
469 EXPECT_TRUE(CheckBlobRemovals());
473 TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
474 IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0"));
475 IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1"));
476 IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2"));
477 IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3"));
478 IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
479 IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
480 IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
481 IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
482 IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key1, key2, false, false),
483 IndexedDBKeyRange(key1, key2, false, false),
484 IndexedDBKeyRange(key0, key2, true, false),
485 IndexedDBKeyRange(key1, key3, false, true),
486 IndexedDBKeyRange(key0, key3, true, true)};
488 for (unsigned i = 0; i < sizeof(ranges) / sizeof(IndexedDBKeyRange); ++i) {
489 backing_store_->ClearWrites();
490 backing_store_->ClearRemovals();
493 std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2,
494 blob_info3;
495 blob_info0.push_back(blob0);
496 blob_info1.push_back(blob1);
497 blob_info2.push_back(blob2);
498 blob_info3.push_back(blob3);
499 IndexedDBValue value0 = IndexedDBValue("value0", blob_info0);
500 IndexedDBValue value1 = IndexedDBValue("value1", blob_info1);
501 IndexedDBValue value2 = IndexedDBValue("value2", blob_info2);
502 IndexedDBValue value3 = IndexedDBValue("value3", blob_info3);
503 IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
504 transaction1.Begin();
505 ScopedVector<storage::BlobDataHandle> handles;
506 IndexedDBBackingStore::RecordIdentifier record;
507 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
509 i + 1,
510 key0,
511 &value0,
512 &handles,
513 &record).ok());
514 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
516 i + 1,
517 key1,
518 &value1,
519 &handles,
520 &record).ok());
521 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
523 i + 1,
524 key2,
525 &value2,
526 &handles,
527 &record).ok());
528 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
530 i + 1,
531 key3,
532 &value3,
533 &handles,
534 &record).ok());
535 scoped_refptr<TestCallback> callback(new TestCallback());
536 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
537 task_runner_->RunUntilIdle();
538 EXPECT_TRUE(callback->called);
539 EXPECT_TRUE(callback->succeeded);
540 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
544 IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
545 transaction2.Begin();
546 IndexedDBValue result_value;
547 EXPECT_TRUE(
548 backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok());
549 scoped_refptr<TestCallback> callback(new TestCallback());
550 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
551 task_runner_->RunUntilIdle();
552 EXPECT_TRUE(callback->called);
553 EXPECT_TRUE(callback->succeeded);
554 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
555 EXPECT_EQ(2UL, backing_store_->removals().size());
556 EXPECT_EQ(backing_store_->writes()[1].key(),
557 backing_store_->removals()[0]);
558 EXPECT_EQ(backing_store_->writes()[2].key(),
559 backing_store_->removals()[1]);
564 TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
565 IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0"));
566 IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1"));
567 IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2"));
568 IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3"));
569 IndexedDBKey key4 = IndexedDBKey(ASCIIToUTF16("key4"));
570 IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
571 IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
572 IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
573 IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
574 IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key3, key4, true, false),
575 IndexedDBKeyRange(key2, key1, false, false),
576 IndexedDBKeyRange(key2, key1, true, true)};
578 for (unsigned i = 0; i < arraysize(ranges); ++i) {
579 backing_store_->ClearWrites();
580 backing_store_->ClearRemovals();
583 std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2,
584 blob_info3;
585 blob_info0.push_back(blob0);
586 blob_info1.push_back(blob1);
587 blob_info2.push_back(blob2);
588 blob_info3.push_back(blob3);
589 IndexedDBValue value0 = IndexedDBValue("value0", blob_info0);
590 IndexedDBValue value1 = IndexedDBValue("value1", blob_info1);
591 IndexedDBValue value2 = IndexedDBValue("value2", blob_info2);
592 IndexedDBValue value3 = IndexedDBValue("value3", blob_info3);
593 IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
594 transaction1.Begin();
595 ScopedVector<storage::BlobDataHandle> handles;
596 IndexedDBBackingStore::RecordIdentifier record;
597 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
599 i + 1,
600 key0,
601 &value0,
602 &handles,
603 &record).ok());
604 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
606 i + 1,
607 key1,
608 &value1,
609 &handles,
610 &record).ok());
611 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
613 i + 1,
614 key2,
615 &value2,
616 &handles,
617 &record).ok());
618 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
620 i + 1,
621 key3,
622 &value3,
623 &handles,
624 &record).ok());
625 scoped_refptr<TestCallback> callback(new TestCallback());
626 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
627 task_runner_->RunUntilIdle();
628 EXPECT_TRUE(callback->called);
629 EXPECT_TRUE(callback->succeeded);
630 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
634 IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
635 transaction2.Begin();
636 IndexedDBValue result_value;
637 EXPECT_TRUE(
638 backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok());
639 scoped_refptr<TestCallback> callback(new TestCallback());
640 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
641 task_runner_->RunUntilIdle();
642 EXPECT_TRUE(callback->called);
643 EXPECT_TRUE(callback->succeeded);
644 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
645 EXPECT_EQ(0UL, backing_store_->removals().size());
650 TEST_F(IndexedDBBackingStoreTest, BlobJournalInterleavedTransactions) {
651 IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
652 transaction1.Begin();
653 ScopedVector<storage::BlobDataHandle> handles1;
654 IndexedDBBackingStore::RecordIdentifier record1;
655 EXPECT_TRUE(backing_store_->PutRecord(&transaction1, 1, 1, m_key3, &m_value3,
656 &handles1, &record1).ok());
657 scoped_refptr<TestCallback> callback1(new TestCallback());
658 EXPECT_TRUE(transaction1.CommitPhaseOne(callback1).ok());
659 task_runner_->RunUntilIdle();
660 EXPECT_TRUE(CheckBlobWrites());
661 EXPECT_TRUE(callback1->called);
662 EXPECT_TRUE(callback1->succeeded);
663 EXPECT_EQ(0U, backing_store_->removals().size());
665 IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
666 transaction2.Begin();
667 ScopedVector<storage::BlobDataHandle> handles2;
668 IndexedDBBackingStore::RecordIdentifier record2;
669 EXPECT_TRUE(backing_store_->PutRecord(&transaction2, 1, 1, m_key1, &m_value1,
670 &handles2, &record2).ok());
671 scoped_refptr<TestCallback> callback2(new TestCallback());
672 EXPECT_TRUE(transaction2.CommitPhaseOne(callback2).ok());
673 task_runner_->RunUntilIdle();
674 EXPECT_TRUE(CheckBlobWrites());
675 EXPECT_TRUE(callback2->called);
676 EXPECT_TRUE(callback2->succeeded);
677 EXPECT_EQ(0U, backing_store_->removals().size());
679 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
680 EXPECT_EQ(0U, backing_store_->removals().size());
682 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
683 EXPECT_EQ(0U, backing_store_->removals().size());
686 TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) {
688 IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
689 transaction1.Begin();
690 ScopedVector<storage::BlobDataHandle> handles;
691 IndexedDBBackingStore::RecordIdentifier record;
692 EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
695 m_key3,
696 &m_value3,
697 &handles,
698 &record).ok());
699 scoped_refptr<TestCallback> callback(new TestCallback());
700 EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
701 task_runner_->RunUntilIdle();
702 EXPECT_TRUE(CheckBlobWrites());
703 EXPECT_TRUE(callback->called);
704 EXPECT_TRUE(callback->succeeded);
705 EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
708 IndexedDBValue read_result_value;
710 IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
711 transaction2.Begin();
712 EXPECT_TRUE(
713 backing_store_->GetRecord(
714 &transaction2, 1, 1, m_key3, &read_result_value)
715 .ok());
716 scoped_refptr<TestCallback> callback(new TestCallback());
717 EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
718 EXPECT_TRUE(callback->called);
719 EXPECT_TRUE(callback->succeeded);
720 EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
721 EXPECT_EQ(m_value3.bits, read_result_value.bits);
722 EXPECT_TRUE(CheckBlobInfoMatches(read_result_value.blob_info));
723 EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value.blob_info));
724 for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) {
725 read_result_value.blob_info[i].mark_used_callback().Run();
730 IndexedDBBackingStore::Transaction transaction3(backing_store_.get());
731 transaction3.Begin();
732 EXPECT_TRUE(backing_store_->DeleteRange(&transaction3,
735 IndexedDBKeyRange(m_key3)).ok());
736 scoped_refptr<TestCallback> callback(new TestCallback());
737 EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok());
738 task_runner_->RunUntilIdle();
739 EXPECT_TRUE(callback->called);
740 EXPECT_TRUE(callback->succeeded);
741 EXPECT_TRUE(transaction3.CommitPhaseTwo().ok());
742 EXPECT_EQ(0U, backing_store_->removals().size());
743 for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) {
744 read_result_value.blob_info[i].release_callback().Run(
745 read_result_value.blob_info[i].file_path());
747 task_runner_->RunUntilIdle();
748 EXPECT_NE(0U, backing_store_->removals().size());
749 EXPECT_TRUE(CheckBlobRemovals());
753 // Make sure that using very high ( more than 32 bit ) values for database_id
754 // and object_store_id still work.
755 TEST_F(IndexedDBBackingStoreTest, HighIds) {
756 const int64 high_database_id = 1ULL << 35;
757 const int64 high_object_store_id = 1ULL << 39;
758 // index_ids are capped at 32 bits for storage purposes.
759 const int64 high_index_id = 1ULL << 29;
761 const int64 invalid_high_index_id = 1ULL << 37;
763 const IndexedDBKey& index_key = m_key2;
764 std::string index_key_raw;
765 EncodeIDBKey(index_key, &index_key_raw);
767 IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
768 transaction1.Begin();
769 ScopedVector<storage::BlobDataHandle> handles;
770 IndexedDBBackingStore::RecordIdentifier record;
771 leveldb::Status s = backing_store_->PutRecord(&transaction1,
772 high_database_id,
773 high_object_store_id,
774 m_key1,
775 &m_value1,
776 &handles,
777 &record);
778 EXPECT_TRUE(s.ok());
780 s = backing_store_->PutIndexDataForRecord(&transaction1,
781 high_database_id,
782 high_object_store_id,
783 invalid_high_index_id,
784 index_key,
785 record);
786 EXPECT_FALSE(s.ok());
788 s = backing_store_->PutIndexDataForRecord(&transaction1,
789 high_database_id,
790 high_object_store_id,
791 high_index_id,
792 index_key,
793 record);
794 EXPECT_TRUE(s.ok());
796 scoped_refptr<TestCallback> callback(new TestCallback());
797 s = transaction1.CommitPhaseOne(callback);
798 EXPECT_TRUE(s.ok());
799 EXPECT_TRUE(callback->called);
800 EXPECT_TRUE(callback->succeeded);
801 s = transaction1.CommitPhaseTwo();
802 EXPECT_TRUE(s.ok());
806 IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
807 transaction2.Begin();
808 IndexedDBValue result_value;
809 leveldb::Status s = backing_store_->GetRecord(&transaction2,
810 high_database_id,
811 high_object_store_id,
812 m_key1,
813 &result_value);
814 EXPECT_TRUE(s.ok());
815 EXPECT_EQ(m_value1.bits, result_value.bits);
817 scoped_ptr<IndexedDBKey> new_primary_key;
818 s = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
819 high_database_id,
820 high_object_store_id,
821 invalid_high_index_id,
822 index_key,
823 &new_primary_key);
824 EXPECT_FALSE(s.ok());
826 s = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
827 high_database_id,
828 high_object_store_id,
829 high_index_id,
830 index_key,
831 &new_primary_key);
832 EXPECT_TRUE(s.ok());
833 EXPECT_TRUE(new_primary_key->Equals(m_key1));
835 scoped_refptr<TestCallback> callback(new TestCallback());
836 s = transaction2.CommitPhaseOne(callback);
837 EXPECT_TRUE(s.ok());
838 EXPECT_TRUE(callback->called);
839 EXPECT_TRUE(callback->succeeded);
840 s = transaction2.CommitPhaseTwo();
841 EXPECT_TRUE(s.ok());
845 // Make sure that other invalid ids do not crash.
846 TEST_F(IndexedDBBackingStoreTest, InvalidIds) {
847 // valid ids for use when testing invalid ids
848 const int64 database_id = 1;
849 const int64 object_store_id = 1;
850 const int64 index_id = kMinimumIndexId;
851 const int64 invalid_low_index_id = 19; // index_ids must be > kMinimumIndexId
853 IndexedDBValue result_value;
855 IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
856 transaction1.Begin();
858 ScopedVector<storage::BlobDataHandle> handles;
859 IndexedDBBackingStore::RecordIdentifier record;
860 leveldb::Status s = backing_store_->PutRecord(&transaction1,
861 database_id,
862 KeyPrefix::kInvalidId,
863 m_key1,
864 &m_value1,
865 &handles,
866 &record);
867 EXPECT_FALSE(s.ok());
868 s = backing_store_->PutRecord(
869 &transaction1, database_id, 0, m_key1, &m_value1, &handles, &record);
870 EXPECT_FALSE(s.ok());
871 s = backing_store_->PutRecord(&transaction1,
872 KeyPrefix::kInvalidId,
873 object_store_id,
874 m_key1,
875 &m_value1,
876 &handles,
877 &record);
878 EXPECT_FALSE(s.ok());
879 s = backing_store_->PutRecord(
880 &transaction1, 0, object_store_id, m_key1, &m_value1, &handles, &record);
881 EXPECT_FALSE(s.ok());
883 s = backing_store_->GetRecord(
884 &transaction1, database_id, KeyPrefix::kInvalidId, m_key1, &result_value);
885 EXPECT_FALSE(s.ok());
886 s = backing_store_->GetRecord(
887 &transaction1, database_id, 0, m_key1, &result_value);
888 EXPECT_FALSE(s.ok());
889 s = backing_store_->GetRecord(&transaction1,
890 KeyPrefix::kInvalidId,
891 object_store_id,
892 m_key1,
893 &result_value);
894 EXPECT_FALSE(s.ok());
895 s = backing_store_->GetRecord(
896 &transaction1, 0, object_store_id, m_key1, &result_value);
897 EXPECT_FALSE(s.ok());
899 scoped_ptr<IndexedDBKey> new_primary_key;
900 s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
901 database_id,
902 object_store_id,
903 KeyPrefix::kInvalidId,
904 m_key1,
905 &new_primary_key);
906 EXPECT_FALSE(s.ok());
907 s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
908 database_id,
909 object_store_id,
910 invalid_low_index_id,
911 m_key1,
912 &new_primary_key);
913 EXPECT_FALSE(s.ok());
914 s = backing_store_->GetPrimaryKeyViaIndex(
915 &transaction1, database_id, object_store_id, 0, m_key1, &new_primary_key);
916 EXPECT_FALSE(s.ok());
918 s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
919 KeyPrefix::kInvalidId,
920 object_store_id,
921 index_id,
922 m_key1,
923 &new_primary_key);
924 EXPECT_FALSE(s.ok());
925 s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
926 database_id,
927 KeyPrefix::kInvalidId,
928 index_id,
929 m_key1,
930 &new_primary_key);
931 EXPECT_FALSE(s.ok());
934 TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
935 const base::string16 database_name(ASCIIToUTF16("db1"));
936 int64 database_id;
937 const base::string16 version(ASCIIToUTF16("old_string_version"));
938 const int64 int_version = 9;
940 const int64 object_store_id = 99;
941 const base::string16 object_store_name(ASCIIToUTF16("object_store1"));
942 const bool auto_increment = true;
943 const IndexedDBKeyPath object_store_key_path(
944 ASCIIToUTF16("object_store_key"));
946 const int64 index_id = 999;
947 const base::string16 index_name(ASCIIToUTF16("index1"));
948 const bool unique = true;
949 const bool multi_entry = true;
950 const IndexedDBKeyPath index_key_path(ASCIIToUTF16("index_key"));
953 leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
954 database_name, version, int_version, &database_id);
955 EXPECT_TRUE(s.ok());
956 EXPECT_GT(database_id, 0);
958 IndexedDBBackingStore::Transaction transaction(backing_store_.get());
959 transaction.Begin();
961 s = backing_store_->CreateObjectStore(&transaction,
962 database_id,
963 object_store_id,
964 object_store_name,
965 object_store_key_path,
966 auto_increment);
967 EXPECT_TRUE(s.ok());
969 s = backing_store_->CreateIndex(&transaction,
970 database_id,
971 object_store_id,
972 index_id,
973 index_name,
974 index_key_path,
975 unique,
976 multi_entry);
977 EXPECT_TRUE(s.ok());
979 scoped_refptr<TestCallback> callback(new TestCallback());
980 s = transaction.CommitPhaseOne(callback);
981 EXPECT_TRUE(s.ok());
982 EXPECT_TRUE(callback->called);
983 EXPECT_TRUE(callback->succeeded);
984 s = transaction.CommitPhaseTwo();
985 EXPECT_TRUE(s.ok());
989 IndexedDBDatabaseMetadata database;
990 bool found;
991 leveldb::Status s = backing_store_->GetIDBDatabaseMetaData(
992 database_name, &database, &found);
993 EXPECT_TRUE(s.ok());
994 EXPECT_TRUE(found);
996 // database.name is not filled in by the implementation.
997 EXPECT_EQ(version, database.version);
998 EXPECT_EQ(int_version, database.int_version);
999 EXPECT_EQ(database_id, database.id);
1001 s = backing_store_->GetObjectStores(database.id, &database.object_stores);
1002 EXPECT_TRUE(s.ok());
1004 EXPECT_EQ(1UL, database.object_stores.size());
1005 IndexedDBObjectStoreMetadata object_store =
1006 database.object_stores[object_store_id];
1007 EXPECT_EQ(object_store_name, object_store.name);
1008 EXPECT_EQ(object_store_key_path, object_store.key_path);
1009 EXPECT_EQ(auto_increment, object_store.auto_increment);
1011 EXPECT_EQ(1UL, object_store.indexes.size());
1012 IndexedDBIndexMetadata index = object_store.indexes[index_id];
1013 EXPECT_EQ(index_name, index.name);
1014 EXPECT_EQ(index_key_path, index.key_path);
1015 EXPECT_EQ(unique, index.unique);
1016 EXPECT_EQ(multi_entry, index.multi_entry);
1020 TEST_F(IndexedDBBackingStoreTest, GetDatabaseNames) {
1021 const base::string16 string_version(ASCIIToUTF16("string_version"));
1023 const base::string16 db1_name(ASCIIToUTF16("db1"));
1024 const int64 db1_version = 1LL;
1025 int64 db1_id;
1027 // Database records with DEFAULT_INT_VERSION represent stale data,
1028 // and should not be enumerated.
1029 const base::string16 db2_name(ASCIIToUTF16("db2"));
1030 const int64 db2_version = IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION;
1031 int64 db2_id;
1033 leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
1034 db1_name, string_version, db1_version, &db1_id);
1035 EXPECT_TRUE(s.ok());
1036 EXPECT_GT(db1_id, 0LL);
1038 s = backing_store_->CreateIDBDatabaseMetaData(
1039 db2_name, string_version, db2_version, &db2_id);
1040 EXPECT_TRUE(s.ok());
1041 EXPECT_GT(db2_id, db1_id);
1043 std::vector<base::string16> names = backing_store_->GetDatabaseNames(&s);
1044 EXPECT_TRUE(s.ok());
1045 EXPECT_EQ(names.size(), 1ULL);
1046 EXPECT_EQ(names[0], db1_name);
1049 } // namespace
1051 } // namespace content