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 IndexedDBTestDatabase
: public IndexedDBDatabase
{
46 IndexedDBTestDatabase(const base::string16
& name
,
47 IndexedDBBackingStore
* backing_store
,
48 IndexedDBFactory
* factory
,
49 const IndexedDBDatabase::Identifier
& unique_identifier
)
50 : IndexedDBDatabase(name
, backing_store
, factory
, unique_identifier
) {}
53 ~IndexedDBTestDatabase() override
{}
55 size_t GetMaxMessageSizeInBytes() const override
{
56 return 10 * 1024 * 1024; // 10MB
60 class IndexedDBTestTransaction
: public IndexedDBTransaction
{
62 IndexedDBTestTransaction(
64 scoped_refptr
<IndexedDBDatabaseCallbacks
> callbacks
,
65 const std::set
<int64
>& scope
,
66 blink::WebIDBTransactionMode mode
,
67 IndexedDBDatabase
* db
,
68 IndexedDBBackingStore::Transaction
* backing_store_transaction
)
69 : IndexedDBTransaction(id
,
74 backing_store_transaction
) {}
77 ~IndexedDBTestTransaction() override
{}
79 // Browser tests run under memory/address sanitizers (etc) may trip the
80 // default 60s timeout, so relax it during tests.
81 base::TimeDelta
GetInactivityTimeout() const override
{
82 return base::TimeDelta::FromSeconds(60 * 60);
86 class LevelDBTestTransaction
: public LevelDBTransaction
{
88 LevelDBTestTransaction(LevelDBDatabase
* db
,
89 FailMethod fail_method
,
91 : LevelDBTransaction(db
),
92 fail_method_(fail_method
),
93 fail_on_call_num_(fail_on_call_num
),
94 current_call_num_(0) {
95 DCHECK(fail_method
!= FAIL_METHOD_NOTHING
);
96 DCHECK_GT(fail_on_call_num
, 0);
99 leveldb::Status
Get(const base::StringPiece
& key
,
101 bool* found
) override
{
102 if (fail_method_
!= FAIL_METHOD_GET
||
103 ++current_call_num_
!= fail_on_call_num_
)
104 return LevelDBTransaction::Get(key
, value
, found
);
107 return leveldb::Status::Corruption("Corrupted for the test");
110 leveldb::Status
Commit() override
{
111 if ((fail_method_
!= FAIL_METHOD_COMMIT
&&
112 fail_method_
!= FAIL_METHOD_COMMIT_DISK_FULL
) ||
113 ++current_call_num_
!= fail_on_call_num_
)
114 return LevelDBTransaction::Commit();
116 // TODO(jsbell): Consider parameterizing the failure mode.
117 if (fail_method_
== FAIL_METHOD_COMMIT_DISK_FULL
) {
118 return leveldb_env::MakeIOError("dummy filename", "Disk Full",
119 leveldb_env::kWritableFileAppend
,
120 base::File::FILE_ERROR_NO_SPACE
);
123 return leveldb::Status::Corruption("Corrupted for the test");
127 ~LevelDBTestTransaction() override
{}
129 FailMethod fail_method_
;
130 int fail_on_call_num_
;
131 int current_call_num_
;
134 class LevelDBTraceTransaction
: public LevelDBTransaction
{
136 LevelDBTraceTransaction(LevelDBDatabase
* db
, int tx_num
)
137 : LevelDBTransaction(db
),
138 commit_tracer_(s_class_name
, "Commit", tx_num
),
139 get_tracer_(s_class_name
, "Get", tx_num
) {}
141 leveldb::Status
Get(const base::StringPiece
& key
,
143 bool* found
) override
{
144 get_tracer_
.log_call();
145 return LevelDBTransaction::Get(key
, value
, found
);
148 leveldb::Status
Commit() override
{
149 commit_tracer_
.log_call();
150 return LevelDBTransaction::Commit();
154 static const std::string s_class_name
;
156 ~LevelDBTraceTransaction() override
{}
158 FunctionTracer commit_tracer_
;
159 FunctionTracer get_tracer_
;
162 const std::string
LevelDBTraceTransaction::s_class_name
= "LevelDBTransaction";
164 class LevelDBTraceIteratorImpl
: public LevelDBIteratorImpl
{
166 LevelDBTraceIteratorImpl(scoped_ptr
<leveldb::Iterator
> iterator
, int inst_num
)
167 : LevelDBIteratorImpl(iterator
.Pass()),
168 is_valid_tracer_(s_class_name
, "IsValid", inst_num
),
169 seek_to_last_tracer_(s_class_name
, "SeekToLast", inst_num
),
170 seek_tracer_(s_class_name
, "Seek", inst_num
),
171 next_tracer_(s_class_name
, "Next", inst_num
),
172 prev_tracer_(s_class_name
, "Prev", inst_num
),
173 key_tracer_(s_class_name
, "Key", inst_num
),
174 value_tracer_(s_class_name
, "Value", inst_num
) {}
175 ~LevelDBTraceIteratorImpl() override
{}
178 static const std::string s_class_name
;
180 bool IsValid() const override
{
181 is_valid_tracer_
.log_call();
182 return LevelDBIteratorImpl::IsValid();
184 leveldb::Status
SeekToLast() override
{
185 seek_to_last_tracer_
.log_call();
186 return LevelDBIteratorImpl::SeekToLast();
188 leveldb::Status
Seek(const base::StringPiece
& target
) override
{
189 seek_tracer_
.log_call();
190 return LevelDBIteratorImpl::Seek(target
);
192 leveldb::Status
Next() override
{
193 next_tracer_
.log_call();
194 return LevelDBIteratorImpl::Next();
196 leveldb::Status
Prev() override
{
197 prev_tracer_
.log_call();
198 return LevelDBIteratorImpl::Prev();
200 base::StringPiece
Key() const override
{
201 key_tracer_
.log_call();
202 return LevelDBIteratorImpl::Key();
204 base::StringPiece
Value() const override
{
205 value_tracer_
.log_call();
206 return LevelDBIteratorImpl::Value();
209 mutable FunctionTracer is_valid_tracer_
;
210 mutable FunctionTracer seek_to_last_tracer_
;
211 mutable FunctionTracer seek_tracer_
;
212 mutable FunctionTracer next_tracer_
;
213 mutable FunctionTracer prev_tracer_
;
214 mutable FunctionTracer key_tracer_
;
215 mutable FunctionTracer value_tracer_
;
218 const std::string
LevelDBTraceIteratorImpl::s_class_name
= "LevelDBIterator";
220 class LevelDBTestIteratorImpl
: public content::LevelDBIteratorImpl
{
222 LevelDBTestIteratorImpl(scoped_ptr
<leveldb::Iterator
> iterator
,
223 FailMethod fail_method
,
224 int fail_on_call_num
)
225 : LevelDBIteratorImpl(iterator
.Pass()),
226 fail_method_(fail_method
),
227 fail_on_call_num_(fail_on_call_num
),
228 current_call_num_(0) {}
229 ~LevelDBTestIteratorImpl() override
{}
232 leveldb::Status
Seek(const base::StringPiece
& target
) override
{
233 if (fail_method_
!= FAIL_METHOD_SEEK
||
234 ++current_call_num_
!= fail_on_call_num_
)
235 return LevelDBIteratorImpl::Seek(target
);
236 return leveldb::Status::Corruption("Corrupted for test");
239 FailMethod fail_method_
;
240 int fail_on_call_num_
;
241 int current_call_num_
;
244 MockBrowserTestIndexedDBClassFactory::MockBrowserTestIndexedDBClassFactory()
245 : failure_class_(FAIL_CLASS_NOTHING
),
246 failure_method_(FAIL_METHOD_NOTHING
),
247 only_trace_calls_(false) {
250 MockBrowserTestIndexedDBClassFactory::~MockBrowserTestIndexedDBClassFactory() {
254 MockBrowserTestIndexedDBClassFactory::CreateIndexedDBDatabase(
255 const base::string16
& name
,
256 IndexedDBBackingStore
* backing_store
,
257 IndexedDBFactory
* factory
,
258 const IndexedDBDatabase::Identifier
& unique_identifier
) {
259 return new IndexedDBTestDatabase(name
, backing_store
, factory
,
263 IndexedDBTransaction
*
264 MockBrowserTestIndexedDBClassFactory::CreateIndexedDBTransaction(
266 scoped_refptr
<IndexedDBDatabaseCallbacks
> callbacks
,
267 const std::set
<int64
>& scope
,
268 blink::WebIDBTransactionMode mode
,
269 IndexedDBDatabase
* db
,
270 IndexedDBBackingStore::Transaction
* backing_store_transaction
) {
271 return new IndexedDBTestTransaction(id
, callbacks
, scope
, mode
, db
,
272 backing_store_transaction
);
276 MockBrowserTestIndexedDBClassFactory::CreateLevelDBTransaction(
277 LevelDBDatabase
* db
) {
278 instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
] =
279 instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
] + 1;
280 if (only_trace_calls_
) {
281 return new LevelDBTraceTransaction(
282 db
, instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
]);
284 if (failure_class_
== FAIL_CLASS_LEVELDB_TRANSACTION
&&
285 instance_count_
[FAIL_CLASS_LEVELDB_TRANSACTION
] ==
286 fail_on_instance_num_
[FAIL_CLASS_LEVELDB_TRANSACTION
]) {
287 return new LevelDBTestTransaction(
290 fail_on_call_num_
[FAIL_CLASS_LEVELDB_TRANSACTION
]);
292 return IndexedDBClassFactory::CreateLevelDBTransaction(db
);
297 LevelDBIteratorImpl
* MockBrowserTestIndexedDBClassFactory::CreateIteratorImpl(
298 scoped_ptr
<leveldb::Iterator
> iterator
) {
299 instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
] =
300 instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
] + 1;
301 if (only_trace_calls_
) {
302 return new LevelDBTraceIteratorImpl(
303 iterator
.Pass(), instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
]);
305 if (failure_class_
== FAIL_CLASS_LEVELDB_ITERATOR
&&
306 instance_count_
[FAIL_CLASS_LEVELDB_ITERATOR
] ==
307 fail_on_instance_num_
[FAIL_CLASS_LEVELDB_ITERATOR
]) {
308 return new LevelDBTestIteratorImpl(
311 fail_on_call_num_
[FAIL_CLASS_LEVELDB_ITERATOR
]);
313 return new LevelDBIteratorImpl(iterator
.Pass());
318 void MockBrowserTestIndexedDBClassFactory::FailOperation(
319 FailClass failure_class
,
320 FailMethod failure_method
,
321 int fail_on_instance_num
,
322 int fail_on_call_num
) {
323 VLOG(0) << "FailOperation: class=" << failure_class
324 << ", method=" << failure_method
325 << ", instanceNum=" << fail_on_instance_num
326 << ", callNum=" << fail_on_call_num
;
327 DCHECK(failure_class
!= FAIL_CLASS_NOTHING
);
328 DCHECK(failure_method
!= FAIL_METHOD_NOTHING
);
329 failure_class_
= failure_class
;
330 failure_method_
= failure_method
;
331 fail_on_instance_num_
[failure_class_
] = fail_on_instance_num
;
332 fail_on_call_num_
[failure_class_
] = fail_on_call_num
;
333 instance_count_
.clear();
336 void MockBrowserTestIndexedDBClassFactory::Reset() {
337 failure_class_
= FAIL_CLASS_NOTHING
;
338 failure_method_
= FAIL_METHOD_NOTHING
;
339 instance_count_
.clear();
340 fail_on_instance_num_
.clear();
341 fail_on_call_num_
.clear();
344 } // namespace content