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