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 <cerrno>
      6 
      7 #include "base/files/file.h"
      8 #include "base/files/file_path.h"
      9 #include "base/files/scoped_temp_dir.h"
     10 #include "base/strings/string16.h"
     11 #include "base/strings/utf_string_conversions.h"
     12 #include "content/browser/indexed_db/indexed_db_backing_store.h"
     13 #include "content/browser/indexed_db/leveldb/leveldb_database.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #include "third_party/leveldatabase/env_chromium.h"
     16 
     17 using base::StringPiece;
     18 using content::IndexedDBBackingStore;
     19 using content::LevelDBComparator;
     20 using content::LevelDBDatabase;
     21 using content::LevelDBFactory;
     22 using content::LevelDBSnapshot;
     23 
     24 namespace base {
     25 class TaskRunner;
     26 }
     27 
     28 namespace content {
     29 class IndexedDBFactory;
     30 }
     31 
     32 namespace net {
     33 class URLRequestContext;
     34 }
     35 
     36 namespace {
     37 
     38 class BustedLevelDBDatabase : public LevelDBDatabase {
     39  public:
     40   BustedLevelDBDatabase() {}
     41   static scoped_ptr<LevelDBDatabase> Open(
     42       const base::FilePath& file_name,
     43       const LevelDBComparator* /*comparator*/) {
     44     return scoped_ptr<LevelDBDatabase>(new BustedLevelDBDatabase);
     45   }
     46   virtual leveldb::Status Get(const base::StringPiece& key,
     47                               std::string* value,
     48                               bool* found,
     49                               const LevelDBSnapshot* = 0) OVERRIDE {
     50     return leveldb::Status::IOError("It's busted!");
     51   }
     52 
     53  private:
     54   DISALLOW_COPY_AND_ASSIGN(BustedLevelDBDatabase);
     55 };
     56 
     57 class MockLevelDBFactory : public LevelDBFactory {
     58  public:
     59   MockLevelDBFactory() : destroy_called_(false) {}
     60   virtual leveldb::Status OpenLevelDB(
     61       const base::FilePath& file_name,
     62       const LevelDBComparator* comparator,
     63       scoped_ptr<LevelDBDatabase>* db,
     64       bool* is_disk_full = 0) OVERRIDE {
     65     *db = BustedLevelDBDatabase::Open(file_name, comparator);
     66     return leveldb::Status::OK();
     67   }
     68   virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name)
     69       OVERRIDE {
     70     EXPECT_FALSE(destroy_called_);
     71     destroy_called_ = true;
     72     return leveldb::Status::IOError("error");
     73   }
     74   virtual ~MockLevelDBFactory() { EXPECT_TRUE(destroy_called_); }
     75 
     76  private:
     77   bool destroy_called_;
     78 
     79  private:
     80   DISALLOW_COPY_AND_ASSIGN(MockLevelDBFactory);
     81 };
     82 
     83 TEST(IndexedDBIOErrorTest, CleanUpTest) {
     84   content::IndexedDBFactory* factory = NULL;
     85   const GURL origin("http://localhost:81");
     86   base::ScopedTempDir temp_directory;
     87   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
     88   const base::FilePath path = temp_directory.path();
     89   net::URLRequestContext* request_context = NULL;
     90   MockLevelDBFactory mock_leveldb_factory;
     91   blink::WebIDBDataLoss data_loss =
     92       blink::WebIDBDataLossNone;
     93   std::string data_loss_message;
     94   bool disk_full = false;
     95   base::TaskRunner* task_runner = NULL;
     96   bool clean_journal = false;
     97   scoped_refptr<IndexedDBBackingStore> backing_store =
     98       IndexedDBBackingStore::Open(factory,
     99                                   origin,
    100                                   path,
    101                                   request_context,
    102                                   &data_loss,
    103                                   &data_loss_message,
    104                                   &disk_full,
    105                                   &mock_leveldb_factory,
    106                                   task_runner,
    107                                   clean_journal);
    108 }
    109 
    110 // TODO(dgrogan): Remove expect_destroy if we end up not using it again. It is
    111 // currently set to false in all 4 calls below.
    112 template <class T>
    113 class MockErrorLevelDBFactory : public LevelDBFactory {
    114  public:
    115   MockErrorLevelDBFactory(T error, bool expect_destroy)
    116       : error_(error),
    117         expect_destroy_(expect_destroy),
    118         destroy_called_(false) {}
    119   virtual leveldb::Status OpenLevelDB(
    120       const base::FilePath& file_name,
    121       const LevelDBComparator* comparator,
    122       scoped_ptr<LevelDBDatabase>* db,
    123       bool* is_disk_full = 0) OVERRIDE {
    124     return MakeIOError(
    125         "some filename", "some message", leveldb_env::kNewLogger, error_);
    126   }
    127   virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name)
    128       OVERRIDE {
    129     EXPECT_FALSE(destroy_called_);
    130     destroy_called_ = true;
    131     return leveldb::Status::IOError("error");
    132   }
    133   virtual ~MockErrorLevelDBFactory() {
    134     EXPECT_EQ(expect_destroy_, destroy_called_);
    135   }
    136 
    137  private:
    138   T error_;
    139   bool expect_destroy_;
    140   bool destroy_called_;
    141 
    142   DISALLOW_COPY_AND_ASSIGN(MockErrorLevelDBFactory);
    143 };
    144 
    145 TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
    146   content::IndexedDBFactory* factory = NULL;
    147   const GURL origin("http://localhost:81");
    148   net::URLRequestContext* request_context = NULL;
    149   base::ScopedTempDir temp_directory;
    150   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
    151   const base::FilePath path = temp_directory.path();
    152   blink::WebIDBDataLoss data_loss =
    153       blink::WebIDBDataLossNone;
    154   std::string data_loss_reason;
    155   bool disk_full = false;
    156   base::TaskRunner* task_runner = NULL;
    157   bool clean_journal = false;
    158 
    159   MockErrorLevelDBFactory<int> mock_leveldb_factory(ENOSPC, false);
    160   scoped_refptr<IndexedDBBackingStore> backing_store =
    161       IndexedDBBackingStore::Open(factory,
    162                                   origin,
    163                                   path,
    164                                   request_context,
    165                                   &data_loss,
    166                                   &data_loss_reason,
    167                                   &disk_full,
    168                                   &mock_leveldb_factory,
    169                                   task_runner,
    170                                   clean_journal);
    171 
    172   MockErrorLevelDBFactory<base::File::Error> mock_leveldb_factory2(
    173       base::File::FILE_ERROR_NO_MEMORY, false);
    174   scoped_refptr<IndexedDBBackingStore> backing_store2 =
    175       IndexedDBBackingStore::Open(factory,
    176                                   origin,
    177                                   path,
    178                                   request_context,
    179                                   &data_loss,
    180                                   &data_loss_reason,
    181                                   &disk_full,
    182                                   &mock_leveldb_factory2,
    183                                   task_runner,
    184                                   clean_journal);
    185 
    186   MockErrorLevelDBFactory<int> mock_leveldb_factory3(EIO, false);
    187   scoped_refptr<IndexedDBBackingStore> backing_store3 =
    188       IndexedDBBackingStore::Open(factory,
    189                                   origin,
    190                                   path,
    191                                   request_context,
    192                                   &data_loss,
    193                                   &data_loss_reason,
    194                                   &disk_full,
    195                                   &mock_leveldb_factory3,
    196                                   task_runner,
    197                                   clean_journal);
    198 
    199   MockErrorLevelDBFactory<base::File::Error> mock_leveldb_factory4(
    200       base::File::FILE_ERROR_FAILED, false);
    201   scoped_refptr<IndexedDBBackingStore> backing_store4 =
    202       IndexedDBBackingStore::Open(factory,
    203                                   origin,
    204                                   path,
    205                                   request_context,
    206                                   &data_loss,
    207                                   &data_loss_reason,
    208                                   &disk_full,
    209                                   &mock_leveldb_factory4,
    210                                   task_runner,
    211                                   clean_journal);
    212 }
    213 
    214 }  // namespace
    215