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