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/indexed_db_transaction.h"
9 #include "content/browser/indexed_db/leveldb/leveldb_iterator_impl.h"
10 #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
11 #include "content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h"
12 #include "third_party/leveldatabase/env_chromium.h"
13 #include "third_party/leveldatabase/src/include/leveldb/status.h"
17 class FunctionTracer
{
19 FunctionTracer(const std::string
& class_name
,
20 const std::string
& method_name
,
22 : class_name_(class_name
),
23 method_name_(method_name
),
24 instance_count_(instance_num
),
25 current_call_num_(0) {}
29 VLOG(0) << class_name_
<< '[' << instance_count_
<< "]::" << method_name_
30 << "()[" << current_call_num_
<< ']';
34 std::string class_name_
;
35 std::string method_name_
;
37 int current_call_num_
;
44 class IndexedDBTestTransaction
: public IndexedDBTransaction
{
46 IndexedDBTestTransaction(
48 scoped_refptr
<IndexedDBDatabaseCallbacks
> callbacks
,
49 const std::set
<int64
>& scope
,
50 blink::WebIDBTransactionMode mode
,
51 IndexedDBDatabase
* db
,
52 IndexedDBBackingStore::Transaction
* backing_store_transaction
)
53 : IndexedDBTransaction(id
,
58 backing_store_transaction
) {}
61 ~IndexedDBTestTransaction() override
{}
63 // Browser tests run under memory/address sanitizers (etc) may trip the
64 // default 60s timeout, so relax it during tests.
65 base::TimeDelta
GetInactivityTimeout() const override
{
66 return base::TimeDelta::FromSeconds(60 * 60);
70 class LevelDBTestTransaction
: public LevelDBTransaction
{
72 LevelDBTestTransaction(LevelDBDatabase
* db
,
73 FailMethod fail_method
,
75 : LevelDBTransaction(db
),
76 fail_method_(fail_method
),
77 fail_on_call_num_(fail_on_call_num
),
78 current_call_num_(0) {
79 DCHECK(fail_method
!= FAIL_METHOD_NOTHING
);
80 DCHECK_GT(fail_on_call_num
, 0);
83 leveldb::Status
Get(const base::StringPiece
& key
,
85 bool* found
) override
{
86 if (fail_method_
!= FAIL_METHOD_GET
||
87 ++current_call_num_
!= fail_on_call_num_
)
88 return LevelDBTransaction::Get(key
, value
, found
);
91 return leveldb::Status::Corruption("Corrupted for the test");
94 leveldb::Status
Commit() override
{
95 if ((fail_method_
!= FAIL_METHOD_COMMIT
&&
96 fail_method_
!= FAIL_METHOD_COMMIT_DISK_FULL
) ||
97 ++current_call_num_
!= fail_on_call_num_
)
98 return LevelDBTransaction::Commit();
100 // TODO(jsbell): Consider parameterizing the failure mode.
101 if (fail_method_
== FAIL_METHOD_COMMIT_DISK_FULL
) {
102 return leveldb_env::MakeIOError("dummy filename", "Disk Full",
103 leveldb_env::kWritableFileAppend
,
104 base::File::FILE_ERROR_NO_SPACE
);
107 return leveldb::Status::Corruption("Corrupted for the test");
111 ~LevelDBTestTransaction() override
{}
113 FailMethod fail_method_
;
114 int fail_on_call_num_
;
115 int current_call_num_
;
118 class LevelDBTraceTransaction
: public LevelDBTransaction
{
120 LevelDBTraceTransaction(LevelDBDatabase
* db
, int tx_num
)
121 : LevelDBTransaction(db
),
122 commit_tracer_(s_class_name
, "Commit", tx_num
),
123 get_tracer_(s_class_name
, "Get", tx_num
) {}
125 leveldb::Status
Get(const base::StringPiece
& key
,
127 bool* found
) override
{
128 get_tracer_
.log_call();
129 return LevelDBTransaction::Get(key
, value
, found
);
132 leveldb::Status
Commit() override
{
133 commit_tracer_
.log_call();
134 return LevelDBTransaction::Commit();
138 static const std::string s_class_name
;
140 ~LevelDBTraceTransaction() override
{}
142 FunctionTracer commit_tracer_
;
143 FunctionTracer get_tracer_
;
146 const std::string
LevelDBTraceTransaction::s_class_name
= "LevelDBTransaction";
148 class LevelDBTraceIteratorImpl
: public LevelDBIteratorImpl
{
150 LevelDBTraceIteratorImpl(scoped_ptr
<leveldb::Iterator
> iterator
, int inst_num
)
151 : LevelDBIteratorImpl(iterator
.Pass()),
152 is_valid_tracer_(s_class_name
, "IsValid", inst_num
),
153 seek_to_last_tracer_(s_class_name
, "SeekToLast", inst_num
),
154 seek_tracer_(s_class_name
, "Seek", inst_num
),
155 next_tracer_(s_class_name
, "Next", inst_num
),
156 prev_tracer_(s_class_name
, "Prev", inst_num
),
157 key_tracer_(s_class_name
, "Key", inst_num
),
158 value_tracer_(s_class_name
, "Value", inst_num
) {}
159 ~LevelDBTraceIteratorImpl() override
{}
162 static const std::string s_class_name
;
164 bool IsValid() const override
{
165 is_valid_tracer_
.log_call();
166 return LevelDBIteratorImpl::IsValid();
168 leveldb::Status
SeekToLast() override
{
169 seek_to_last_tracer_
.log_call();
170 return LevelDBIteratorImpl::SeekToLast();
172 leveldb::Status
Seek(const base::StringPiece
& target
) override
{
173 seek_tracer_
.log_call();
174 return LevelDBIteratorImpl::Seek(target
);
176 leveldb::Status
Next() override
{
177 next_tracer_
.log_call();
178 return LevelDBIteratorImpl::Next();
180 leveldb::Status
Prev() override
{
181 prev_tracer_
.log_call();
182 return LevelDBIteratorImpl::Prev();
184 base::StringPiece
Key() const override
{
185 key_tracer_
.log_call();
186 return LevelDBIteratorImpl::Key();
188 base::StringPiece
Value() const override
{
189 value_tracer_
.log_call();
190 return LevelDBIteratorImpl::Value();
193 mutable FunctionTracer is_valid_tracer_
;
194 mutable FunctionTracer seek_to_last_tracer_
;
195 mutable FunctionTracer seek_tracer_
;
196 mutable FunctionTracer next_tracer_
;
197 mutable FunctionTracer prev_tracer_
;
198 mutable FunctionTracer key_tracer_
;
199 mutable FunctionTracer value_tracer_
;
202 const std::string
LevelDBTraceIteratorImpl::s_class_name
= "LevelDBIterator";
204 class LevelDBTestIteratorImpl
: public content::LevelDBIteratorImpl
{
206 LevelDBTestIteratorImpl(scoped_ptr
<leveldb::Iterator
> iterator
,
207 FailMethod fail_method
,
208 int fail_on_call_num
)
209 : LevelDBIteratorImpl(iterator
.Pass()),
210 fail_method_(fail_method
),
211 fail_on_call_num_(fail_on_call_num
),
212 current_call_num_(0) {}
213 ~LevelDBTestIteratorImpl() override
{}
216 leveldb::Status
Seek(const base::StringPiece
& target
) override
{
217 if (fail_method_
!= FAIL_METHOD_SEEK
||
218 ++current_call_num_
!= fail_on_call_num_
)
219 return LevelDBIteratorImpl::Seek(target
);
220 return leveldb::Status::Corruption("Corrupted for test");
223 FailMethod fail_method_
;
224 int fail_on_call_num_
;
225 int current_call_num_
;
228 MockBrowserTestIndexedDBClassFactory::MockBrowserTestIndexedDBClassFactory()
229 : failure_class_(FAIL_CLASS_NOTHING
),
230 failure_method_(FAIL_METHOD_NOTHING
),
231 only_trace_calls_(false) {
234 MockBrowserTestIndexedDBClassFactory::~MockBrowserTestIndexedDBClassFactory() {
237 IndexedDBTransaction
*
238 MockBrowserTestIndexedDBClassFactory::CreateIndexedDBTransaction(
240 scoped_refptr
<IndexedDBDatabaseCallbacks
> callbacks
,
241 const std::set
<int64
>& scope
,
242 blink::WebIDBTransactionMode mode
,
243 IndexedDBDatabase
* db
,
244 IndexedDBBackingStore::Transaction
* backing_store_transaction
) {
245 return new IndexedDBTestTransaction(id
, callbacks
, scope
, mode
, db
,
246 backing_store_transaction
);
250 MockBrowserTestIndexedDBClassFactory::CreateLevelDBTransaction(
251 LevelDBDatabase
* db
) {
252 instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
] =
253 instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
] + 1;
254 if (only_trace_calls_
) {
255 return new LevelDBTraceTransaction(
256 db
, instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
]);
258 if (failure_class_
== FAIL_CLASS_LEVELDB_TRANSACTION
&&
259 instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
] ==
260 fail_on_instance_num_
[FAIL_CLASS_LEVELDB_TRANSACTION
]) {
261 return new LevelDBTestTransaction(
264 fail_on_call_num_
[FAIL_CLASS_LEVELDB_TRANSACTION
]);
266 return IndexedDBClassFactory::CreateLevelDBTransaction(db
);
271 LevelDBIteratorImpl
* MockBrowserTestIndexedDBClassFactory::CreateIteratorImpl(
272 scoped_ptr
<leveldb::Iterator
> iterator
) {
273 instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
] =
274 instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
] + 1;
275 if (only_trace_calls_
) {
276 return new LevelDBTraceIteratorImpl(
277 iterator
.Pass(), instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
]);
279 if (failure_class_
== FAIL_CLASS_LEVELDB_ITERATOR
&&
280 instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
] ==
281 fail_on_instance_num_
[FAIL_CLASS_LEVELDB_ITERATOR
]) {
282 return new LevelDBTestIteratorImpl(
285 fail_on_call_num_
[FAIL_CLASS_LEVELDB_ITERATOR
]);
287 return new LevelDBIteratorImpl(iterator
.Pass());
292 void MockBrowserTestIndexedDBClassFactory::FailOperation(
293 FailClass failure_class
,
294 FailMethod failure_method
,
295 int fail_on_instance_num
,
296 int fail_on_call_num
) {
297 VLOG(0) << "FailOperation: class=" << failure_class
298 << ", method=" << failure_method
299 << ", instanceNum=" << fail_on_instance_num
300 << ", callNum=" << fail_on_call_num
;
301 DCHECK(failure_class
!= FAIL_CLASS_NOTHING
);
302 DCHECK(failure_method
!= FAIL_METHOD_NOTHING
);
303 failure_class_
= failure_class
;
304 failure_method_
= failure_method
;
305 fail_on_instance_num_
[failure_class_
] = fail_on_instance_num
;
306 fail_on_call_num_
[failure_class_
] = fail_on_call_num
;
307 instance_count_
.clear();
310 void MockBrowserTestIndexedDBClassFactory::Reset() {
311 failure_class_
= FAIL_CLASS_NOTHING
;
312 failure_method_
= FAIL_METHOD_NOTHING
;
313 instance_count_
.clear();
314 fail_on_instance_num_
.clear();
315 fail_on_call_num_
.clear();
318 } // namespace content