blob: 0014070b3a2e789c92262ea6d59433c66b76202c [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "base/logging.h"
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
#include "content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
namespace {
class FunctionTracer {
public:
FunctionTracer(const std::string& class_name,
const std::string& method_name,
int instance_num)
: class_name_(class_name),
method_name_(method_name),
instance_count_(instance_num),
current_call_num_(0) {}
void log_call() {
current_call_num_++;
VLOG(0) << class_name_ << '[' << instance_count_ << "]::" << method_name_
<< "()[" << current_call_num_ << ']';
}
private:
std::string class_name_;
std::string method_name_;
int instance_count_;
int current_call_num_;
};
} // namespace
namespace content {
class LevelDBTestTansaction : public LevelDBTransaction {
public:
LevelDBTestTansaction(LevelDBDatabase* db,
FailMethod fail_method,
int fail_on_call_num)
: LevelDBTransaction(db),
fail_method_(fail_method),
fail_on_call_num_(fail_on_call_num),
current_call_num_(0) {
DCHECK(fail_method != FAIL_METHOD_NOTHING);
DCHECK_GT(fail_on_call_num, 0);
}
virtual leveldb::Status Get(const base::StringPiece& key,
std::string* value,
bool* found) OVERRIDE {
if (fail_method_ != FAIL_METHOD_GET ||
++current_call_num_ != fail_on_call_num_)
return LevelDBTransaction::Get(key, value, found);
*found = false;
return leveldb::Status::Corruption("Corrupted for the test");
}
virtual leveldb::Status Commit() OVERRIDE {
if (fail_method_ != FAIL_METHOD_COMMIT ||
++current_call_num_ != fail_on_call_num_)
return LevelDBTransaction::Commit();
return leveldb::Status::Corruption("Corrupted for the test");
}
private:
virtual ~LevelDBTestTansaction() {}
FailMethod fail_method_;
int fail_on_call_num_;
int current_call_num_;
};
class LevelDBTraceTansaction : public LevelDBTransaction {
public:
LevelDBTraceTansaction(LevelDBDatabase* db, int tx_num)
: LevelDBTransaction(db),
commit_tracer_(s_class_name, "Commit", tx_num),
get_tracer_(s_class_name, "Get", tx_num) {}
virtual leveldb::Status Get(const base::StringPiece& key,
std::string* value,
bool* found) OVERRIDE {
get_tracer_.log_call();
return LevelDBTransaction::Get(key, value, found);
}
virtual leveldb::Status Commit() OVERRIDE {
commit_tracer_.log_call();
return LevelDBTransaction::Commit();
}
private:
virtual ~LevelDBTraceTansaction() {}
const static std::string s_class_name;
FunctionTracer commit_tracer_;
FunctionTracer get_tracer_;
};
const std::string LevelDBTraceTansaction::s_class_name = "LevelDBTransaction";
MockBrowserTestIndexedDBClassFactory::MockBrowserTestIndexedDBClassFactory()
: failure_class_(FAIL_CLASS_NOTHING),
failure_method_(FAIL_METHOD_NOTHING),
only_trace_calls_(false) {
}
MockBrowserTestIndexedDBClassFactory::~MockBrowserTestIndexedDBClassFactory() {
}
LevelDBTransaction*
MockBrowserTestIndexedDBClassFactory::CreateLevelDBTransaction(
LevelDBDatabase* db) {
instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] =
instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] + 1;
if (only_trace_calls_) {
return new LevelDBTraceTansaction(
db, instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION]);
} else {
if (failure_class_ == FAIL_CLASS_LEVELDB_TRANSACTION &&
instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] ==
fail_on_instance_num_[FAIL_CLASS_LEVELDB_TRANSACTION]) {
return new LevelDBTestTansaction(
db,
failure_method_,
fail_on_call_num_[FAIL_CLASS_LEVELDB_TRANSACTION]);
} else {
return IndexedDBClassFactory::CreateLevelDBTransaction(db);
}
}
}
void MockBrowserTestIndexedDBClassFactory::FailOperation(
FailClass failure_class,
FailMethod failure_method,
int fail_on_instance_num,
int fail_on_call_num) {
VLOG(0) << "FailOperation: class=" << failure_class
<< ", method=" << failure_method
<< ", instanceNum=" << fail_on_instance_num
<< ", callNum=" << fail_on_call_num;
DCHECK(failure_class != FAIL_CLASS_NOTHING);
DCHECK(failure_method != FAIL_METHOD_NOTHING);
failure_class_ = failure_class;
failure_method_ = failure_method;
fail_on_instance_num_[failure_class_] = fail_on_instance_num;
fail_on_call_num_[failure_class_] = fail_on_call_num;
instance_count_.clear();
}
void MockBrowserTestIndexedDBClassFactory::Reset() {
failure_class_ = FAIL_CLASS_NOTHING;
failure_method_ = FAIL_METHOD_NOTHING;
instance_count_.clear();
fail_on_instance_num_.clear();
fail_on_call_num_.clear();
}
} // namespace content