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.
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/env_chromium.h"
12 #include "third_party/leveldatabase/src/include/leveldb/status.h"
16 class FunctionTracer
{
18 FunctionTracer(const std::string
& class_name
,
19 const std::string
& method_name
,
21 : class_name_(class_name
),
22 method_name_(method_name
),
23 instance_count_(instance_num
),
24 current_call_num_(0) {}
28 VLOG(0) << class_name_
<< '[' << instance_count_
<< "]::" << method_name_
29 << "()[" << current_call_num_
<< ']';
33 std::string class_name_
;
34 std::string method_name_
;
36 int current_call_num_
;
43 class LevelDBTestTransaction
: public LevelDBTransaction
{
45 LevelDBTestTransaction(LevelDBDatabase
* db
,
46 FailMethod fail_method
,
48 : LevelDBTransaction(db
),
49 fail_method_(fail_method
),
50 fail_on_call_num_(fail_on_call_num
),
51 current_call_num_(0) {
52 DCHECK(fail_method
!= FAIL_METHOD_NOTHING
);
53 DCHECK_GT(fail_on_call_num
, 0);
56 leveldb::Status
Get(const base::StringPiece
& key
,
58 bool* found
) override
{
59 if (fail_method_
!= FAIL_METHOD_GET
||
60 ++current_call_num_
!= fail_on_call_num_
)
61 return LevelDBTransaction::Get(key
, value
, found
);
64 return leveldb::Status::Corruption("Corrupted for the test");
67 leveldb::Status
Commit() override
{
68 if ((fail_method_
!= FAIL_METHOD_COMMIT
&&
69 fail_method_
!= FAIL_METHOD_COMMIT_DISK_FULL
) ||
70 ++current_call_num_
!= fail_on_call_num_
)
71 return LevelDBTransaction::Commit();
73 // TODO(jsbell): Consider parameterizing the failure mode.
74 if (fail_method_
== FAIL_METHOD_COMMIT_DISK_FULL
) {
75 return leveldb_env::MakeIOError("dummy filename", "Disk Full",
76 leveldb_env::kWritableFileAppend
,
77 base::File::FILE_ERROR_NO_SPACE
);
80 return leveldb::Status::Corruption("Corrupted for the test");
84 ~LevelDBTestTransaction() override
{}
86 FailMethod fail_method_
;
87 int fail_on_call_num_
;
88 int current_call_num_
;
91 class LevelDBTraceTransaction
: public LevelDBTransaction
{
93 LevelDBTraceTransaction(LevelDBDatabase
* db
, int tx_num
)
94 : LevelDBTransaction(db
),
95 commit_tracer_(s_class_name
, "Commit", tx_num
),
96 get_tracer_(s_class_name
, "Get", tx_num
) {}
98 leveldb::Status
Get(const base::StringPiece
& key
,
100 bool* found
) override
{
101 get_tracer_
.log_call();
102 return LevelDBTransaction::Get(key
, value
, found
);
105 leveldb::Status
Commit() override
{
106 commit_tracer_
.log_call();
107 return LevelDBTransaction::Commit();
111 static const std::string s_class_name
;
113 ~LevelDBTraceTransaction() override
{}
115 FunctionTracer commit_tracer_
;
116 FunctionTracer get_tracer_
;
119 const std::string
LevelDBTraceTransaction::s_class_name
= "LevelDBTransaction";
121 class LevelDBTraceIteratorImpl
: public LevelDBIteratorImpl
{
123 LevelDBTraceIteratorImpl(scoped_ptr
<leveldb::Iterator
> iterator
, int inst_num
)
124 : LevelDBIteratorImpl(iterator
.Pass()),
125 is_valid_tracer_(s_class_name
, "IsValid", inst_num
),
126 seek_to_last_tracer_(s_class_name
, "SeekToLast", inst_num
),
127 seek_tracer_(s_class_name
, "Seek", inst_num
),
128 next_tracer_(s_class_name
, "Next", inst_num
),
129 prev_tracer_(s_class_name
, "Prev", inst_num
),
130 key_tracer_(s_class_name
, "Key", inst_num
),
131 value_tracer_(s_class_name
, "Value", inst_num
) {}
132 ~LevelDBTraceIteratorImpl() override
{}
135 static const std::string s_class_name
;
137 bool IsValid() const override
{
138 is_valid_tracer_
.log_call();
139 return LevelDBIteratorImpl::IsValid();
141 leveldb::Status
SeekToLast() override
{
142 seek_to_last_tracer_
.log_call();
143 return LevelDBIteratorImpl::SeekToLast();
145 leveldb::Status
Seek(const base::StringPiece
& target
) override
{
146 seek_tracer_
.log_call();
147 return LevelDBIteratorImpl::Seek(target
);
149 leveldb::Status
Next() override
{
150 next_tracer_
.log_call();
151 return LevelDBIteratorImpl::Next();
153 leveldb::Status
Prev() override
{
154 prev_tracer_
.log_call();
155 return LevelDBIteratorImpl::Prev();
157 base::StringPiece
Key() const override
{
158 key_tracer_
.log_call();
159 return LevelDBIteratorImpl::Key();
161 base::StringPiece
Value() const override
{
162 value_tracer_
.log_call();
163 return LevelDBIteratorImpl::Value();
166 mutable FunctionTracer is_valid_tracer_
;
167 mutable FunctionTracer seek_to_last_tracer_
;
168 mutable FunctionTracer seek_tracer_
;
169 mutable FunctionTracer next_tracer_
;
170 mutable FunctionTracer prev_tracer_
;
171 mutable FunctionTracer key_tracer_
;
172 mutable FunctionTracer value_tracer_
;
175 const std::string
LevelDBTraceIteratorImpl::s_class_name
= "LevelDBIterator";
177 class LevelDBTestIteratorImpl
: public content::LevelDBIteratorImpl
{
179 LevelDBTestIteratorImpl(scoped_ptr
<leveldb::Iterator
> iterator
,
180 FailMethod fail_method
,
181 int fail_on_call_num
)
182 : LevelDBIteratorImpl(iterator
.Pass()),
183 fail_method_(fail_method
),
184 fail_on_call_num_(fail_on_call_num
),
185 current_call_num_(0) {}
186 ~LevelDBTestIteratorImpl() override
{}
189 leveldb::Status
Seek(const base::StringPiece
& target
) override
{
190 if (fail_method_
!= FAIL_METHOD_SEEK
||
191 ++current_call_num_
!= fail_on_call_num_
)
192 return LevelDBIteratorImpl::Seek(target
);
193 return leveldb::Status::Corruption("Corrupted for test");
196 FailMethod fail_method_
;
197 int fail_on_call_num_
;
198 int current_call_num_
;
201 MockBrowserTestIndexedDBClassFactory::MockBrowserTestIndexedDBClassFactory()
202 : failure_class_(FAIL_CLASS_NOTHING
),
203 failure_method_(FAIL_METHOD_NOTHING
),
204 only_trace_calls_(false) {
207 MockBrowserTestIndexedDBClassFactory::~MockBrowserTestIndexedDBClassFactory() {
211 MockBrowserTestIndexedDBClassFactory::CreateLevelDBTransaction(
212 LevelDBDatabase
* db
) {
213 instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
] =
214 instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
] + 1;
215 if (only_trace_calls_
) {
216 return new LevelDBTraceTransaction(
217 db
, instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
]);
219 if (failure_class_
== FAIL_CLASS_LEVELDB_TRANSACTION
&&
220 instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
] ==
221 fail_on_instance_num_
[FAIL_CLASS_LEVELDB_TRANSACTION
]) {
222 return new LevelDBTestTransaction(
225 fail_on_call_num_
[FAIL_CLASS_LEVELDB_TRANSACTION
]);
227 return IndexedDBClassFactory::CreateLevelDBTransaction(db
);
232 LevelDBIteratorImpl
* MockBrowserTestIndexedDBClassFactory::CreateIteratorImpl(
233 scoped_ptr
<leveldb::Iterator
> iterator
) {
234 instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
] =
235 instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
] + 1;
236 if (only_trace_calls_
) {
237 return new LevelDBTraceIteratorImpl(
238 iterator
.Pass(), instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
]);
240 if (failure_class_
== FAIL_CLASS_LEVELDB_ITERATOR
&&
241 instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
] ==
242 fail_on_instance_num_
[FAIL_CLASS_LEVELDB_ITERATOR
]) {
243 return new LevelDBTestIteratorImpl(
246 fail_on_call_num_
[FAIL_CLASS_LEVELDB_ITERATOR
]);
248 return new LevelDBIteratorImpl(iterator
.Pass());
253 void MockBrowserTestIndexedDBClassFactory::FailOperation(
254 FailClass failure_class
,
255 FailMethod failure_method
,
256 int fail_on_instance_num
,
257 int fail_on_call_num
) {
258 VLOG(0) << "FailOperation: class=" << failure_class
259 << ", method=" << failure_method
260 << ", instanceNum=" << fail_on_instance_num
261 << ", callNum=" << fail_on_call_num
;
262 DCHECK(failure_class
!= FAIL_CLASS_NOTHING
);
263 DCHECK(failure_method
!= FAIL_METHOD_NOTHING
);
264 failure_class_
= failure_class
;
265 failure_method_
= failure_method
;
266 fail_on_instance_num_
[failure_class_
] = fail_on_instance_num
;
267 fail_on_call_num_
[failure_class_
] = fail_on_call_num
;
268 instance_count_
.clear();
271 void MockBrowserTestIndexedDBClassFactory::Reset() {
272 failure_class_
= FAIL_CLASS_NOTHING
;
273 failure_method_
= FAIL_METHOD_NOTHING
;
274 instance_count_
.clear();
275 fail_on_instance_num_
.clear();
276 fail_on_call_num_
.clear();
279 } // namespace content