Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: content/browser/indexed_db/indexed_db_browsertest.cc

Issue 334303002: Using a mock LevelDBTransaction for corruption tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/browser/indexed_db/leveldb/leveldb_transaction.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/bind.h" 5 #include "base/bind.h"
6 #include "base/command_line.h" 6 #include "base/command_line.h"
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/files/file.h" 8 #include "base/files/file.h"
9 #include "base/files/file_enumerator.h" 9 #include "base/files/file_enumerator.h"
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
11 #include "base/lazy_instance.h"
11 #include "base/memory/ref_counted.h" 12 #include "base/memory/ref_counted.h"
12 #include "base/message_loop/message_loop.h" 13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/string_split.h"
13 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
14 #include "base/test/thread_test_helper.h" 16 #include "base/test/thread_test_helper.h"
15 #include "content/browser/browser_main_loop.h" 17 #include "content/browser/browser_main_loop.h"
18 #include "content/browser/indexed_db/indexed_db_class_factory.h"
16 #include "content/browser/indexed_db/indexed_db_context_impl.h" 19 #include "content/browser/indexed_db/indexed_db_context_impl.h"
17 #include "content/browser/web_contents/web_contents_impl.h" 20 #include "content/browser/web_contents/web_contents_impl.h"
18 #include "content/public/browser/browser_context.h" 21 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/browser_thread.h" 22 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/render_process_host.h" 23 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/storage_partition.h" 24 #include "content/public/browser/storage_partition.h"
22 #include "content/public/browser/web_contents.h" 25 #include "content/public/browser/web_contents.h"
23 #include "content/public/common/content_switches.h" 26 #include "content/public/common/content_switches.h"
24 #include "content/public/common/url_constants.h" 27 #include "content/public/common/url_constants.h"
25 #include "content/public/test/browser_test_utils.h" 28 #include "content/public/test/browser_test_utils.h"
26 #include "content/public/test/content_browser_test.h" 29 #include "content/public/test/content_browser_test.h"
27 #include "content/public/test/content_browser_test_utils.h" 30 #include "content/public/test/content_browser_test_utils.h"
28 #include "content/shell/browser/shell.h" 31 #include "content/shell/browser/shell.h"
29 #include "net/base/net_errors.h" 32 #include "net/base/net_errors.h"
30 #include "net/test/embedded_test_server/embedded_test_server.h" 33 #include "net/test/embedded_test_server/embedded_test_server.h"
31 #include "net/test/embedded_test_server/http_request.h" 34 #include "net/test/embedded_test_server/http_request.h"
32 #include "net/test/embedded_test_server/http_response.h" 35 #include "net/test/embedded_test_server/http_response.h"
33 #include "webkit/browser/database/database_util.h" 36 #include "webkit/browser/database/database_util.h"
34 #include "webkit/browser/quota/quota_manager.h" 37 #include "webkit/browser/quota/quota_manager.h"
35 38
36 using base::ASCIIToUTF16; 39 using base::ASCIIToUTF16;
37 using quota::QuotaManager; 40 using quota::QuotaManager;
38 using webkit_database::DatabaseUtil; 41 using webkit_database::DatabaseUtil;
39 42
40 namespace content { 43 namespace content {
41 44
45 enum FailClass {
46 FAIL_CLASS_NOTHING,
47 FAIL_CLASS_LEVELDB_TRANSACTION,
48 };
49
50 enum FailMethod {
51 FAIL_METHOD_NOTHING,
52 FAIL_METHOD_COMMIT,
53 FAIL_METHOD_GET,
54 };
55
56 class FunctionTracer {
57 public:
58 FunctionTracer(const std::string& class_name,
59 const std::string& method_name,
60 int instance_num)
61 : class_name_(class_name),
62 method_name_(method_name),
63 instance_count_(instance_num),
64 current_call_num_(0) {}
65
66 void log_call() {
67 current_call_num_++;
68 VLOG(0) << class_name_ << '[' << instance_count_ << "]::" << method_name_
69 << "()[" << current_call_num_ << ']';
70 }
71
72 private:
73 std::string class_name_;
74 std::string method_name_;
75 int instance_count_;
76 int current_call_num_;
77 };
78
79 class LevelDBTestTansaction : public LevelDBTransaction {
80 public:
81 LevelDBTestTansaction(LevelDBDatabase* db,
82 FailMethod fail_method,
83 int fail_on_call_num)
84 : LevelDBTransaction(db),
85 fail_method_(fail_method),
86 fail_on_call_num_(fail_on_call_num),
87 current_call_num_(0) {
88 DCHECK(fail_method != FAIL_METHOD_NOTHING);
89 DCHECK_GT(fail_on_call_num, 0);
90 }
91
92 virtual leveldb::Status Get(const base::StringPiece& key,
93 std::string* value,
94 bool* found) OVERRIDE {
95 if (fail_method_ != FAIL_METHOD_GET ||
96 ++current_call_num_ != fail_on_call_num_)
97 return LevelDBTransaction::Get(key, value, found);
98
99 *found = false;
100 return leveldb::Status::Corruption("Corrupted for the test");
101 }
102
103 virtual leveldb::Status Commit() OVERRIDE {
104 if (fail_method_ != FAIL_METHOD_COMMIT ||
105 ++current_call_num_ != fail_on_call_num_)
106 return LevelDBTransaction::Commit();
107
108 return leveldb::Status::Corruption("Corrupted for the test");
109 }
110
111 private:
112 virtual ~LevelDBTestTansaction() {}
113
114 FailMethod fail_method_;
115 int fail_on_call_num_;
116 int current_call_num_;
117 };
118
119 class LevelDBTraceTansaction : public LevelDBTransaction {
120 public:
121 LevelDBTraceTansaction(LevelDBDatabase* db, int tx_num)
122 : LevelDBTransaction(db),
123 commit_tracer_(s_class_name, "Commit", tx_num),
124 get_tracer_(s_class_name, "Get", tx_num) {}
125
126 virtual leveldb::Status Get(const base::StringPiece& key,
127 std::string* value,
128 bool* found) OVERRIDE {
129 get_tracer_.log_call();
130 return LevelDBTransaction::Get(key, value, found);
131 }
132
133 virtual leveldb::Status Commit() OVERRIDE {
134 commit_tracer_.log_call();
135 return LevelDBTransaction::Commit();
136 }
137
138 private:
139 virtual ~LevelDBTraceTansaction() {}
140
141 const std::string s_class_name = "LevelDBTransaction";
142
143 FunctionTracer commit_tracer_;
144 FunctionTracer get_tracer_;
145 };
146
147 class IndexedDBBrowserTestClassFactory : public IndexedDBClassFactory {
148 public:
149 IndexedDBBrowserTestClassFactory()
150 : failure_class_(FAIL_CLASS_NOTHING),
151 failure_method_(FAIL_METHOD_NOTHING),
152 only_trace_calls_(false) {}
153 virtual LevelDBTransaction* CreateLevelDBTransaction(
154 LevelDBDatabase* db) OVERRIDE {
155 instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] =
156 instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] + 1;
157 if (only_trace_calls_) {
158 return new LevelDBTraceTansaction(
159 db, instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION]);
160 } else {
161 if (failure_class_ == FAIL_CLASS_LEVELDB_TRANSACTION &&
162 instance_count_[FAIL_CLASS_LEVELDB_TRANSACTION] ==
163 fail_on_instance_num_[FAIL_CLASS_LEVELDB_TRANSACTION])
164 return new LevelDBTestTansaction(
165 db,
166 failure_method_,
167 fail_on_call_num_[FAIL_CLASS_LEVELDB_TRANSACTION]);
168 else
169 return IndexedDBClassFactory::CreateLevelDBTransaction(db);
170 }
171 }
172
173 void FailOperation(FailClass failure_class,
174 FailMethod failure_method,
175 int fail_on_instance_num,
176 int fail_on_call_num) {
177 VLOG(0) << "FailOperation: class=" << failure_class
178 << ", method=" << failure_method
179 << ", instanceNum=" << fail_on_instance_num
180 << ", callNum=" << fail_on_call_num;
181 DCHECK(failure_class != FAIL_CLASS_NOTHING);
182 DCHECK(failure_method != FAIL_METHOD_NOTHING);
183 failure_class_ = failure_class;
184 failure_method_ = failure_method;
185 fail_on_instance_num_[failure_class_] = fail_on_instance_num;
186 fail_on_call_num_[failure_class_] = fail_on_call_num;
187 instance_count_.clear();
188 }
189
190 void Reset() {
191 failure_method_ = FAIL_METHOD_NOTHING;
192 instance_count_.clear();
193 fail_on_instance_num_.clear();
194 fail_on_call_num_.clear();
195 }
196
197 private:
198 FailClass failure_class_;
199 FailMethod failure_method_;
200 std::map<FailClass, int> instance_count_;
201 std::map<FailClass, int> fail_on_instance_num_;
202 std::map<FailClass, int> fail_on_call_num_;
203 bool only_trace_calls_;
204 };
205
206 static ::base::LazyInstance<IndexedDBBrowserTestClassFactory>::Leaky s_factory =
207 LAZY_INSTANCE_INITIALIZER;
208
42 // This browser test is aimed towards exercising the IndexedDB bindings and 209 // This browser test is aimed towards exercising the IndexedDB bindings and
43 // the actual implementation that lives in the browser side. 210 // the actual implementation that lives in the browser side.
44 class IndexedDBBrowserTest : public ContentBrowserTest { 211 class IndexedDBBrowserTest : public ContentBrowserTest {
45 public: 212 public:
46 IndexedDBBrowserTest() : disk_usage_(-1) {} 213 IndexedDBBrowserTest()
214 : disk_usage_(-1),
215 test_class_factory_(new IndexedDBBrowserTestClassFactory) {}
ericu 2014/06/17 01:12:53 Is test_class_factory_ actually used somewhere? I
cmumford 2014/06/17 16:29:24 Embarrassingly no :-|
216
217 static IndexedDBClassFactory* GetIDBClassFactory() {
218 return s_factory.Pointer();
219 }
220
221 virtual void SetUp() OVERRIDE {
222 s_factory.Get().Reset();
223 IndexedDBClassFactory::SetIndexedDBClassFactoryGetter(GetIDBClassFactory);
224 ContentBrowserTest::SetUp();
225 }
226
227 virtual void TearDown() OVERRIDE {
228 IndexedDBClassFactory::SetIndexedDBClassFactoryGetter(NULL);
ericu 2014/06/17 01:12:53 Given this cleanup, do we need s_factory to be a s
cmumford 2014/06/17 16:29:24 I was able to eliminate the use of s_factory in Co
229 ContentBrowserTest::TearDown();
230 }
47 231
48 void SimpleTest(const GURL& test_url, bool incognito = false) { 232 void SimpleTest(const GURL& test_url, bool incognito = false) {
49 // The test page will perform tests on IndexedDB, then navigate to either 233 // The test page will perform tests on IndexedDB, then navigate to either
50 // a #pass or #fail ref. 234 // a #pass or #fail ref.
51 Shell* the_browser = incognito ? CreateOffTheRecordBrowser() : shell(); 235 Shell* the_browser = incognito ? CreateOffTheRecordBrowser() : shell();
52 236
53 VLOG(0) << "Navigating to URL and blocking."; 237 VLOG(0) << "Navigating to URL and blocking.";
54 NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2); 238 NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2);
55 VLOG(0) << "Navigation done."; 239 VLOG(0) << "Navigation done.";
56 std::string result = 240 std::string result =
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 return disk_usage_; 310 return disk_usage_;
127 } 311 }
128 312
129 private: 313 private:
130 virtual void DidGetDiskUsage(int64 bytes) { 314 virtual void DidGetDiskUsage(int64 bytes) {
131 EXPECT_GT(bytes, 0); 315 EXPECT_GT(bytes, 0);
132 disk_usage_ = bytes; 316 disk_usage_ = bytes;
133 } 317 }
134 318
135 int64 disk_usage_; 319 int64 disk_usage_;
320 IndexedDBBrowserTestClassFactory* test_class_factory_;
136 321
137 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTest); 322 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTest);
138 }; 323 };
139 324
140 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) { 325 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
141 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html")); 326 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"));
142 } 327 }
143 328
144 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) { 329 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) {
145 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"), 330 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"),
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 const net::test_server::HttpRequest& request) { 630 const net::test_server::HttpRequest& request) {
446 631
447 std::string request_path; 632 std::string request_path;
448 if (path.find(s_corrupt_db_test_prefix) != std::string::npos) 633 if (path.find(s_corrupt_db_test_prefix) != std::string::npos)
449 request_path = request.relative_url.substr(s_corrupt_db_test_prefix.size()); 634 request_path = request.relative_url.substr(s_corrupt_db_test_prefix.size());
450 else 635 else
451 return scoped_ptr<net::test_server::HttpResponse>(); 636 return scoped_ptr<net::test_server::HttpResponse>();
452 637
453 // Remove the query string if present. 638 // Remove the query string if present.
454 std::string request_query; 639 std::string request_query;
640 std::vector<std::pair<std::string, std::string> > query_params;
455 size_t query_pos = request_path.find('?'); 641 size_t query_pos = request_path.find('?');
456 if (query_pos != std::string::npos) { 642 if (query_pos != std::string::npos) {
457 request_query = request_path.substr(query_pos + 1); 643 request_query = request_path.substr(query_pos + 1);
458 request_path = request_path.substr(0, query_pos); 644 request_path = request_path.substr(0, query_pos);
645
646 base::SplitStringIntoKeyValuePairs(request_query, '=', '&', &query_params);
459 } 647 }
460 648
461 if (request_path == "corruptdb" && !request_query.empty()) { 649 if (request_path == "corruptdb" && !request_query.empty()) {
462 VLOG(0) << "Requested to corrupt IndexedDB: " << request_query; 650 VLOG(0) << "Requested to corrupt IndexedDB: " << request_query;
463 base::WaitableEvent signal_when_finished(false, false); 651 base::WaitableEvent signal_when_finished(false, false);
464 context->TaskRunner()->PostTask(FROM_HERE, 652 context->TaskRunner()->PostTask(FROM_HERE,
465 base::Bind(&CorruptIndexedDBDatabase, 653 base::Bind(&CorruptIndexedDBDatabase,
466 base::ConstRef(context), 654 base::ConstRef(context),
467 origin_url, 655 origin_url,
468 &signal_when_finished)); 656 &signal_when_finished));
469 signal_when_finished.Wait(); 657 signal_when_finished.Wait();
470 658
471 scoped_ptr<net::test_server::BasicHttpResponse> http_response( 659 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
472 new net::test_server::BasicHttpResponse); 660 new net::test_server::BasicHttpResponse);
473 http_response->set_code(net::HTTP_OK); 661 http_response->set_code(net::HTTP_OK);
474 return http_response.PassAs<net::test_server::HttpResponse>(); 662 return http_response.PassAs<net::test_server::HttpResponse>();
663 } else if (request_path == "fail" && !query_params.empty()) {
664 FailClass failure_class = FAIL_CLASS_NOTHING;
665 FailMethod failure_method = FAIL_METHOD_NOTHING;
666 int instance_num = 1;
667 int call_num = 1;
668 std::string fail_class;
669 std::string fail_method;
670
671 for (std::vector<std::pair<std::string, std::string> >::iterator it =
672 query_params.begin();
673 it != query_params.end();
674 it++) {
675 if (it->first == "method")
676 fail_method = it->second;
677 else if (it->first == "class")
678 fail_class = it->second;
679 else if (it->first == "num")
ericu 2014/06/17 01:12:53 Should "num" be qualified, just as "callNum" is?
cmumford 2014/06/17 16:29:24 How about "instNum"?
ericu 2014/06/17 17:03:04 Sure.
680 instance_num = atoi(it->second.c_str());
681 else if (it->first == "callNum")
682 call_num = atoi(it->second.c_str());
683 else {
684 VLOG(0) << "Unknown param: \"" << it->first << '"';
685 NOTREACHED();
686 }
687 }
688
689 if (fail_class == "LevelDBTransaction") {
690 failure_class = FAIL_CLASS_LEVELDB_TRANSACTION;
691 if (fail_method == "Get")
692 failure_method = FAIL_METHOD_GET;
693 else if (fail_method == "Commit")
694 failure_method = FAIL_METHOD_COMMIT;
695 }
ericu 2014/06/17 01:12:53 else...? It's undoubtedly a typo of some sort.
cmumford 2014/06/17 16:29:24 Done. A DCHECK would have caught the error, but a
696
697 DCHECK(instance_num >= 1);
698 DCHECK(call_num >= 1);
699
700 s_factory.Get().FailOperation(
701 failure_class, failure_method, instance_num, call_num);
702
703 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
704 new net::test_server::BasicHttpResponse);
705 http_response->set_code(net::HTTP_OK);
706 return http_response.PassAs<net::test_server::HttpResponse>();
707 } else if (request_path == "nothing") {
ericu 2014/06/17 01:12:53 Is this clause needed by anything, or do you have
cmumford 2014/06/17 16:29:24 Oops - shouldn't have been there. I was experiment
708 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
709 new net::test_server::BasicHttpResponse);
710 http_response->set_code(net::HTTP_OK);
711 return http_response.PassAs<net::test_server::HttpResponse>();
475 } 712 }
476 713
477 // A request for a test resource 714 // A request for a test resource
478 base::FilePath resourcePath = 715 base::FilePath resourcePath =
479 content::GetTestFilePath("indexeddb", request_path.c_str()); 716 content::GetTestFilePath("indexeddb", request_path.c_str());
480 scoped_ptr<net::test_server::BasicHttpResponse> http_response( 717 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
481 new net::test_server::BasicHttpResponse); 718 new net::test_server::BasicHttpResponse);
482 http_response->set_code(net::HTTP_OK); 719 http_response->set_code(net::HTTP_OK);
483 std::string file_contents; 720 std::string file_contents;
484 if (!base::ReadFileToString(resourcePath, &file_contents)) 721 if (!base::ReadFileToString(resourcePath, &file_contents))
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 #define MAYBE_RenderThreadShutdownTest DISABLED_RenderThreadShutdownTest 866 #define MAYBE_RenderThreadShutdownTest DISABLED_RenderThreadShutdownTest
630 #else 867 #else
631 #define MAYBE_RenderThreadShutdownTest RenderThreadShutdownTest 868 #define MAYBE_RenderThreadShutdownTest RenderThreadShutdownTest
632 #endif 869 #endif
633 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestSingleProcess, 870 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestSingleProcess,
634 MAYBE_RenderThreadShutdownTest) { 871 MAYBE_RenderThreadShutdownTest) {
635 SimpleTest(GetTestUrl("indexeddb", "shutdown_with_requests.html")); 872 SimpleTest(GetTestUrl("indexeddb", "shutdown_with_requests.html"));
636 } 873 }
637 874
638 } // namespace content 875 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/browser/indexed_db/leveldb/leveldb_transaction.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698