Home | History | Annotate | Download | only in indexed_db
      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.
      4 
      5 #include "content/browser/indexed_db/indexed_db_backing_store.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/files/file_util.h"
      9 #include "base/files/scoped_temp_dir.h"
     10 #include "base/logging.h"
     11 #include "base/macros.h"
     12 #include "base/sequenced_task_runner.h"
     13 #include "base/strings/string16.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/test/test_simple_task_runner.h"
     16 #include "content/browser/indexed_db/indexed_db_context_impl.h"
     17 #include "content/browser/indexed_db/indexed_db_factory_impl.h"
     18 #include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
     19 #include "content/browser/indexed_db/indexed_db_value.h"
     20 #include "content/browser/indexed_db/leveldb/leveldb_factory.h"
     21 #include "content/public/test/mock_special_storage_policy.h"
     22 #include "content/public/test/test_browser_thread_bundle.h"
     23 #include "net/url_request/url_request_test_util.h"
     24 #include "storage/browser/blob/blob_data_handle.h"
     25 #include "storage/browser/quota/special_storage_policy.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
     28 
     29 using base::ASCIIToUTF16;
     30 
     31 namespace content {
     32 
     33 namespace {
     34 
     35 class Comparator : public LevelDBComparator {
     36  public:
     37   virtual int Compare(const base::StringPiece& a,
     38                       const base::StringPiece& b) const OVERRIDE {
     39     return content::Compare(a, b, false /*index_keys*/);
     40   }
     41   virtual const char* Name() const OVERRIDE { return "idb_cmp1"; }
     42 };
     43 
     44 class DefaultLevelDBFactory : public LevelDBFactory {
     45  public:
     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);
     52   }
     53   virtual leveldb::Status DestroyLevelDB(
     54       const base::FilePath& file_name) OVERRIDE {
     55     return LevelDBDatabase::Destroy(file_name);
     56   }
     57 
     58  private:
     59   DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory);
     60 };
     61 
     62 class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
     63  public:
     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());
     73 
     74     scoped_ptr<LevelDBComparator> comparator(new Comparator());
     75 
     76     if (!base::CreateDirectory(path_base)) {
     77       *status = leveldb::Status::IOError("Unable to create base dir");
     78       return scoped_refptr<TestableIndexedDBBackingStore>();
     79     }
     80 
     81     const base::FilePath file_path = path_base.AppendASCII("test_db_path");
     82     const base::FilePath blob_path = path_base.AppendASCII("test_blob_path");
     83 
     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);
     88 
     89     if (!db || !status->ok())
     90       return scoped_refptr<TestableIndexedDBBackingStore>();
     91 
     92     scoped_refptr<TestableIndexedDBBackingStore> backing_store(
     93         new TestableIndexedDBBackingStore(indexed_db_factory,
     94                                           origin_url,
     95                                           blob_path,
     96                                           request_context,
     97                                           db.Pass(),
     98                                           comparator.Pass(),
     99                                           task_runner));
    100 
    101     *status = backing_store->SetUpMetadata();
    102     if (!status->ok())
    103       return scoped_refptr<TestableIndexedDBBackingStore>();
    104 
    105     return backing_store;
    106   }
    107 
    108   const std::vector<IndexedDBBackingStore::Transaction::WriteDescriptor>&
    109   writes() const {
    110     return writes_;
    111   }
    112   void ClearWrites() { writes_.clear(); }
    113   const std::vector<int64>& removals() const { return removals_; }
    114   void ClearRemovals() { removals_.clear(); }
    115 
    116  protected:
    117   virtual ~TestableIndexedDBBackingStore() {}
    118 
    119   virtual bool WriteBlobFile(
    120       int64 database_id,
    121       const Transaction::WriteDescriptor& descriptor,
    122       Transaction::ChainedBlobWriter* chained_blob_writer) OVERRIDE {
    123     if (KeyPrefix::IsValidDatabaseId(database_id_)) {
    124       if (database_id_ != database_id) {
    125         return false;
    126       }
    127     } else {
    128       database_id_ = database_id;
    129     }
    130     writes_.push_back(descriptor);
    131     task_runner()->PostTask(
    132         FROM_HERE,
    133         base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion,
    134                    chained_blob_writer,
    135                    true,
    136                    1));
    137     return true;
    138   }
    139 
    140   virtual bool RemoveBlobFile(int64 database_id, int64 key) OVERRIDE {
    141     if (database_id_ != database_id ||
    142         !KeyPrefix::IsValidDatabaseId(database_id)) {
    143       return false;
    144     }
    145     removals_.push_back(key);
    146     return true;
    147   }
    148 
    149   // Timers don't play nicely with unit tests.
    150   virtual void StartJournalCleaningTimer() OVERRIDE {
    151     CleanPrimaryJournalIgnoreReturn();
    152   }
    153 
    154  private:
    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,
    163                               origin_url,
    164                               blob_path,
    165                               request_context,
    166                               db.Pass(),
    167                               comparator.Pass(),
    168                               task_runner),
    169         database_id_(0) {}
    170 
    171   int64 database_id_;
    172   std::vector<Transaction::WriteDescriptor> writes_;
    173   std::vector<int64> removals_;
    174 
    175   DISALLOW_COPY_AND_ASSIGN(TestableIndexedDBBackingStore);
    176 };
    177 
    178 class TestIDBFactory : public IndexedDBFactoryImpl {
    179  public:
    180   explicit TestIDBFactory(IndexedDBContextImpl* idb_context)
    181       : IndexedDBFactoryImpl(idb_context) {}
    182 
    183   scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest(
    184       const GURL& origin,
    185       net::URLRequestContext* url_request_context) {
    186     blink::WebIDBDataLoss data_loss;
    187     std::string data_loss_reason;
    188     bool disk_full;
    189     leveldb::Status status;
    190     scoped_refptr<IndexedDBBackingStore> backing_store =
    191         OpenBackingStore(origin,
    192                          context()->data_path(),
    193                          url_request_context,
    194                          &data_loss,
    195                          &data_loss_reason,
    196                          &disk_full,
    197                          &status);
    198     scoped_refptr<TestableIndexedDBBackingStore> testable_store =
    199         static_cast<TestableIndexedDBBackingStore*>(backing_store.get());
    200     return testable_store;
    201   }
    202 
    203  protected:
    204   virtual ~TestIDBFactory() {}
    205 
    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,
    212       bool* disk_full,
    213       bool first_time,
    214       leveldb::Status* status) OVERRIDE {
    215     DefaultLevelDBFactory leveldb_factory;
    216     return TestableIndexedDBBackingStore::Open(this,
    217                                                origin_url,
    218                                                data_directory,
    219                                                request_context,
    220                                                &leveldb_factory,
    221                                                context()->TaskRunner(),
    222                                                status);
    223   }
    224 
    225  private:
    226   DISALLOW_COPY_AND_ASSIGN(TestIDBFactory);
    227 };
    228 
    229 class IndexedDBBackingStoreTest : public testing::Test {
    230  public:
    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(),
    240                                             NULL,
    241                                             task_runner_.get());
    242     idb_factory_ = new TestIDBFactory(idb_context_.get());
    243     backing_store_ =
    244         idb_factory_->OpenBackingStoreForTest(origin, &url_request_context_);
    245 
    246     // useful keys and values during tests
    247     m_value1 = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>());
    248     m_value2 = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>());
    249 
    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);
    258 
    259     m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber);
    260     m_key2 = IndexedDBKey(ASCIIToUTF16("key2"));
    261     m_key3 = IndexedDBKey(ASCIIToUTF16("key3"));
    262   }
    263 
    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())
    268       return false;
    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())
    273         return false;
    274       if (a.type() != b.type())
    275         return false;
    276       if (a.is_file()) {
    277         if (a.file_name() != b.file_name())
    278           return false;
    279       } else {
    280         if (a.size() != b.size())
    281           return false;
    282       }
    283     }
    284     return true;
    285   }
    286 
    287   bool CheckBlobReadsMatchWrites(
    288       const std::vector<IndexedDBBlobInfo>& reads) const {
    289     if (backing_store_->writes().size() != reads.size())
    290       return false;
    291     std::set<int64> ids;
    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())
    295       return false;
    296     for (size_t i = 0; i < reads.size(); ++i) {
    297       if (ids.count(reads[i].key()) != 1)
    298         return false;
    299     }
    300     return true;
    301   }
    302 
    303   bool CheckBlobWrites() const {
    304     if (backing_store_->writes().size() != m_blob_info.size())
    305       return false;
    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())
    311         return false;
    312       if (desc.is_file()) {
    313         if (desc.file_path() != info.file_path())
    314           return false;
    315       } else {
    316         if (desc.url() != GURL("blob:uuid/" + info.uuid()))
    317           return false;
    318       }
    319     }
    320     return true;
    321   }
    322 
    323   bool CheckBlobRemovals() const {
    324     if (backing_store_->removals().size() != backing_store_->writes().size())
    325       return false;
    326     for (size_t i = 0; i < backing_store_->writes().size(); ++i) {
    327       if (backing_store_->writes()[i].key() != backing_store_->removals()[i])
    328         return false;
    329     }
    330     return true;
    331   }
    332 
    333  protected:
    334   // Must be initialized before url_request_context_
    335   content::TestBrowserThreadBundle thread_bundle_;
    336 
    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_;
    343 
    344   scoped_refptr<TestableIndexedDBBackingStore> backing_store_;
    345 
    346   // Sample keys and values that are consistent.
    347   IndexedDBKey m_key1;
    348   IndexedDBKey m_key2;
    349   IndexedDBKey m_key3;
    350   IndexedDBValue m_value1;
    351   IndexedDBValue m_value2;
    352   IndexedDBValue m_value3;
    353   std::vector<IndexedDBBlobInfo> m_blob_info;
    354 
    355  private:
    356   DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest);
    357 };
    358 
    359 class TestCallback : public IndexedDBBackingStore::BlobWriteCallback {
    360  public:
    361   TestCallback() : called(false), succeeded(false) {}
    362   virtual void Run(bool succeeded_in) OVERRIDE {
    363     called = true;
    364     succeeded = succeeded_in;
    365   }
    366   bool called;
    367   bool succeeded;
    368 
    369  protected:
    370   virtual ~TestCallback() {}
    371 
    372  private:
    373   DISALLOW_COPY_AND_ASSIGN(TestCallback);
    374 };
    375 
    376 TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
    377   {
    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);
    384     EXPECT_TRUE(s.ok());
    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());
    390   }
    391 
    392   {
    393     IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
    394     transaction2.Begin();
    395     IndexedDBValue result_value;
    396     EXPECT_TRUE(
    397         backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value)
    398             .ok());
    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);
    405   }
    406 }
    407 
    408 TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) {
    409   {
    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,
    415                                           1,
    416                                           1,
    417                                           m_key3,
    418                                           &m_value3,
    419                                           &handles,
    420                                           &record).ok());
    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());
    428   }
    429 
    430   {
    431     IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
    432     transaction2.Begin();
    433     IndexedDBValue result_value;
    434     EXPECT_TRUE(
    435         backing_store_->GetRecord(&transaction2, 1, 1, m_key3, &result_value)
    436             .ok());
    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));
    445   }
    446 
    447   {
    448     IndexedDBBackingStore::Transaction transaction3(backing_store_.get());
    449     transaction3.Begin();
    450     IndexedDBValue result_value;
    451     EXPECT_TRUE(backing_store_->DeleteRange(&transaction3,
    452                                             1,
    453                                             1,
    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());
    462   }
    463 }
    464 
    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)};
    479 
    480   for (unsigned i = 0; i < sizeof(ranges) / sizeof(IndexedDBKeyRange); ++i) {
    481     backing_store_->ClearWrites();
    482     backing_store_->ClearRemovals();
    483 
    484     {
    485       std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2,
    486           blob_info3;
    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,
    500                                             1,
    501                                             i + 1,
    502                                             key0,
    503                                             &value0,
    504                                             &handles,
    505                                             &record).ok());
    506       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    507                                             1,
    508                                             i + 1,
    509                                             key1,
    510                                             &value1,
    511                                             &handles,
    512                                             &record).ok());
    513       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    514                                             1,
    515                                             i + 1,
    516                                             key2,
    517                                             &value2,
    518                                             &handles,
    519                                             &record).ok());
    520       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    521                                             1,
    522                                             i + 1,
    523                                             key3,
    524                                             &value3,
    525                                             &handles,
    526                                             &record).ok());
    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());
    533     }
    534 
    535     {
    536       IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
    537       transaction2.Begin();
    538       IndexedDBValue result_value;
    539       EXPECT_TRUE(
    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]);
    552     }
    553   }
    554 }
    555 
    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)};
    569 
    570   for (unsigned i = 0; i < arraysize(ranges); ++i) {
    571     backing_store_->ClearWrites();
    572     backing_store_->ClearRemovals();
    573 
    574     {
    575       std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2,
    576           blob_info3;
    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,
    590                                             1,
    591                                             i + 1,
    592                                             key0,
    593                                             &value0,
    594                                             &handles,
    595                                             &record).ok());
    596       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    597                                             1,
    598                                             i + 1,
    599                                             key1,
    600                                             &value1,
    601                                             &handles,
    602                                             &record).ok());
    603       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    604                                             1,
    605                                             i + 1,
    606                                             key2,
    607                                             &value2,
    608                                             &handles,
    609                                             &record).ok());
    610       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    611                                             1,
    612                                             i + 1,
    613                                             key3,
    614                                             &value3,
    615                                             &handles,
    616                                             &record).ok());
    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());
    623     }
    624 
    625     {
    626       IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
    627       transaction2.Begin();
    628       IndexedDBValue result_value;
    629       EXPECT_TRUE(
    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());
    638     }
    639   }
    640 }
    641 
    642 TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) {
    643   {
    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,
    649                                           1,
    650                                           1,
    651                                           m_key3,
    652                                           &m_value3,
    653                                           &handles,
    654                                           &record).ok());
    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());
    662   }
    663 
    664   IndexedDBValue read_result_value;
    665   {
    666     IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
    667     transaction2.Begin();
    668     EXPECT_TRUE(
    669         backing_store_->GetRecord(
    670                             &transaction2, 1, 1, m_key3, &read_result_value)
    671             .ok());
    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();
    682     }
    683   }
    684 
    685   {
    686     IndexedDBBackingStore::Transaction transaction3(backing_store_.get());
    687     transaction3.Begin();
    688     EXPECT_TRUE(backing_store_->DeleteRange(&transaction3,
    689                                             1,
    690                                             1,
    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());
    702     }
    703     task_runner_->RunUntilIdle();
    704     EXPECT_NE(0U, backing_store_->removals().size());
    705     EXPECT_TRUE(CheckBlobRemovals());
    706   }
    707 }
    708 
    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;
    716 
    717   const int64 invalid_high_index_id = 1ULL << 37;
    718 
    719   const IndexedDBKey& index_key = m_key2;
    720   std::string index_key_raw;
    721   EncodeIDBKey(index_key, &index_key_raw);
    722   {
    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,
    728                                                   high_database_id,
    729                                                   high_object_store_id,
    730                                                   m_key1,
    731                                                   &m_value1,
    732                                                   &handles,
    733                                                   &record);
    734     EXPECT_TRUE(s.ok());
    735 
    736     s = backing_store_->PutIndexDataForRecord(&transaction1,
    737                                               high_database_id,
    738                                               high_object_store_id,
    739                                               invalid_high_index_id,
    740                                               index_key,
    741                                               record);
    742     EXPECT_FALSE(s.ok());
    743 
    744     s = backing_store_->PutIndexDataForRecord(&transaction1,
    745                                               high_database_id,
    746                                               high_object_store_id,
    747                                               high_index_id,
    748                                               index_key,
    749                                               record);
    750     EXPECT_TRUE(s.ok());
    751 
    752     scoped_refptr<TestCallback> callback(new TestCallback());
    753     s = transaction1.CommitPhaseOne(callback);
    754     EXPECT_TRUE(s.ok());
    755     EXPECT_TRUE(callback->called);
    756     EXPECT_TRUE(callback->succeeded);
    757     s = transaction1.CommitPhaseTwo();
    758     EXPECT_TRUE(s.ok());
    759   }
    760 
    761   {
    762     IndexedDBBackingStore::Transaction transaction2(backing_store_.get());
    763     transaction2.Begin();
    764     IndexedDBValue result_value;
    765     leveldb::Status s = backing_store_->GetRecord(&transaction2,
    766                                                   high_database_id,
    767                                                   high_object_store_id,
    768                                                   m_key1,
    769                                                   &result_value);
    770     EXPECT_TRUE(s.ok());
    771     EXPECT_EQ(m_value1.bits, result_value.bits);
    772 
    773     scoped_ptr<IndexedDBKey> new_primary_key;
    774     s = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
    775                                               high_database_id,
    776                                               high_object_store_id,
    777                                               invalid_high_index_id,
    778                                               index_key,
    779                                               &new_primary_key);
    780     EXPECT_FALSE(s.ok());
    781 
    782     s = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
    783                                               high_database_id,
    784                                               high_object_store_id,
    785                                               high_index_id,
    786                                               index_key,
    787                                               &new_primary_key);
    788     EXPECT_TRUE(s.ok());
    789     EXPECT_TRUE(new_primary_key->Equals(m_key1));
    790 
    791     scoped_refptr<TestCallback> callback(new TestCallback());
    792     s = transaction2.CommitPhaseOne(callback);
    793     EXPECT_TRUE(s.ok());
    794     EXPECT_TRUE(callback->called);
    795     EXPECT_TRUE(callback->succeeded);
    796     s = transaction2.CommitPhaseTwo();
    797     EXPECT_TRUE(s.ok());
    798   }
    799 }
    800 
    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
    808 
    809   IndexedDBValue result_value;
    810 
    811   IndexedDBBackingStore::Transaction transaction1(backing_store_.get());
    812   transaction1.Begin();
    813 
    814   ScopedVector<storage::BlobDataHandle> handles;
    815   IndexedDBBackingStore::RecordIdentifier record;
    816   leveldb::Status s = backing_store_->PutRecord(&transaction1,
    817                                                 database_id,
    818                                                 KeyPrefix::kInvalidId,
    819                                                 m_key1,
    820                                                 &m_value1,
    821                                                 &handles,
    822                                                 &record);
    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,
    829                                 object_store_id,
    830                                 m_key1,
    831                                 &m_value1,
    832                                 &handles,
    833                                 &record);
    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());
    838 
    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,
    847                                 object_store_id,
    848                                 m_key1,
    849                                 &result_value);
    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());
    854 
    855   scoped_ptr<IndexedDBKey> new_primary_key;
    856   s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
    857                                             database_id,
    858                                             object_store_id,
    859                                             KeyPrefix::kInvalidId,
    860                                             m_key1,
    861                                             &new_primary_key);
    862   EXPECT_FALSE(s.ok());
    863   s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
    864                                             database_id,
    865                                             object_store_id,
    866                                             invalid_low_index_id,
    867                                             m_key1,
    868                                             &new_primary_key);
    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());
    873 
    874   s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
    875                                             KeyPrefix::kInvalidId,
    876                                             object_store_id,
    877                                             index_id,
    878                                             m_key1,
    879                                             &new_primary_key);
    880   EXPECT_FALSE(s.ok());
    881   s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
    882                                             database_id,
    883                                             KeyPrefix::kInvalidId,
    884                                             index_id,
    885                                             m_key1,
    886                                             &new_primary_key);
    887   EXPECT_FALSE(s.ok());
    888 }
    889 
    890 TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
    891   const base::string16 database_name(ASCIIToUTF16("db1"));
    892   int64 database_id;
    893   const base::string16 version(ASCIIToUTF16("old_string_version"));
    894   const int64 int_version = 9;
    895 
    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"));
    901 
    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"));
    907 
    908   {
    909     leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
    910         database_name, version, int_version, &database_id);
    911     EXPECT_TRUE(s.ok());
    912     EXPECT_GT(database_id, 0);
    913 
    914     IndexedDBBackingStore::Transaction transaction(backing_store_.get());
    915     transaction.Begin();
    916 
    917     s = backing_store_->CreateObjectStore(&transaction,
    918                                           database_id,
    919                                           object_store_id,
    920                                           object_store_name,
    921                                           object_store_key_path,
    922                                           auto_increment);
    923     EXPECT_TRUE(s.ok());
    924 
    925     s = backing_store_->CreateIndex(&transaction,
    926                                     database_id,
    927                                     object_store_id,
    928                                     index_id,
    929                                     index_name,
    930                                     index_key_path,
    931                                     unique,
    932                                     multi_entry);
    933     EXPECT_TRUE(s.ok());
    934 
    935     scoped_refptr<TestCallback> callback(new TestCallback());
    936     s = transaction.CommitPhaseOne(callback);
    937     EXPECT_TRUE(s.ok());
    938     EXPECT_TRUE(callback->called);
    939     EXPECT_TRUE(callback->succeeded);
    940     s = transaction.CommitPhaseTwo();
    941     EXPECT_TRUE(s.ok());
    942   }
    943 
    944   {
    945     IndexedDBDatabaseMetadata database;
    946     bool found;
    947     leveldb::Status s = backing_store_->GetIDBDatabaseMetaData(
    948         database_name, &database, &found);
    949     EXPECT_TRUE(s.ok());
    950     EXPECT_TRUE(found);
    951 
    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);
    956 
    957     s = backing_store_->GetObjectStores(database.id, &database.object_stores);
    958     EXPECT_TRUE(s.ok());
    959 
    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);
    966 
    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);
    973   }
    974 }
    975 
    976 TEST_F(IndexedDBBackingStoreTest, GetDatabaseNames) {
    977   const base::string16 string_version(ASCIIToUTF16("string_version"));
    978 
    979   const base::string16 db1_name(ASCIIToUTF16("db1"));
    980   const int64 db1_version = 1LL;
    981   int64 db1_id;
    982 
    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;
    987   int64 db2_id;
    988 
    989   leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
    990       db1_name, string_version, db1_version, &db1_id);
    991   EXPECT_TRUE(s.ok());
    992   EXPECT_GT(db1_id, 0LL);
    993 
    994   s = backing_store_->CreateIDBDatabaseMetaData(
    995       db2_name, string_version, db2_version, &db2_id);
    996   EXPECT_TRUE(s.ok());
    997   EXPECT_GT(db2_id, db1_id);
    998 
    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);
   1003 }
   1004 
   1005 }  // namespace
   1006 
   1007 }  // namespace content
   1008