Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / indexed_db / indexed_db_browsertest.cc
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
3 // found in the LICENSE file.
4
5 #include "base/bind.h"
6 #include "base/command_line.h"
7 #include "base/files/file.h"
8 #include "base/files/file_enumerator.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/lazy_instance.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/test/thread_test_helper.h"
16 #include "content/browser/browser_main_loop.h"
17 #include "content/browser/indexed_db/indexed_db_class_factory.h"
18 #include "content/browser/indexed_db/indexed_db_context_impl.h"
19 #include "content/browser/indexed_db/mock_browsertest_indexed_db_class_factory.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/storage_partition.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/common/content_switches.h"
27 #include "content/public/common/url_constants.h"
28 #include "content/public/test/browser_test_utils.h"
29 #include "content/public/test/content_browser_test.h"
30 #include "content/public/test/content_browser_test_utils.h"
31 #include "content/shell/browser/shell.h"
32 #include "net/base/escape.h"
33 #include "net/base/net_errors.h"
34 #include "net/test/embedded_test_server/embedded_test_server.h"
35 #include "net/test/embedded_test_server/http_request.h"
36 #include "net/test/embedded_test_server/http_response.h"
37 #include "storage/browser/database/database_util.h"
38 #include "storage/browser/quota/quota_manager.h"
39
40 using base::ASCIIToUTF16;
41 using storage::QuotaManager;
42 using storage::DatabaseUtil;
43
44 namespace content {
45
46 // This browser test is aimed towards exercising the IndexedDB bindings and
47 // the actual implementation that lives in the browser side.
48 class IndexedDBBrowserTest : public ContentBrowserTest {
49  public:
50   IndexedDBBrowserTest() : disk_usage_(-1) {}
51
52   virtual void SetUp() OVERRIDE {
53     GetTestClassFactory()->Reset();
54     IndexedDBClassFactory::SetIndexedDBClassFactoryGetter(GetIDBClassFactory);
55     ContentBrowserTest::SetUp();
56   }
57
58   virtual void TearDown() OVERRIDE {
59     IndexedDBClassFactory::SetIndexedDBClassFactoryGetter(NULL);
60     ContentBrowserTest::TearDown();
61   }
62
63   void FailOperation(FailClass failure_class,
64                      FailMethod failure_method,
65                      int fail_on_instance_num,
66                      int fail_on_call_num) {
67     GetTestClassFactory()->FailOperation(
68         failure_class, failure_method, fail_on_instance_num, fail_on_call_num);
69   }
70
71   void SimpleTest(const GURL& test_url, bool incognito = false) {
72     // The test page will perform tests on IndexedDB, then navigate to either
73     // a #pass or #fail ref.
74     Shell* the_browser = incognito ? CreateOffTheRecordBrowser() : shell();
75
76     VLOG(0) << "Navigating to URL and blocking.";
77     NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2);
78     VLOG(0) << "Navigation done.";
79     std::string result =
80         the_browser->web_contents()->GetLastCommittedURL().ref();
81     if (result != "pass") {
82       std::string js_result;
83       ASSERT_TRUE(ExecuteScriptAndExtractString(
84           the_browser->web_contents(),
85           "window.domAutomationController.send(getLog())",
86           &js_result));
87       FAIL() << "Failed: " << js_result;
88     }
89   }
90
91   void NavigateAndWaitForTitle(Shell* shell,
92                                const char* filename,
93                                const char* hash,
94                                const char* expected_string) {
95     GURL url = GetTestUrl("indexeddb", filename);
96     if (hash)
97       url = GURL(url.spec() + hash);
98
99     base::string16 expected_title16(ASCIIToUTF16(expected_string));
100     TitleWatcher title_watcher(shell->web_contents(), expected_title16);
101     NavigateToURL(shell, url);
102     EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
103   }
104
105   IndexedDBContextImpl* GetContext() {
106     StoragePartition* partition =
107         BrowserContext::GetDefaultStoragePartition(
108             shell()->web_contents()->GetBrowserContext());
109     return static_cast<IndexedDBContextImpl*>(partition->GetIndexedDBContext());
110   }
111
112   void SetQuota(int quotaKilobytes) {
113     const int kTemporaryStorageQuotaSize = quotaKilobytes
114         * 1024 * QuotaManager::kPerHostTemporaryPortion;
115     SetTempQuota(kTemporaryStorageQuotaSize,
116         BrowserContext::GetDefaultStoragePartition(
117             shell()->web_contents()->GetBrowserContext())->GetQuotaManager());
118   }
119
120   static void SetTempQuota(int64 bytes, scoped_refptr<QuotaManager> qm) {
121     if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
122       BrowserThread::PostTask(
123           BrowserThread::IO, FROM_HERE,
124           base::Bind(&IndexedDBBrowserTest::SetTempQuota, bytes, qm));
125       return;
126     }
127     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
128     qm->SetTemporaryGlobalOverrideQuota(bytes, storage::QuotaCallback());
129     // Don't return until the quota has been set.
130     scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
131         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
132     ASSERT_TRUE(helper->Run());
133   }
134
135   virtual int64 RequestDiskUsage() {
136     PostTaskAndReplyWithResult(
137         GetContext()->TaskRunner(),
138         FROM_HERE,
139         base::Bind(&IndexedDBContext::GetOriginDiskUsage,
140                    GetContext(),
141                    GURL("file:///")),
142         base::Bind(&IndexedDBBrowserTest::DidGetDiskUsage, this));
143     scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
144         BrowserMainLoop::GetInstance()->indexed_db_thread()->
145             message_loop_proxy()));
146     EXPECT_TRUE(helper->Run());
147     // Wait for DidGetDiskUsage to be called.
148     base::MessageLoop::current()->RunUntilIdle();
149     return disk_usage_;
150   }
151
152  private:
153   static MockBrowserTestIndexedDBClassFactory* GetTestClassFactory() {
154     static ::base::LazyInstance<MockBrowserTestIndexedDBClassFactory>::Leaky
155         s_factory = LAZY_INSTANCE_INITIALIZER;
156     return s_factory.Pointer();
157   }
158
159   static IndexedDBClassFactory* GetIDBClassFactory() {
160     return GetTestClassFactory();
161   }
162
163   virtual void DidGetDiskUsage(int64 bytes) {
164     EXPECT_GT(bytes, 0);
165     disk_usage_ = bytes;
166   }
167
168   int64 disk_usage_;
169
170   DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTest);
171 };
172
173 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
174   SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"));
175 }
176
177 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) {
178   SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"),
179              true /* incognito */);
180 }
181
182 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorPrefetch) {
183   SimpleTest(GetTestUrl("indexeddb", "cursor_prefetch.html"));
184 }
185
186 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, IndexTest) {
187   SimpleTest(GetTestUrl("indexeddb", "index_test.html"));
188 }
189
190 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyPathTest) {
191   SimpleTest(GetTestUrl("indexeddb", "key_path_test.html"));
192 }
193
194 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
195   SimpleTest(GetTestUrl("indexeddb", "transaction_get_test.html"));
196 }
197
198 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyTypesTest) {
199   SimpleTest(GetTestUrl("indexeddb", "key_types_test.html"));
200 }
201
202 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ObjectStoreTest) {
203   SimpleTest(GetTestUrl("indexeddb", "object_store_test.html"));
204 }
205
206 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
207   SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
208 }
209
210 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionTest) {
211   SimpleTest(GetTestUrl("indexeddb", "transaction_test.html"));
212 }
213
214 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CallbackAccounting) {
215   SimpleTest(GetTestUrl("indexeddb", "callback_accounting.html"));
216 }
217
218 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DoesntHangTest) {
219   SimpleTest(GetTestUrl("indexeddb", "transaction_run_forever.html"));
220   CrashTab(shell()->web_contents());
221   SimpleTest(GetTestUrl("indexeddb", "transaction_not_blocked.html"));
222 }
223
224 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug84933Test) {
225   const GURL url = GetTestUrl("indexeddb", "bug_84933.html");
226
227   // Just navigate to the URL. Test will crash if it fails.
228   NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
229 }
230
231 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug106883Test) {
232   const GURL url = GetTestUrl("indexeddb", "bug_106883.html");
233
234   // Just navigate to the URL. Test will crash if it fails.
235   NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
236 }
237
238 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug109187Test) {
239   const GURL url = GetTestUrl("indexeddb", "bug_109187.html");
240
241   // Just navigate to the URL. Test will crash if it fails.
242   NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
243 }
244
245 class IndexedDBBrowserTestWithLowQuota : public IndexedDBBrowserTest {
246  public:
247   IndexedDBBrowserTestWithLowQuota() {}
248
249   virtual void SetUpOnMainThread() OVERRIDE {
250     const int kInitialQuotaKilobytes = 5000;
251     SetQuota(kInitialQuotaKilobytes);
252   }
253
254  private:
255   DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTestWithLowQuota);
256 };
257
258 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithLowQuota, QuotaTest) {
259   SimpleTest(GetTestUrl("indexeddb", "quota_test.html"));
260 }
261
262 class IndexedDBBrowserTestWithGCExposed : public IndexedDBBrowserTest {
263  public:
264   IndexedDBBrowserTestWithGCExposed() {}
265
266   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
267     command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
268   }
269
270  private:
271   DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTestWithGCExposed);
272 };
273
274 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed,
275                        DatabaseCallbacksTest) {
276   SimpleTest(GetTestUrl("indexeddb", "database_callbacks_first.html"));
277 }
278
279 static void CopyLevelDBToProfile(Shell* shell,
280                                  scoped_refptr<IndexedDBContextImpl> context,
281                                  const std::string& test_directory) {
282   DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
283   base::FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
284   base::FilePath test_data_dir =
285       GetTestFilePath("indexeddb", test_directory.c_str()).Append(leveldb_dir);
286   base::FilePath dest = context->data_path().Append(leveldb_dir);
287   // If we don't create the destination directory first, the contents of the
288   // leveldb directory are copied directly into profile/IndexedDB instead of
289   // profile/IndexedDB/file__0.xxx/
290   ASSERT_TRUE(base::CreateDirectory(dest));
291   const bool kRecursive = true;
292   ASSERT_TRUE(base::CopyDirectory(test_data_dir,
293                                   context->data_path(),
294                                   kRecursive));
295 }
296
297 class IndexedDBBrowserTestWithPreexistingLevelDB : public IndexedDBBrowserTest {
298  public:
299   IndexedDBBrowserTestWithPreexistingLevelDB() {}
300   virtual void SetUpOnMainThread() OVERRIDE {
301     scoped_refptr<IndexedDBContextImpl> context = GetContext();
302     context->TaskRunner()->PostTask(
303         FROM_HERE,
304         base::Bind(
305             &CopyLevelDBToProfile, shell(), context, EnclosingLevelDBDir()));
306     scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
307         BrowserMainLoop::GetInstance()->indexed_db_thread()->
308             message_loop_proxy()));
309     ASSERT_TRUE(helper->Run());
310   }
311
312   virtual std::string EnclosingLevelDBDir() = 0;
313
314  private:
315   DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTestWithPreexistingLevelDB);
316 };
317
318 class IndexedDBBrowserTestWithVersion0Schema : public
319     IndexedDBBrowserTestWithPreexistingLevelDB {
320   virtual std::string EnclosingLevelDBDir() OVERRIDE {
321     return "migration_from_0";
322   }
323 };
324
325 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion0Schema, MigrationTest) {
326   SimpleTest(GetTestUrl("indexeddb", "migration_test.html"));
327 }
328
329 class IndexedDBBrowserTestWithVersion123456Schema : public
330     IndexedDBBrowserTestWithPreexistingLevelDB {
331   virtual std::string EnclosingLevelDBDir() OVERRIDE {
332     return "schema_version_123456";
333   }
334 };
335
336 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion123456Schema,
337                        DestroyTest) {
338   int64 original_size = RequestDiskUsage();
339   EXPECT_GT(original_size, 0);
340   SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
341   int64 new_size = RequestDiskUsage();
342   EXPECT_NE(original_size, new_size);
343 }
344
345 class IndexedDBBrowserTestWithVersion987654SSVData : public
346     IndexedDBBrowserTestWithPreexistingLevelDB {
347   virtual std::string EnclosingLevelDBDir() OVERRIDE {
348     return "ssv_version_987654";
349   }
350 };
351
352 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion987654SSVData,
353                        DestroyTest) {
354   int64 original_size = RequestDiskUsage();
355   EXPECT_GT(original_size, 0);
356   SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
357   int64 new_size = RequestDiskUsage();
358   EXPECT_NE(original_size, new_size);
359 }
360
361 class IndexedDBBrowserTestWithCorruptLevelDB : public
362     IndexedDBBrowserTestWithPreexistingLevelDB {
363   virtual std::string EnclosingLevelDBDir() OVERRIDE {
364     return "corrupt_leveldb";
365   }
366 };
367
368 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithCorruptLevelDB,
369                        DestroyTest) {
370   int64 original_size = RequestDiskUsage();
371   EXPECT_GT(original_size, 0);
372   SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
373   int64 new_size = RequestDiskUsage();
374   EXPECT_NE(original_size, new_size);
375 }
376
377 class IndexedDBBrowserTestWithMissingSSTFile : public
378     IndexedDBBrowserTestWithPreexistingLevelDB {
379   virtual std::string EnclosingLevelDBDir() OVERRIDE {
380     return "missing_sst";
381   }
382 };
383
384 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithMissingSSTFile,
385                        DestroyTest) {
386   int64 original_size = RequestDiskUsage();
387   EXPECT_GT(original_size, 0);
388   SimpleTest(GetTestUrl("indexeddb", "open_missing_table.html"));
389   int64 new_size = RequestDiskUsage();
390   EXPECT_NE(original_size, new_size);
391 }
392
393 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, LevelDBLogFileTest) {
394   // Any page that opens an IndexedDB will work here.
395   SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
396   base::FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
397   base::FilePath log_file(FILE_PATH_LITERAL("LOG"));
398   base::FilePath log_file_path =
399       GetContext()->data_path().Append(leveldb_dir).Append(log_file);
400   int64 size;
401   EXPECT_TRUE(base::GetFileSize(log_file_path, &size));
402   EXPECT_GT(size, 0);
403 }
404
405 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CanDeleteWhenOverQuotaTest) {
406   SimpleTest(GetTestUrl("indexeddb", "fill_up_5k.html"));
407   int64 size = RequestDiskUsage();
408   const int kQuotaKilobytes = 2;
409   EXPECT_GT(size, kQuotaKilobytes * 1024);
410   SetQuota(kQuotaKilobytes);
411   SimpleTest(GetTestUrl("indexeddb", "delete_over_quota.html"));
412 }
413
414 namespace {
415
416 static void CompactIndexedDBBackingStore(
417     scoped_refptr<IndexedDBContextImpl> context,
418     const GURL& origin_url) {
419   IndexedDBFactory* factory = context->GetIDBFactory();
420
421   std::pair<IndexedDBFactory::OriginDBMapIterator,
422             IndexedDBFactory::OriginDBMapIterator> range =
423       factory->GetOpenDatabasesForOrigin(origin_url);
424
425   if (range.first == range.second)  // If no open db's for this origin
426     return;
427
428   // Compact the first db's backing store since all the db's are in the same
429   // backing store.
430   IndexedDBDatabase* db = range.first->second;
431   IndexedDBBackingStore* backing_store = db->backing_store();
432   backing_store->Compact();
433 }
434
435 static void CorruptIndexedDBDatabase(
436     IndexedDBContextImpl* context,
437     const GURL& origin_url,
438     base::WaitableEvent* signal_when_finished) {
439
440   CompactIndexedDBBackingStore(context, origin_url);
441
442   int numFiles = 0;
443   int numErrors = 0;
444   base::FilePath idb_data_path = context->GetFilePath(origin_url);
445   const bool recursive = false;
446   base::FileEnumerator enumerator(
447       idb_data_path, recursive, base::FileEnumerator::FILES);
448   for (base::FilePath idb_file = enumerator.Next(); !idb_file.empty();
449        idb_file = enumerator.Next()) {
450     int64 size(0);
451     GetFileSize(idb_file, &size);
452
453     if (idb_file.Extension() == FILE_PATH_LITERAL(".ldb")) {
454       numFiles++;
455       base::File file(idb_file,
456                       base::File::FLAG_WRITE | base::File::FLAG_OPEN_TRUNCATED);
457       if (file.IsValid()) {
458         // Was opened truncated, expand back to the original
459         // file size and fill with zeros (corrupting the file).
460         file.SetLength(size);
461       } else {
462         numErrors++;
463       }
464     }
465   }
466
467   VLOG(0) << "There were " << numFiles << " in " << idb_data_path.value()
468           << " with " << numErrors << " errors";
469   signal_when_finished->Signal();
470 }
471
472 const std::string s_corrupt_db_test_prefix = "/corrupt/test/";
473
474 static scoped_ptr<net::test_server::HttpResponse> CorruptDBRequestHandler(
475     IndexedDBContextImpl* context,
476     const GURL& origin_url,
477     const std::string& path,
478     IndexedDBBrowserTest* test,
479     const net::test_server::HttpRequest& request) {
480   std::string request_path;
481   if (path.find(s_corrupt_db_test_prefix) != std::string::npos)
482     request_path = request.relative_url.substr(s_corrupt_db_test_prefix.size());
483   else
484     return scoped_ptr<net::test_server::HttpResponse>();
485
486   // Remove the query string if present.
487   std::string request_query;
488   size_t query_pos = request_path.find('?');
489   if (query_pos != std::string::npos) {
490     request_query = request_path.substr(query_pos + 1);
491     request_path = request_path.substr(0, query_pos);
492   }
493
494   if (request_path == "corruptdb" && !request_query.empty()) {
495     VLOG(0) << "Requested to corrupt IndexedDB: " << request_query;
496     base::WaitableEvent signal_when_finished(false, false);
497     context->TaskRunner()->PostTask(FROM_HERE,
498                                     base::Bind(&CorruptIndexedDBDatabase,
499                                                base::ConstRef(context),
500                                                origin_url,
501                                                &signal_when_finished));
502     signal_when_finished.Wait();
503
504     scoped_ptr<net::test_server::BasicHttpResponse> http_response(
505         new net::test_server::BasicHttpResponse);
506     http_response->set_code(net::HTTP_OK);
507     return http_response.PassAs<net::test_server::HttpResponse>();
508   } else if (request_path == "fail" && !request_query.empty()) {
509     FailClass failure_class = FAIL_CLASS_NOTHING;
510     FailMethod failure_method = FAIL_METHOD_NOTHING;
511     int instance_num = 1;
512     int call_num = 1;
513     std::string fail_class;
514     std::string fail_method;
515
516     url::Component query(0, request_query.length()), key_pos, value_pos;
517     while (url::ExtractQueryKeyValue(
518         request_query.c_str(), &query, &key_pos, &value_pos)) {
519       std::string escaped_key(request_query.substr(key_pos.begin, key_pos.len));
520       std::string escaped_value(
521           request_query.substr(value_pos.begin, value_pos.len));
522
523       std::string key = net::UnescapeURLComponent(
524           escaped_key,
525           net::UnescapeRule::NORMAL | net::UnescapeRule::SPACES |
526               net::UnescapeRule::URL_SPECIAL_CHARS);
527
528       std::string value = net::UnescapeURLComponent(
529           escaped_value,
530           net::UnescapeRule::NORMAL | net::UnescapeRule::SPACES |
531               net::UnescapeRule::URL_SPECIAL_CHARS);
532
533       if (key == "method")
534         fail_method = value;
535       else if (key == "class")
536         fail_class = value;
537       else if (key == "instNum")
538         instance_num = atoi(value.c_str());
539       else if (key == "callNum")
540         call_num = atoi(value.c_str());
541       else
542         NOTREACHED() << "Unknown param: \"" << key << "\"";
543     }
544
545     if (fail_class == "LevelDBTransaction") {
546       failure_class = FAIL_CLASS_LEVELDB_TRANSACTION;
547       if (fail_method == "Get")
548         failure_method = FAIL_METHOD_GET;
549       else if (fail_method == "Commit")
550         failure_method = FAIL_METHOD_COMMIT;
551       else
552         NOTREACHED() << "Unknown method: \"" << fail_method << "\"";
553     } else if (fail_class == "LevelDBIterator") {
554       failure_class = FAIL_CLASS_LEVELDB_ITERATOR;
555       if (fail_method == "Seek")
556         failure_method = FAIL_METHOD_SEEK;
557       else
558         NOTREACHED() << "Unknown method: \"" << fail_method << "\"";
559     } else {
560       NOTREACHED() << "Unknown class: \"" << fail_class << "\"";
561     }
562
563     DCHECK_GE(instance_num, 1);
564     DCHECK_GE(call_num, 1);
565
566     test->FailOperation(failure_class, failure_method, instance_num, call_num);
567
568     scoped_ptr<net::test_server::BasicHttpResponse> http_response(
569         new net::test_server::BasicHttpResponse);
570     http_response->set_code(net::HTTP_OK);
571     return http_response.PassAs<net::test_server::HttpResponse>();
572   }
573
574   // A request for a test resource
575   base::FilePath resourcePath =
576       content::GetTestFilePath("indexeddb", request_path.c_str());
577   scoped_ptr<net::test_server::BasicHttpResponse> http_response(
578       new net::test_server::BasicHttpResponse);
579   http_response->set_code(net::HTTP_OK);
580   std::string file_contents;
581   if (!base::ReadFileToString(resourcePath, &file_contents))
582     return scoped_ptr<net::test_server::HttpResponse>();
583   http_response->set_content(file_contents);
584   return http_response.PassAs<net::test_server::HttpResponse>();
585 }
586
587 }  // namespace
588
589 class IndexedDBBrowserCorruptionTest
590     : public IndexedDBBrowserTest,
591       public ::testing::WithParamInterface<const char*> {};
592
593 IN_PROC_BROWSER_TEST_P(IndexedDBBrowserCorruptionTest,
594                        OperationOnCorruptedOpenDatabase) {
595   ASSERT_TRUE(embedded_test_server()->Started() ||
596               embedded_test_server()->InitializeAndWaitUntilReady());
597   const GURL& origin_url = embedded_test_server()->base_url();
598   embedded_test_server()->RegisterRequestHandler(
599       base::Bind(&CorruptDBRequestHandler,
600                  base::Unretained(GetContext()),
601                  origin_url,
602                  s_corrupt_db_test_prefix,
603                  this));
604
605   std::string test_file = s_corrupt_db_test_prefix +
606                           "corrupted_open_db_detection.html#" + GetParam();
607   SimpleTest(embedded_test_server()->GetURL(test_file));
608
609   test_file = s_corrupt_db_test_prefix + "corrupted_open_db_recovery.html";
610   SimpleTest(embedded_test_server()->GetURL(test_file));
611 }
612
613 INSTANTIATE_TEST_CASE_P(IndexedDBBrowserCorruptionTestInstantiation,
614                         IndexedDBBrowserCorruptionTest,
615                         ::testing::Values("failGetBlobJournal",
616                                           "get",
617                                           "failWebkitGetDatabaseNames",
618                                           "iterate",
619                                           "failTransactionCommit",
620                                           "clearObjectStore"));
621
622 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
623                        DeleteCompactsBackingStore) {
624   const GURL test_url = GetTestUrl("indexeddb", "delete_compact.html");
625   SimpleTest(GURL(test_url.spec() + "#fill"));
626   int64 after_filling = RequestDiskUsage();
627   EXPECT_GT(after_filling, 0);
628
629   SimpleTest(GURL(test_url.spec() + "#purge"));
630   int64 after_deleting = RequestDiskUsage();
631   EXPECT_LT(after_deleting, after_filling);
632
633   // The above tests verify basic assertions - that filling writes data and
634   // deleting reduces the amount stored.
635
636   // The below tests make assumptions about implementation specifics, such as
637   // data compression, compaction efficiency, and the maximum amount of
638   // metadata and log data remains after a deletion. It is possible that
639   // changes to the implementation may require these constants to be tweaked.
640
641   const int kTestFillBytes = 1024 * 1024 * 5;  // 5MB
642   EXPECT_GT(after_filling, kTestFillBytes);
643
644   const int kTestCompactBytes = 1024 * 10;  // 10kB
645   EXPECT_LT(after_deleting, kTestCompactBytes);
646 }
647
648 // Complex multi-step (converted from pyauto) tests begin here.
649
650 // Verify null key path persists after restarting browser.
651 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_NullKeyPathPersistence) {
652   NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part1",
653                           "pass - first run");
654 }
655
656 // Verify null key path persists after restarting browser.
657 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, NullKeyPathPersistence) {
658   NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part2",
659                           "pass - second run");
660 }
661
662 // Verify that a VERSION_CHANGE transaction is rolled back after a
663 // renderer/browser crash
664 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
665                        PRE_PRE_VersionChangeCrashResilience) {
666   NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part1",
667                           "pass - part1 - complete");
668 }
669
670 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_VersionChangeCrashResilience) {
671   NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part2",
672                           "pass - part2 - crash me");
673   // If we actually crash here then googletest will not run the next step
674   // (VersionChangeCrashResilience) as an optimization. googletest's
675   // ASSERT_DEATH/EXIT fails to work properly (on Windows) due to how we
676   // implement the PRE_* test mechanism.
677   exit(0);
678 }
679
680 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, VersionChangeCrashResilience) {
681   NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part3",
682                           "pass - part3 - rolled back");
683 }
684
685 // Verify that open DB connections are closed when a tab is destroyed.
686 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ConnectionsClosedOnTabClose) {
687   NavigateAndWaitForTitle(shell(), "version_change_blocked.html", "#tab1",
688                           "setVersion(2) complete");
689
690   // Start on a different URL to force a new renderer process.
691   Shell* new_shell = CreateBrowser();
692   NavigateToURL(new_shell, GURL(url::kAboutBlankURL));
693   NavigateAndWaitForTitle(new_shell, "version_change_blocked.html", "#tab2",
694                           "setVersion(3) blocked");
695
696   base::string16 expected_title16(ASCIIToUTF16("setVersion(3) complete"));
697   TitleWatcher title_watcher(new_shell->web_contents(), expected_title16);
698
699   base::KillProcess(
700       shell()->web_contents()->GetRenderProcessHost()->GetHandle(), 0, true);
701   shell()->Close();
702
703   EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
704 }
705
706 // Verify that a "close" event is fired at database connections when
707 // the backing store is deleted.
708 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ForceCloseEventTest) {
709   NavigateAndWaitForTitle(shell(), "force_close_event.html", NULL,
710                           "connection ready");
711
712   GetContext()->TaskRunner()->PostTask(
713       FROM_HERE,
714       base::Bind(&IndexedDBContextImpl::DeleteForOrigin,
715                  GetContext(),
716                  GURL("file:///")));
717
718   base::string16 expected_title16(ASCIIToUTF16("connection closed"));
719   TitleWatcher title_watcher(shell()->web_contents(), expected_title16);
720   title_watcher.AlsoWaitForTitle(ASCIIToUTF16("connection closed with error"));
721   EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
722 }
723
724 class IndexedDBBrowserTestSingleProcess : public IndexedDBBrowserTest {
725  public:
726   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
727     command_line->AppendSwitch(switches::kSingleProcess);
728   }
729 };
730
731 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestSingleProcess,
732                        RenderThreadShutdownTest) {
733   SimpleTest(GetTestUrl("indexeddb", "shutdown_with_requests.html"));
734 }
735
736 }  // namespace content