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/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_leveldb_coding.h"
     18 #include "content/browser/indexed_db/indexed_db_value.h"
     19 #include "content/public/test/mock_special_storage_policy.h"
     20 #include "net/url_request/url_request_test_util.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
     23 #include "webkit/browser/blob/blob_data_handle.h"
     24 #include "webkit/browser/quota/special_storage_policy.h"
     25 
     26 using base::ASCIIToUTF16;
     27 
     28 namespace content {
     29 
     30 namespace {
     31 
     32 class Comparator : public LevelDBComparator {
     33  public:
     34   virtual int Compare(const base::StringPiece& a,
     35                       const base::StringPiece& b) const OVERRIDE {
     36     return content::Compare(a, b, false /*index_keys*/);
     37   }
     38   virtual const char* Name() const OVERRIDE { return "idb_cmp1"; }
     39 };
     40 
     41 class DefaultLevelDBFactory : public LevelDBFactory {
     42  public:
     43   DefaultLevelDBFactory() {}
     44   virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name,
     45                                       const LevelDBComparator* comparator,
     46                                       scoped_ptr<LevelDBDatabase>* db,
     47                                       bool* is_disk_full) OVERRIDE {
     48     return LevelDBDatabase::Open(file_name, comparator, db, is_disk_full);
     49   }
     50   virtual leveldb::Status DestroyLevelDB(
     51       const base::FilePath& file_name) OVERRIDE {
     52     return LevelDBDatabase::Destroy(file_name);
     53   }
     54 
     55  private:
     56   DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory);
     57 };
     58 
     59 class TestableIndexedDBBackingStore : public IndexedDBBackingStore {
     60  public:
     61   static scoped_refptr<TestableIndexedDBBackingStore> Open(
     62       IndexedDBFactory* indexed_db_factory,
     63       const GURL& origin_url,
     64       const base::FilePath& path_base,
     65       net::URLRequestContext* request_context,
     66       LevelDBFactory* leveldb_factory,
     67       base::TaskRunner* task_runner) {
     68     DCHECK(!path_base.empty());
     69 
     70     scoped_ptr<LevelDBComparator> comparator(new Comparator());
     71 
     72     if (!base::CreateDirectory(path_base))
     73       return scoped_refptr<TestableIndexedDBBackingStore>();
     74 
     75     const base::FilePath file_path = path_base.AppendASCII("test_db_path");
     76     const base::FilePath blob_path = path_base.AppendASCII("test_blob_path");
     77 
     78     scoped_ptr<LevelDBDatabase> db;
     79     bool is_disk_full = false;
     80     leveldb::Status status = leveldb_factory->OpenLevelDB(
     81         file_path, comparator.get(), &db, &is_disk_full);
     82 
     83     if (!db || !status.ok())
     84       return scoped_refptr<TestableIndexedDBBackingStore>();
     85 
     86     scoped_refptr<TestableIndexedDBBackingStore> backing_store(
     87         new TestableIndexedDBBackingStore(indexed_db_factory,
     88                                           origin_url,
     89                                           blob_path,
     90                                           request_context,
     91                                           db.Pass(),
     92                                           comparator.Pass(),
     93                                           task_runner));
     94 
     95     if (!backing_store->SetUpMetadata())
     96       return scoped_refptr<TestableIndexedDBBackingStore>();
     97 
     98     return backing_store;
     99   }
    100 
    101   const std::vector<IndexedDBBackingStore::Transaction::WriteDescriptor>&
    102   writes() const {
    103     return writes_;
    104   }
    105   void ClearWrites() { writes_.clear(); }
    106   const std::vector<int64>& removals() const { return removals_; }
    107   void ClearRemovals() { removals_.clear(); }
    108 
    109  protected:
    110   virtual ~TestableIndexedDBBackingStore() {}
    111 
    112   virtual bool WriteBlobFile(
    113       int64 database_id,
    114       const Transaction::WriteDescriptor& descriptor,
    115       Transaction::ChainedBlobWriter* chained_blob_writer) OVERRIDE {
    116     if (KeyPrefix::IsValidDatabaseId(database_id_)) {
    117       if (database_id_ != database_id) {
    118         return false;
    119       }
    120     } else {
    121       database_id_ = database_id;
    122     }
    123     writes_.push_back(descriptor);
    124     task_runner()->PostTask(
    125         FROM_HERE,
    126         base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion,
    127                    chained_blob_writer,
    128                    true,
    129                    1));
    130     return true;
    131   }
    132 
    133   virtual bool RemoveBlobFile(int64 database_id, int64 key) OVERRIDE {
    134     if (database_id_ != database_id ||
    135         !KeyPrefix::IsValidDatabaseId(database_id)) {
    136       return false;
    137     }
    138     removals_.push_back(key);
    139     return true;
    140   }
    141 
    142   // Timers don't play nicely with unit tests.
    143   virtual void StartJournalCleaningTimer() OVERRIDE {
    144     CleanPrimaryJournalIgnoreReturn();
    145   }
    146 
    147  private:
    148   TestableIndexedDBBackingStore(IndexedDBFactory* indexed_db_factory,
    149                                 const GURL& origin_url,
    150                                 const base::FilePath& blob_path,
    151                                 net::URLRequestContext* request_context,
    152                                 scoped_ptr<LevelDBDatabase> db,
    153                                 scoped_ptr<LevelDBComparator> comparator,
    154                                 base::TaskRunner* task_runner)
    155       : IndexedDBBackingStore(indexed_db_factory,
    156                               origin_url,
    157                               blob_path,
    158                               request_context,
    159                               db.Pass(),
    160                               comparator.Pass(),
    161                               task_runner),
    162         database_id_(0) {}
    163 
    164   int64 database_id_;
    165   std::vector<Transaction::WriteDescriptor> writes_;
    166   std::vector<int64> removals_;
    167 
    168   DISALLOW_COPY_AND_ASSIGN(TestableIndexedDBBackingStore);
    169 };
    170 
    171 class TestIDBFactory : public IndexedDBFactory {
    172  public:
    173   explicit TestIDBFactory(IndexedDBContextImpl* idb_context)
    174       : IndexedDBFactory(idb_context) {}
    175 
    176   scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest(
    177       const GURL& origin,
    178       net::URLRequestContext* url_request_context) {
    179     blink::WebIDBDataLoss data_loss;
    180     std::string data_loss_reason;
    181     bool disk_full;
    182     scoped_refptr<IndexedDBBackingStore> backing_store =
    183         OpenBackingStore(origin,
    184                          context()->data_path(),
    185                          url_request_context,
    186                          &data_loss,
    187                          &data_loss_reason,
    188                          &disk_full);
    189     scoped_refptr<TestableIndexedDBBackingStore> testable_store =
    190         static_cast<TestableIndexedDBBackingStore*>(backing_store.get());
    191     return testable_store;
    192   }
    193 
    194  protected:
    195   virtual ~TestIDBFactory() {}
    196 
    197   virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper(
    198       const GURL& origin_url,
    199       const base::FilePath& data_directory,
    200       net::URLRequestContext* request_context,
    201       blink::WebIDBDataLoss* data_loss,
    202       std::string* data_loss_message,
    203       bool* disk_full,
    204       bool first_time) OVERRIDE {
    205     DefaultLevelDBFactory leveldb_factory;
    206     return TestableIndexedDBBackingStore::Open(this,
    207                                                origin_url,
    208                                                data_directory,
    209                                                request_context,
    210                                                &leveldb_factory,
    211                                                context()->TaskRunner());
    212   }
    213 
    214  private:
    215   DISALLOW_COPY_AND_ASSIGN(TestIDBFactory);
    216 };
    217 
    218 class IndexedDBBackingStoreTest : public testing::Test {
    219  public:
    220   IndexedDBBackingStoreTest() {}
    221   virtual void SetUp() {
    222     const GURL origin("http://localhost:81");
    223     task_runner_ = new base::TestSimpleTaskRunner();
    224     special_storage_policy_ = new MockSpecialStoragePolicy();
    225     special_storage_policy_->SetAllUnlimited(true);
    226     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    227     idb_context_ = new IndexedDBContextImpl(
    228         temp_dir_.path(), special_storage_policy_, NULL, task_runner_);
    229     idb_factory_ = new TestIDBFactory(idb_context_);
    230     backing_store_ =
    231         idb_factory_->OpenBackingStoreForTest(origin, &url_request_context_);
    232 
    233     // useful keys and values during tests
    234     m_value1 = IndexedDBValue("value1", std::vector<IndexedDBBlobInfo>());
    235     m_value2 = IndexedDBValue("value2", std::vector<IndexedDBBlobInfo>());
    236 
    237     m_blob_info.push_back(
    238         IndexedDBBlobInfo("uuid 3", base::UTF8ToUTF16("blob type"), 1));
    239     m_blob_info.push_back(
    240         IndexedDBBlobInfo("uuid 4",
    241                           base::FilePath(FILE_PATH_LITERAL("path/to/file")),
    242                           base::UTF8ToUTF16("file name"),
    243                           base::UTF8ToUTF16("file type")));
    244     m_value3 = IndexedDBValue("value3", m_blob_info);
    245 
    246     m_key1 = IndexedDBKey(99, blink::WebIDBKeyTypeNumber);
    247     m_key2 = IndexedDBKey(ASCIIToUTF16("key2"));
    248     m_key3 = IndexedDBKey(ASCIIToUTF16("key3"));
    249   }
    250 
    251   // This just checks the data that survive getting stored and recalled, e.g.
    252   // the file path and UUID will change and thus aren't verified.
    253   bool CheckBlobInfoMatches(const std::vector<IndexedDBBlobInfo>& reads) const {
    254     if (m_blob_info.size() != reads.size())
    255       return false;
    256     for (size_t i = 0; i < m_blob_info.size(); ++i) {
    257       const IndexedDBBlobInfo& a = m_blob_info[i];
    258       const IndexedDBBlobInfo& b = reads[i];
    259       if (a.is_file() != b.is_file())
    260         return false;
    261       if (a.type() != b.type())
    262         return false;
    263       if (a.is_file()) {
    264         if (a.file_name() != b.file_name())
    265           return false;
    266       } else {
    267         if (a.size() != b.size())
    268           return false;
    269       }
    270     }
    271     return true;
    272   }
    273 
    274   bool CheckBlobReadsMatchWrites(
    275       const std::vector<IndexedDBBlobInfo>& reads) const {
    276     if (backing_store_->writes().size() != reads.size())
    277       return false;
    278     std::set<int64> ids;
    279     for (size_t i = 0; i < backing_store_->writes().size(); ++i)
    280       ids.insert(backing_store_->writes()[i].key());
    281     if (ids.size() != backing_store_->writes().size())
    282       return false;
    283     for (size_t i = 0; i < reads.size(); ++i) {
    284       if (ids.count(reads[i].key()) != 1)
    285         return false;
    286     }
    287     return true;
    288   }
    289 
    290   bool CheckBlobWrites() const {
    291     if (backing_store_->writes().size() != m_blob_info.size())
    292       return false;
    293     for (size_t i = 0; i < backing_store_->writes().size(); ++i) {
    294       const IndexedDBBackingStore::Transaction::WriteDescriptor& desc =
    295           backing_store_->writes()[i];
    296       const IndexedDBBlobInfo& info = m_blob_info[i];
    297       if (desc.is_file() != info.is_file())
    298         return false;
    299       if (desc.is_file()) {
    300         if (desc.file_path() != info.file_path())
    301           return false;
    302       } else {
    303         if (desc.url() != GURL("blob:uuid/" + info.uuid()))
    304           return false;
    305       }
    306     }
    307     return true;
    308   }
    309 
    310   bool CheckBlobRemovals() const {
    311     if (backing_store_->removals().size() != backing_store_->writes().size())
    312       return false;
    313     for (size_t i = 0; i < backing_store_->writes().size(); ++i) {
    314       if (backing_store_->writes()[i].key() != backing_store_->removals()[i])
    315         return false;
    316     }
    317     return true;
    318   }
    319 
    320  protected:
    321   base::ScopedTempDir temp_dir_;
    322   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
    323   scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
    324   scoped_refptr<IndexedDBContextImpl> idb_context_;
    325   scoped_refptr<TestIDBFactory> idb_factory_;
    326   net::TestURLRequestContext url_request_context_;
    327 
    328   scoped_refptr<TestableIndexedDBBackingStore> backing_store_;
    329 
    330   // Sample keys and values that are consistent.
    331   IndexedDBKey m_key1;
    332   IndexedDBKey m_key2;
    333   IndexedDBKey m_key3;
    334   IndexedDBValue m_value1;
    335   IndexedDBValue m_value2;
    336   IndexedDBValue m_value3;
    337   std::vector<IndexedDBBlobInfo> m_blob_info;
    338 
    339  private:
    340   DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStoreTest);
    341 };
    342 
    343 class TestCallback : public IndexedDBBackingStore::BlobWriteCallback {
    344  public:
    345   TestCallback() : called(false), succeeded(false) {}
    346   virtual void Run(bool succeeded_in) OVERRIDE {
    347     called = true;
    348     succeeded = succeeded_in;
    349   }
    350   bool called;
    351   bool succeeded;
    352 
    353  protected:
    354   virtual ~TestCallback() {}
    355 
    356  private:
    357   DISALLOW_COPY_AND_ASSIGN(TestCallback);
    358 };
    359 
    360 TEST_F(IndexedDBBackingStoreTest, PutGetConsistency) {
    361   {
    362     IndexedDBBackingStore::Transaction transaction1(backing_store_);
    363     transaction1.Begin();
    364     ScopedVector<webkit_blob::BlobDataHandle> handles;
    365     IndexedDBBackingStore::RecordIdentifier record;
    366     leveldb::Status s = backing_store_->PutRecord(
    367         &transaction1, 1, 1, m_key1, m_value1, &handles, &record);
    368     EXPECT_TRUE(s.ok());
    369     scoped_refptr<TestCallback> callback(new TestCallback());
    370     EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
    371     EXPECT_TRUE(callback->called);
    372     EXPECT_TRUE(callback->succeeded);
    373     EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
    374   }
    375 
    376   {
    377     IndexedDBBackingStore::Transaction transaction2(backing_store_);
    378     transaction2.Begin();
    379     IndexedDBValue result_value;
    380     EXPECT_TRUE(
    381         backing_store_->GetRecord(&transaction2, 1, 1, m_key1, &result_value)
    382             .ok());
    383     scoped_refptr<TestCallback> callback(new TestCallback());
    384     EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
    385     EXPECT_TRUE(callback->called);
    386     EXPECT_TRUE(callback->succeeded);
    387     EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
    388     EXPECT_EQ(m_value1.bits, result_value.bits);
    389   }
    390 }
    391 
    392 TEST_F(IndexedDBBackingStoreTest, PutGetConsistencyWithBlobs) {
    393   {
    394     IndexedDBBackingStore::Transaction transaction1(backing_store_);
    395     transaction1.Begin();
    396     ScopedVector<webkit_blob::BlobDataHandle> handles;
    397     IndexedDBBackingStore::RecordIdentifier record;
    398     EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    399                                           1,
    400                                           1,
    401                                           m_key3,
    402                                           m_value3,
    403                                           &handles,
    404                                           &record).ok());
    405     scoped_refptr<TestCallback> callback(new TestCallback());
    406     EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
    407     task_runner_->RunUntilIdle();
    408     EXPECT_TRUE(CheckBlobWrites());
    409     EXPECT_TRUE(callback->called);
    410     EXPECT_TRUE(callback->succeeded);
    411     EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
    412   }
    413 
    414   {
    415     IndexedDBBackingStore::Transaction transaction2(backing_store_);
    416     transaction2.Begin();
    417     IndexedDBValue result_value;
    418     EXPECT_TRUE(
    419         backing_store_->GetRecord(&transaction2, 1, 1, m_key3, &result_value)
    420             .ok());
    421     scoped_refptr<TestCallback> callback(new TestCallback());
    422     EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
    423     EXPECT_TRUE(callback->called);
    424     EXPECT_TRUE(callback->succeeded);
    425     EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
    426     EXPECT_EQ(m_value3.bits, result_value.bits);
    427     EXPECT_TRUE(CheckBlobInfoMatches(result_value.blob_info));
    428     EXPECT_TRUE(CheckBlobReadsMatchWrites(result_value.blob_info));
    429   }
    430 
    431   {
    432     IndexedDBBackingStore::Transaction transaction3(backing_store_);
    433     transaction3.Begin();
    434     IndexedDBValue result_value;
    435     EXPECT_TRUE(backing_store_->DeleteRange(&transaction3,
    436                                             1,
    437                                             1,
    438                                             IndexedDBKeyRange(m_key3)).ok());
    439     scoped_refptr<TestCallback> callback(new TestCallback());
    440     EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok());
    441     task_runner_->RunUntilIdle();
    442     EXPECT_TRUE(callback->called);
    443     EXPECT_TRUE(callback->succeeded);
    444     EXPECT_TRUE(transaction3.CommitPhaseTwo().ok());
    445     EXPECT_TRUE(CheckBlobRemovals());
    446   }
    447 }
    448 
    449 TEST_F(IndexedDBBackingStoreTest, DeleteRange) {
    450   IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0"));
    451   IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1"));
    452   IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2"));
    453   IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3"));
    454   IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
    455   IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
    456   IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
    457   IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
    458   IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key1, key2, false, false),
    459                                 IndexedDBKeyRange(key1, key2, false, false),
    460                                 IndexedDBKeyRange(key0, key2, true, false),
    461                                 IndexedDBKeyRange(key1, key3, false, true),
    462                                 IndexedDBKeyRange(key0, key3, true, true)};
    463 
    464   for (unsigned i = 0; i < sizeof(ranges) / sizeof(IndexedDBKeyRange); ++i) {
    465     backing_store_->ClearWrites();
    466     backing_store_->ClearRemovals();
    467 
    468     {
    469       std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2,
    470           blob_info3;
    471       blob_info0.push_back(blob0);
    472       blob_info1.push_back(blob1);
    473       blob_info2.push_back(blob2);
    474       blob_info3.push_back(blob3);
    475       IndexedDBValue value0 = IndexedDBValue("value0", blob_info0);
    476       IndexedDBValue value1 = IndexedDBValue("value1", blob_info1);
    477       IndexedDBValue value2 = IndexedDBValue("value2", blob_info2);
    478       IndexedDBValue value3 = IndexedDBValue("value3", blob_info3);
    479       IndexedDBBackingStore::Transaction transaction1(backing_store_);
    480       transaction1.Begin();
    481       ScopedVector<webkit_blob::BlobDataHandle> handles;
    482       IndexedDBBackingStore::RecordIdentifier record;
    483       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    484                                             1,
    485                                             i + 1,
    486                                             key0,
    487                                             value0,
    488                                             &handles,
    489                                             &record).ok());
    490       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    491                                             1,
    492                                             i + 1,
    493                                             key1,
    494                                             value1,
    495                                             &handles,
    496                                             &record).ok());
    497       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    498                                             1,
    499                                             i + 1,
    500                                             key2,
    501                                             value2,
    502                                             &handles,
    503                                             &record).ok());
    504       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    505                                             1,
    506                                             i + 1,
    507                                             key3,
    508                                             value3,
    509                                             &handles,
    510                                             &record).ok());
    511       scoped_refptr<TestCallback> callback(new TestCallback());
    512       EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
    513       task_runner_->RunUntilIdle();
    514       EXPECT_TRUE(callback->called);
    515       EXPECT_TRUE(callback->succeeded);
    516       EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
    517     }
    518 
    519     {
    520       IndexedDBBackingStore::Transaction transaction2(backing_store_);
    521       transaction2.Begin();
    522       IndexedDBValue result_value;
    523       EXPECT_TRUE(
    524           backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok());
    525       scoped_refptr<TestCallback> callback(new TestCallback());
    526       EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
    527       task_runner_->RunUntilIdle();
    528       EXPECT_TRUE(callback->called);
    529       EXPECT_TRUE(callback->succeeded);
    530       EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
    531       EXPECT_EQ(2UL, backing_store_->removals().size());
    532       EXPECT_EQ(backing_store_->writes()[1].key(),
    533                 backing_store_->removals()[0]);
    534       EXPECT_EQ(backing_store_->writes()[2].key(),
    535                 backing_store_->removals()[1]);
    536     }
    537   }
    538 }
    539 
    540 TEST_F(IndexedDBBackingStoreTest, DeleteRangeEmptyRange) {
    541   IndexedDBKey key0 = IndexedDBKey(ASCIIToUTF16("key0"));
    542   IndexedDBKey key1 = IndexedDBKey(ASCIIToUTF16("key1"));
    543   IndexedDBKey key2 = IndexedDBKey(ASCIIToUTF16("key2"));
    544   IndexedDBKey key3 = IndexedDBKey(ASCIIToUTF16("key3"));
    545   IndexedDBKey key4 = IndexedDBKey(ASCIIToUTF16("key4"));
    546   IndexedDBBlobInfo blob0("uuid 0", base::UTF8ToUTF16("type 0"), 1);
    547   IndexedDBBlobInfo blob1("uuid 1", base::UTF8ToUTF16("type 1"), 1);
    548   IndexedDBBlobInfo blob2("uuid 2", base::UTF8ToUTF16("type 2"), 1);
    549   IndexedDBBlobInfo blob3("uuid 3", base::UTF8ToUTF16("type 3"), 1);
    550   IndexedDBKeyRange ranges[] = {IndexedDBKeyRange(key3, key4, true, false),
    551                                 IndexedDBKeyRange(key2, key1, false, false),
    552                                 IndexedDBKeyRange(key2, key1, true, true)};
    553 
    554   for (unsigned i = 0; i < arraysize(ranges); ++i) {
    555     backing_store_->ClearWrites();
    556     backing_store_->ClearRemovals();
    557 
    558     {
    559       std::vector<IndexedDBBlobInfo> blob_info0, blob_info1, blob_info2,
    560           blob_info3;
    561       blob_info0.push_back(blob0);
    562       blob_info1.push_back(blob1);
    563       blob_info2.push_back(blob2);
    564       blob_info3.push_back(blob3);
    565       IndexedDBValue value0 = IndexedDBValue("value0", blob_info0);
    566       IndexedDBValue value1 = IndexedDBValue("value1", blob_info1);
    567       IndexedDBValue value2 = IndexedDBValue("value2", blob_info2);
    568       IndexedDBValue value3 = IndexedDBValue("value3", blob_info3);
    569       IndexedDBBackingStore::Transaction transaction1(backing_store_);
    570       transaction1.Begin();
    571       ScopedVector<webkit_blob::BlobDataHandle> handles;
    572       IndexedDBBackingStore::RecordIdentifier record;
    573       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    574                                             1,
    575                                             i + 1,
    576                                             key0,
    577                                             value0,
    578                                             &handles,
    579                                             &record).ok());
    580       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    581                                             1,
    582                                             i + 1,
    583                                             key1,
    584                                             value1,
    585                                             &handles,
    586                                             &record).ok());
    587       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    588                                             1,
    589                                             i + 1,
    590                                             key2,
    591                                             value2,
    592                                             &handles,
    593                                             &record).ok());
    594       EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    595                                             1,
    596                                             i + 1,
    597                                             key3,
    598                                             value3,
    599                                             &handles,
    600                                             &record).ok());
    601       scoped_refptr<TestCallback> callback(new TestCallback());
    602       EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
    603       task_runner_->RunUntilIdle();
    604       EXPECT_TRUE(callback->called);
    605       EXPECT_TRUE(callback->succeeded);
    606       EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
    607     }
    608 
    609     {
    610       IndexedDBBackingStore::Transaction transaction2(backing_store_);
    611       transaction2.Begin();
    612       IndexedDBValue result_value;
    613       EXPECT_TRUE(
    614           backing_store_->DeleteRange(&transaction2, 1, i + 1, ranges[i]).ok());
    615       scoped_refptr<TestCallback> callback(new TestCallback());
    616       EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
    617       task_runner_->RunUntilIdle();
    618       EXPECT_TRUE(callback->called);
    619       EXPECT_TRUE(callback->succeeded);
    620       EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
    621       EXPECT_EQ(0UL, backing_store_->removals().size());
    622     }
    623   }
    624 }
    625 
    626 TEST_F(IndexedDBBackingStoreTest, LiveBlobJournal) {
    627   {
    628     IndexedDBBackingStore::Transaction transaction1(backing_store_);
    629     transaction1.Begin();
    630     ScopedVector<webkit_blob::BlobDataHandle> handles;
    631     IndexedDBBackingStore::RecordIdentifier record;
    632     EXPECT_TRUE(backing_store_->PutRecord(&transaction1,
    633                                           1,
    634                                           1,
    635                                           m_key3,
    636                                           m_value3,
    637                                           &handles,
    638                                           &record).ok());
    639     scoped_refptr<TestCallback> callback(new TestCallback());
    640     EXPECT_TRUE(transaction1.CommitPhaseOne(callback).ok());
    641     task_runner_->RunUntilIdle();
    642     EXPECT_TRUE(CheckBlobWrites());
    643     EXPECT_TRUE(callback->called);
    644     EXPECT_TRUE(callback->succeeded);
    645     EXPECT_TRUE(transaction1.CommitPhaseTwo().ok());
    646   }
    647 
    648   IndexedDBValue read_result_value;
    649   {
    650     IndexedDBBackingStore::Transaction transaction2(backing_store_);
    651     transaction2.Begin();
    652     EXPECT_TRUE(
    653         backing_store_->GetRecord(
    654                             &transaction2, 1, 1, m_key3, &read_result_value)
    655             .ok());
    656     scoped_refptr<TestCallback> callback(new TestCallback());
    657     EXPECT_TRUE(transaction2.CommitPhaseOne(callback).ok());
    658     EXPECT_TRUE(callback->called);
    659     EXPECT_TRUE(callback->succeeded);
    660     EXPECT_TRUE(transaction2.CommitPhaseTwo().ok());
    661     EXPECT_EQ(m_value3.bits, read_result_value.bits);
    662     EXPECT_TRUE(CheckBlobInfoMatches(read_result_value.blob_info));
    663     EXPECT_TRUE(CheckBlobReadsMatchWrites(read_result_value.blob_info));
    664     for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) {
    665       read_result_value.blob_info[i].mark_used_callback().Run();
    666     }
    667   }
    668 
    669   {
    670     IndexedDBBackingStore::Transaction transaction3(backing_store_);
    671     transaction3.Begin();
    672     EXPECT_TRUE(backing_store_->DeleteRange(&transaction3,
    673                                             1,
    674                                             1,
    675                                             IndexedDBKeyRange(m_key3)).ok());
    676     scoped_refptr<TestCallback> callback(new TestCallback());
    677     EXPECT_TRUE(transaction3.CommitPhaseOne(callback).ok());
    678     task_runner_->RunUntilIdle();
    679     EXPECT_TRUE(callback->called);
    680     EXPECT_TRUE(callback->succeeded);
    681     EXPECT_TRUE(transaction3.CommitPhaseTwo().ok());
    682     EXPECT_EQ(0U, backing_store_->removals().size());
    683     for (size_t i = 0; i < read_result_value.blob_info.size(); ++i) {
    684       read_result_value.blob_info[i].release_callback().Run(
    685           read_result_value.blob_info[i].file_path());
    686     }
    687     task_runner_->RunUntilIdle();
    688     EXPECT_NE(0U, backing_store_->removals().size());
    689     EXPECT_TRUE(CheckBlobRemovals());
    690   }
    691 }
    692 
    693 // Make sure that using very high ( more than 32 bit ) values for database_id
    694 // and object_store_id still work.
    695 TEST_F(IndexedDBBackingStoreTest, HighIds) {
    696   const int64 high_database_id = 1ULL << 35;
    697   const int64 high_object_store_id = 1ULL << 39;
    698   // index_ids are capped at 32 bits for storage purposes.
    699   const int64 high_index_id = 1ULL << 29;
    700 
    701   const int64 invalid_high_index_id = 1ULL << 37;
    702 
    703   const IndexedDBKey& index_key = m_key2;
    704   std::string index_key_raw;
    705   EncodeIDBKey(index_key, &index_key_raw);
    706   {
    707     IndexedDBBackingStore::Transaction transaction1(backing_store_);
    708     transaction1.Begin();
    709     ScopedVector<webkit_blob::BlobDataHandle> handles;
    710     IndexedDBBackingStore::RecordIdentifier record;
    711     leveldb::Status s = backing_store_->PutRecord(&transaction1,
    712                                                   high_database_id,
    713                                                   high_object_store_id,
    714                                                   m_key1,
    715                                                   m_value1,
    716                                                   &handles,
    717                                                   &record);
    718     EXPECT_TRUE(s.ok());
    719 
    720     s = backing_store_->PutIndexDataForRecord(&transaction1,
    721                                               high_database_id,
    722                                               high_object_store_id,
    723                                               invalid_high_index_id,
    724                                               index_key,
    725                                               record);
    726     EXPECT_FALSE(s.ok());
    727 
    728     s = backing_store_->PutIndexDataForRecord(&transaction1,
    729                                               high_database_id,
    730                                               high_object_store_id,
    731                                               high_index_id,
    732                                               index_key,
    733                                               record);
    734     EXPECT_TRUE(s.ok());
    735 
    736     scoped_refptr<TestCallback> callback(new TestCallback());
    737     s = transaction1.CommitPhaseOne(callback);
    738     EXPECT_TRUE(s.ok());
    739     EXPECT_TRUE(callback->called);
    740     EXPECT_TRUE(callback->succeeded);
    741     s = transaction1.CommitPhaseTwo();
    742     EXPECT_TRUE(s.ok());
    743   }
    744 
    745   {
    746     IndexedDBBackingStore::Transaction transaction2(backing_store_);
    747     transaction2.Begin();
    748     IndexedDBValue result_value;
    749     leveldb::Status s = backing_store_->GetRecord(&transaction2,
    750                                                   high_database_id,
    751                                                   high_object_store_id,
    752                                                   m_key1,
    753                                                   &result_value);
    754     EXPECT_TRUE(s.ok());
    755     EXPECT_EQ(m_value1.bits, result_value.bits);
    756 
    757     scoped_ptr<IndexedDBKey> new_primary_key;
    758     s = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
    759                                               high_database_id,
    760                                               high_object_store_id,
    761                                               invalid_high_index_id,
    762                                               index_key,
    763                                               &new_primary_key);
    764     EXPECT_FALSE(s.ok());
    765 
    766     s = backing_store_->GetPrimaryKeyViaIndex(&transaction2,
    767                                               high_database_id,
    768                                               high_object_store_id,
    769                                               high_index_id,
    770                                               index_key,
    771                                               &new_primary_key);
    772     EXPECT_TRUE(s.ok());
    773     EXPECT_TRUE(new_primary_key->Equals(m_key1));
    774 
    775     scoped_refptr<TestCallback> callback(new TestCallback());
    776     s = transaction2.CommitPhaseOne(callback);
    777     EXPECT_TRUE(s.ok());
    778     EXPECT_TRUE(callback->called);
    779     EXPECT_TRUE(callback->succeeded);
    780     s = transaction2.CommitPhaseTwo();
    781     EXPECT_TRUE(s.ok());
    782   }
    783 }
    784 
    785 // Make sure that other invalid ids do not crash.
    786 TEST_F(IndexedDBBackingStoreTest, InvalidIds) {
    787   // valid ids for use when testing invalid ids
    788   const int64 database_id = 1;
    789   const int64 object_store_id = 1;
    790   const int64 index_id = kMinimumIndexId;
    791   const int64 invalid_low_index_id = 19;  // index_ids must be > kMinimumIndexId
    792 
    793   IndexedDBValue result_value;
    794 
    795   IndexedDBBackingStore::Transaction transaction1(backing_store_);
    796   transaction1.Begin();
    797 
    798   ScopedVector<webkit_blob::BlobDataHandle> handles;
    799   IndexedDBBackingStore::RecordIdentifier record;
    800   leveldb::Status s = backing_store_->PutRecord(&transaction1,
    801                                                 database_id,
    802                                                 KeyPrefix::kInvalidId,
    803                                                 m_key1,
    804                                                 m_value1,
    805                                                 &handles,
    806                                                 &record);
    807   EXPECT_FALSE(s.ok());
    808   s = backing_store_->PutRecord(
    809       &transaction1, database_id, 0, m_key1, m_value1, &handles, &record);
    810   EXPECT_FALSE(s.ok());
    811   s = backing_store_->PutRecord(&transaction1,
    812                                 KeyPrefix::kInvalidId,
    813                                 object_store_id,
    814                                 m_key1,
    815                                 m_value1,
    816                                 &handles,
    817                                 &record);
    818   EXPECT_FALSE(s.ok());
    819   s = backing_store_->PutRecord(
    820       &transaction1, 0, object_store_id, m_key1, m_value1, &handles, &record);
    821   EXPECT_FALSE(s.ok());
    822 
    823   s = backing_store_->GetRecord(
    824       &transaction1, database_id, KeyPrefix::kInvalidId, m_key1, &result_value);
    825   EXPECT_FALSE(s.ok());
    826   s = backing_store_->GetRecord(
    827       &transaction1, database_id, 0, m_key1, &result_value);
    828   EXPECT_FALSE(s.ok());
    829   s = backing_store_->GetRecord(&transaction1,
    830                                 KeyPrefix::kInvalidId,
    831                                 object_store_id,
    832                                 m_key1,
    833                                 &result_value);
    834   EXPECT_FALSE(s.ok());
    835   s = backing_store_->GetRecord(
    836       &transaction1, 0, object_store_id, m_key1, &result_value);
    837   EXPECT_FALSE(s.ok());
    838 
    839   scoped_ptr<IndexedDBKey> new_primary_key;
    840   s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
    841                                             database_id,
    842                                             object_store_id,
    843                                             KeyPrefix::kInvalidId,
    844                                             m_key1,
    845                                             &new_primary_key);
    846   EXPECT_FALSE(s.ok());
    847   s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
    848                                             database_id,
    849                                             object_store_id,
    850                                             invalid_low_index_id,
    851                                             m_key1,
    852                                             &new_primary_key);
    853   EXPECT_FALSE(s.ok());
    854   s = backing_store_->GetPrimaryKeyViaIndex(
    855       &transaction1, database_id, object_store_id, 0, m_key1, &new_primary_key);
    856   EXPECT_FALSE(s.ok());
    857 
    858   s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
    859                                             KeyPrefix::kInvalidId,
    860                                             object_store_id,
    861                                             index_id,
    862                                             m_key1,
    863                                             &new_primary_key);
    864   EXPECT_FALSE(s.ok());
    865   s = backing_store_->GetPrimaryKeyViaIndex(&transaction1,
    866                                             database_id,
    867                                             KeyPrefix::kInvalidId,
    868                                             index_id,
    869                                             m_key1,
    870                                             &new_primary_key);
    871   EXPECT_FALSE(s.ok());
    872 }
    873 
    874 TEST_F(IndexedDBBackingStoreTest, CreateDatabase) {
    875   const base::string16 database_name(ASCIIToUTF16("db1"));
    876   int64 database_id;
    877   const base::string16 version(ASCIIToUTF16("old_string_version"));
    878   const int64 int_version = 9;
    879 
    880   const int64 object_store_id = 99;
    881   const base::string16 object_store_name(ASCIIToUTF16("object_store1"));
    882   const bool auto_increment = true;
    883   const IndexedDBKeyPath object_store_key_path(
    884       ASCIIToUTF16("object_store_key"));
    885 
    886   const int64 index_id = 999;
    887   const base::string16 index_name(ASCIIToUTF16("index1"));
    888   const bool unique = true;
    889   const bool multi_entry = true;
    890   const IndexedDBKeyPath index_key_path(ASCIIToUTF16("index_key"));
    891 
    892   {
    893     leveldb::Status s = backing_store_->CreateIDBDatabaseMetaData(
    894         database_name, version, int_version, &database_id);
    895     EXPECT_TRUE(s.ok());
    896     EXPECT_GT(database_id, 0);
    897 
    898     IndexedDBBackingStore::Transaction transaction(backing_store_);
    899     transaction.Begin();
    900 
    901     s = backing_store_->CreateObjectStore(&transaction,
    902                                           database_id,
    903                                           object_store_id,
    904                                           object_store_name,
    905                                           object_store_key_path,
    906                                           auto_increment);
    907     EXPECT_TRUE(s.ok());
    908 
    909     s = backing_store_->CreateIndex(&transaction,
    910                                     database_id,
    911                                     object_store_id,
    912                                     index_id,
    913                                     index_name,
    914                                     index_key_path,
    915                                     unique,
    916                                     multi_entry);
    917     EXPECT_TRUE(s.ok());
    918 
    919     scoped_refptr<TestCallback> callback(new TestCallback());
    920     s = transaction.CommitPhaseOne(callback);
    921     EXPECT_TRUE(s.ok());
    922     EXPECT_TRUE(callback->called);
    923     EXPECT_TRUE(callback->succeeded);
    924     s = transaction.CommitPhaseTwo();
    925     EXPECT_TRUE(s.ok());
    926   }
    927 
    928   {
    929     IndexedDBDatabaseMetadata database;
    930     bool found;
    931     leveldb::Status s = backing_store_->GetIDBDatabaseMetaData(
    932         database_name, &database, &found);
    933     EXPECT_TRUE(s.ok());
    934     EXPECT_TRUE(found);
    935 
    936     // database.name is not filled in by the implementation.
    937     EXPECT_EQ(version, database.version);
    938     EXPECT_EQ(int_version, database.int_version);
    939     EXPECT_EQ(database_id, database.id);
    940 
    941     s = backing_store_->GetObjectStores(database.id, &database.object_stores);
    942     EXPECT_TRUE(s.ok());
    943 
    944     EXPECT_EQ(1UL, database.object_stores.size());
    945     IndexedDBObjectStoreMetadata object_store =
    946         database.object_stores[object_store_id];
    947     EXPECT_EQ(object_store_name, object_store.name);
    948     EXPECT_EQ(object_store_key_path, object_store.key_path);
    949     EXPECT_EQ(auto_increment, object_store.auto_increment);
    950 
    951     EXPECT_EQ(1UL, object_store.indexes.size());
    952     IndexedDBIndexMetadata index = object_store.indexes[index_id];
    953     EXPECT_EQ(index_name, index.name);
    954     EXPECT_EQ(index_key_path, index.key_path);
    955     EXPECT_EQ(unique, index.unique);
    956     EXPECT_EQ(multi_entry, index.multi_entry);
    957   }
    958 }
    959 
    960 }  // namespace
    961 
    962 }  // namespace content
    963