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
29using base::ASCIIToUTF16;
30
31namespace content {
32
33namespace {
34
35class 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
44class 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
62class 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
178class 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
229class 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
359class 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
376TEST_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
408TEST_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
465TEST_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
556TEST_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
642TEST_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.
711TEST_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.
802TEST_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
890TEST_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
976TEST_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