1 // Copyright 2014 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 <string> 6 7 #include "base/logging.h" 8 #include "content/browser/indexed_db/leveldb/leveldb_iterator_impl.h" 9 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" 10 #include "content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h" 11 #include "third_party/leveldatabase/src/include/leveldb/status.h" 12 13 namespace { 14 15 class FunctionTracer { 16 public: 17 FunctionTracer(const std::string& class_name, 18 const std::string& method_name, 19 int instance_num) 20 : class_name_(class_name), 21 method_name_(method_name), 22 instance_count_(instance_num), 23 current_call_num_(0) {} 24 25 void log_call() { 26 current_call_num_++; 27 VLOG(0) << class_name_ << '[' << instance_count_ << "]::" << method_name_ 28 << "()[" << current_call_num_ << ']'; 29 } 30 31 private: 32 std::string class_name_; 33 std::string method_name_; 34 int instance_count_; 35 int current_call_num_; 36 }; 37 38 } // namespace 39 40 namespace content { 41 42 class LevelDBTestTansaction : public LevelDBTransaction { 43 public: 44 LevelDBTestTansaction(LevelDBDatabase* db, 45 FailMethod fail_method, 46 int fail_on_call_num) 47 : LevelDBTransaction(db), 48 fail_method_(fail_method), 49 fail_on_call_num_(fail_on_call_num), 50 current_call_num_(0) { 51 DCHECK(fail_method != FAIL_METHOD_NOTHING); 52 DCHECK_GT(fail_on_call_num, 0); 53 } 54 55 virtual leveldb::Status Get(const base::StringPiece& key, 56 std::string* value, 57 bool* found) OVERRIDE { 58 if (fail_method_ != FAIL_METHOD_GET || 59 ++current_call_num_ != fail_on_call_num_) 60 return LevelDBTransaction::Get(key, value, found); 61 62 *found = false; 63 return leveldb::Status::Corruption("Corrupted for the test"); 64 } 65 66 virtual leveldb::Status Commit() OVERRIDE { 67 if (fail_method_ != FAIL_METHOD_COMMIT || 68 ++current_call_num_ != fail_on_call_num_) 69 return LevelDBTransaction::Commit(); 70 71 return leveldb::Status::Corruption("Corrupted for the test"); 72 } 73 74 private: 75 virtual ~LevelDBTestTansaction() {} 76 77 FailMethod fail_method_; 78 int fail_on_call_num_; 79 int current_call_num_; 80 }; 81 82 class LevelDBTraceTansaction : public LevelDBTransaction { 83 public: 84 LevelDBTraceTansaction(LevelDBDatabase* db, int tx_num) 85 : LevelDBTransaction(db), 86 commit_tracer_(s_class_name, "Commit", tx_num), 87 get_tracer_(s_class_name, "Get", tx_num) {} 88 89 virtual leveldb::Status Get(const base::StringPiece& key, 90 std::string* value, 91 bool* found) OVERRIDE { 92 get_tracer_.log_call(); 93 return LevelDBTransaction::Get(key, value, found); 94 } 95 96 virtual leveldb::Status Commit() OVERRIDE { 97 commit_tracer_.log_call(); 98 return LevelDBTransaction::Commit(); 99 } 100 101 private: 102 static const std::string s_class_name; 103 104 virtual ~LevelDBTraceTansaction() {} 105 106 FunctionTracer commit_tracer_; 107 FunctionTracer get_tracer_; 108 }; 109 110 const std::string LevelDBTraceTansaction::s_class_name = "LevelDBTransaction"; 111 112 class LevelDBTraceIteratorImpl : public LevelDBIteratorImpl { 113 public: 114 LevelDBTraceIteratorImpl(scoped_ptr<leveldb::Iterator> iterator, int inst_num) 115 : LevelDBIteratorImpl(iterator.Pass()), 116 is_valid_tracer_(s_class_name, "IsValid", inst_num), 117 seek_to_last_tracer_(s_class_name, "SeekToLast", inst_num), 118 seek_tracer_(s_class_name, "Seek", inst_num), 119 next_tracer_(s_class_name, "Next", inst_num), 120 prev_tracer_(s_class_name, "Prev", inst_num), 121 key_tracer_(s_class_name, "Key", inst_num), 122 value_tracer_(s_class_name, "Value", inst_num) {} 123 virtual ~LevelDBTraceIteratorImpl() {} 124 125 private: 126 static const std::string s_class_name; 127 128 virtual bool IsValid() const OVERRIDE { 129 is_valid_tracer_.log_call(); 130 return LevelDBIteratorImpl::IsValid(); 131 } 132 virtual leveldb::Status SeekToLast() OVERRIDE { 133 seek_to_last_tracer_.log_call(); 134 return LevelDBIteratorImpl::SeekToLast(); 135 } 136 virtual leveldb::Status Seek(const base::StringPiece& target) OVERRIDE { 137 seek_tracer_.log_call(); 138 return LevelDBIteratorImpl::Seek(target); 139 } 140 virtual leveldb::Status Next() OVERRIDE { 141 next_tracer_.log_call(); 142 return LevelDBIteratorImpl::Next(); 143 } 144 virtual leveldb::Status Prev() OVERRIDE { 145 prev_tracer_.log_call(); 146 return LevelDBIteratorImpl::Prev(); 147 } 148 virtual base::StringPiece Key() const OVERRIDE { 149 key_tracer_.log_call(); 150 return LevelDBIteratorImpl::Key(); 151 } 152 virtual base::StringPiece Value() const OVERRIDE { 153 value_tracer_.log_call(); 154 return LevelDBIteratorImpl::Value(); 155 } 156 157 mutable FunctionTracer is_valid_tracer_; 158 mutable FunctionTracer seek_to_last_tracer_; 159 mutable FunctionTracer seek_tracer_; 160 mutable FunctionTracer next_tracer_; 161 mutable FunctionTracer prev_tracer_; 162 mutable FunctionTracer key_tracer_; 163 mutable FunctionTracer value_tracer_; 164 }; 165 166 const std::string LevelDBTraceIteratorImpl::s_class_name = "LevelDBIterator"; 167 168 class LevelDBTestIteratorImpl : public content::LevelDBIteratorImpl { 169 public: 170 LevelDBTestIteratorImpl(scoped_ptr<leveldb::Iterator> iterator, 171 FailMethod fail_method, 172 int fail_on_call_num) 173 : LevelDBIteratorImpl(iterator.Pass()), 174 fail_method_(fail_method), 175 fail_on_call_num_(fail_on_call_num), 176 current_call_num_(0) {} 177 virtual ~LevelDBTestIteratorImpl() {} 178 179 private: 180 virtual leveldb::Status Seek(const base::StringPiece& target) OVERRIDE { 181 if (fail_method_ != FAIL_METHOD_SEEK || 182 ++current_call_num_ != fail_on_call_num_) 183 return LevelDBIteratorImpl::Seek(target); 184 return leveldb::Status::Corruption("Corrupted for test"); 185 } 186 187 FailMethod fail_method_; 188 int fail_on_call_num_; 189 int current_call_num_; 190 }; 191 192 MockBrowserTestIndexedDBClassFactory::MockBrowserTestIndexedDBClassFactory() 193 : failure_class_(FAIL_CLASS_NOTHING), 194 failure_method_(FAIL_METHOD_NOTHING), 195 only_trace_calls_(false) { 196 } 197 198 MockBrowserTestIndexedDBClassFactory::~MockBrowserTestIndexedDBClassFactory() { 199 } 200 201 LevelDBTransaction* 202 MockBrowserTestIndexedDBClassFactory::CreateLevelDBTransaction( 203 LevelDBDatabase* db) { 204 instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] = 205 instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] + 1; 206 if (only_trace_calls_) { 207 return new LevelDBTraceTansaction( 208 db, instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION]); 209 } else { 210 if (failure_class_ == FAIL_CLASS_LEVELDB_TRANSACTION && 211 instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] == 212 fail_on_instance_num_[FAIL_CLASS_LEVELDB_TRANSACTION]) { 213 return new LevelDBTestTansaction( 214 db, 215 failure_method_, 216 fail_on_call_num_[FAIL_CLASS_LEVELDB_TRANSACTION]); 217 } else { 218 return IndexedDBClassFactory::CreateLevelDBTransaction(db); 219 } 220 } 221 } 222 223 LevelDBIteratorImpl* MockBrowserTestIndexedDBClassFactory::CreateIteratorImpl( 224 scoped_ptr<leveldb::Iterator> iterator) { 225 instance_count_[FAIL_CLASS_LEVELDB_ITERATOR] = 226 instance_count_[FAIL_CLASS_LEVELDB_ITERATOR] + 1; 227 if (only_trace_calls_) { 228 return new LevelDBTraceIteratorImpl( 229 iterator.Pass(), instance_count_[FAIL_CLASS_LEVELDB_ITERATOR]); 230 } else { 231 if (failure_class_ == FAIL_CLASS_LEVELDB_ITERATOR && 232 instance_count_[FAIL_CLASS_LEVELDB_ITERATOR] == 233 fail_on_instance_num_[FAIL_CLASS_LEVELDB_ITERATOR]) { 234 return new LevelDBTestIteratorImpl( 235 iterator.Pass(), 236 failure_method_, 237 fail_on_call_num_[FAIL_CLASS_LEVELDB_ITERATOR]); 238 } else { 239 return new LevelDBIteratorImpl(iterator.Pass()); 240 } 241 } 242 } 243 244 void MockBrowserTestIndexedDBClassFactory::FailOperation( 245 FailClass failure_class, 246 FailMethod failure_method, 247 int fail_on_instance_num, 248 int fail_on_call_num) { 249 VLOG(0) << "FailOperation: class=" << failure_class 250 << ", method=" << failure_method 251 << ", instanceNum=" << fail_on_instance_num 252 << ", callNum=" << fail_on_call_num; 253 DCHECK(failure_class != FAIL_CLASS_NOTHING); 254 DCHECK(failure_method != FAIL_METHOD_NOTHING); 255 failure_class_ = failure_class; 256 failure_method_ = failure_method; 257 fail_on_instance_num_[failure_class_] = fail_on_instance_num; 258 fail_on_call_num_[failure_class_] = fail_on_call_num; 259 instance_count_.clear(); 260 } 261 262 void MockBrowserTestIndexedDBClassFactory::Reset() { 263 failure_class_ = FAIL_CLASS_NOTHING; 264 failure_method_ = FAIL_METHOD_NOTHING; 265 instance_count_.clear(); 266 fail_on_instance_num_.clear(); 267 fail_on_call_num_.clear(); 268 } 269 270 } // namespace content 271