Home | History | Annotate | Download | only in indexed_db
      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