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.
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/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 "webkit/browser/database/database_util.h"
38 #include "webkit/browser/quota/quota_manager.h"
40 using base::ASCIIToUTF16
;
41 using storage::QuotaManager
;
42 using storage::DatabaseUtil
;
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
{
50 IndexedDBBrowserTest() : disk_usage_(-1) {}
52 virtual void SetUp() OVERRIDE
{
53 GetTestClassFactory()->Reset();
54 IndexedDBClassFactory::SetIndexedDBClassFactoryGetter(GetIDBClassFactory
);
55 ContentBrowserTest::SetUp();
58 virtual void TearDown() OVERRIDE
{
59 IndexedDBClassFactory::SetIndexedDBClassFactoryGetter(NULL
);
60 ContentBrowserTest::TearDown();
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
);
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();
76 VLOG(0) << "Navigating to URL and blocking.";
77 NavigateToURLBlockUntilNavigationsComplete(the_browser
, test_url
, 2);
78 VLOG(0) << "Navigation done.";
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())",
87 FAIL() << "Failed: " << js_result
;
91 void NavigateAndWaitForTitle(Shell
* shell
,
94 const char* expected_string
) {
95 GURL url
= GetTestUrl("indexeddb", filename
);
97 url
= GURL(url
.spec() + hash
);
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());
105 IndexedDBContextImpl
* GetContext() {
106 StoragePartition
* partition
=
107 BrowserContext::GetDefaultStoragePartition(
108 shell()->web_contents()->GetBrowserContext());
109 return static_cast<IndexedDBContextImpl
*>(partition
->GetIndexedDBContext());
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());
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
));
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());
135 virtual int64
RequestDiskUsage() {
136 PostTaskAndReplyWithResult(
137 GetContext()->TaskRunner(),
139 base::Bind(&IndexedDBContext::GetOriginDiskUsage
,
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();
153 static MockBrowserTestIndexedDBClassFactory
* GetTestClassFactory() {
154 static ::base::LazyInstance
<MockBrowserTestIndexedDBClassFactory
>::Leaky
155 s_factory
= LAZY_INSTANCE_INITIALIZER
;
156 return s_factory
.Pointer();
159 static IndexedDBClassFactory
* GetIDBClassFactory() {
160 return GetTestClassFactory();
163 virtual void DidGetDiskUsage(int64 bytes
) {
170 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTest
);
173 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, CursorTest
) {
174 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"));
177 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, CursorTestIncognito
) {
178 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"),
179 true /* incognito */);
182 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, CursorPrefetch
) {
183 SimpleTest(GetTestUrl("indexeddb", "cursor_prefetch.html"));
186 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, IndexTest
) {
187 SimpleTest(GetTestUrl("indexeddb", "index_test.html"));
190 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, KeyPathTest
) {
191 SimpleTest(GetTestUrl("indexeddb", "key_path_test.html"));
194 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, TransactionGetTest
) {
195 SimpleTest(GetTestUrl("indexeddb", "transaction_get_test.html"));
198 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, KeyTypesTest
) {
199 SimpleTest(GetTestUrl("indexeddb", "key_types_test.html"));
202 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, ObjectStoreTest
) {
203 SimpleTest(GetTestUrl("indexeddb", "object_store_test.html"));
206 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, DatabaseTest
) {
207 SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
210 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, TransactionTest
) {
211 SimpleTest(GetTestUrl("indexeddb", "transaction_test.html"));
214 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, CallbackAccounting
) {
215 SimpleTest(GetTestUrl("indexeddb", "callback_accounting.html"));
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"));
224 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, Bug84933Test
) {
225 const GURL url
= GetTestUrl("indexeddb", "bug_84933.html");
227 // Just navigate to the URL. Test will crash if it fails.
228 NavigateToURLBlockUntilNavigationsComplete(shell(), url
, 1);
231 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, Bug106883Test
) {
232 const GURL url
= GetTestUrl("indexeddb", "bug_106883.html");
234 // Just navigate to the URL. Test will crash if it fails.
235 NavigateToURLBlockUntilNavigationsComplete(shell(), url
, 1);
238 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, Bug109187Test
) {
239 const GURL url
= GetTestUrl("indexeddb", "bug_109187.html");
241 // Just navigate to the URL. Test will crash if it fails.
242 NavigateToURLBlockUntilNavigationsComplete(shell(), url
, 1);
245 class IndexedDBBrowserTestWithLowQuota
: public IndexedDBBrowserTest
{
247 IndexedDBBrowserTestWithLowQuota() {}
249 virtual void SetUpOnMainThread() OVERRIDE
{
250 const int kInitialQuotaKilobytes
= 5000;
251 SetQuota(kInitialQuotaKilobytes
);
255 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTestWithLowQuota
);
258 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithLowQuota
, QuotaTest
) {
259 SimpleTest(GetTestUrl("indexeddb", "quota_test.html"));
262 class IndexedDBBrowserTestWithGCExposed
: public IndexedDBBrowserTest
{
264 IndexedDBBrowserTestWithGCExposed() {}
266 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
267 command_line
->AppendSwitchASCII(switches::kJavaScriptFlags
, "--expose-gc");
271 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTestWithGCExposed
);
274 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed
,
275 DatabaseCallbacksTest
) {
276 SimpleTest(GetTestUrl("indexeddb", "database_callbacks_first.html"));
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(),
297 class IndexedDBBrowserTestWithPreexistingLevelDB
: public IndexedDBBrowserTest
{
299 IndexedDBBrowserTestWithPreexistingLevelDB() {}
300 virtual void SetUpOnMainThread() OVERRIDE
{
301 scoped_refptr
<IndexedDBContextImpl
> context
= GetContext();
302 context
->TaskRunner()->PostTask(
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());
312 virtual std::string
EnclosingLevelDBDir() = 0;
315 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTestWithPreexistingLevelDB
);
318 class IndexedDBBrowserTestWithVersion0Schema
: public
319 IndexedDBBrowserTestWithPreexistingLevelDB
{
320 virtual std::string
EnclosingLevelDBDir() OVERRIDE
{
321 return "migration_from_0";
325 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion0Schema
, MigrationTest
) {
326 SimpleTest(GetTestUrl("indexeddb", "migration_test.html"));
329 class IndexedDBBrowserTestWithVersion123456Schema
: public
330 IndexedDBBrowserTestWithPreexistingLevelDB
{
331 virtual std::string
EnclosingLevelDBDir() OVERRIDE
{
332 return "schema_version_123456";
336 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion123456Schema
,
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
);
345 class IndexedDBBrowserTestWithVersion987654SSVData
: public
346 IndexedDBBrowserTestWithPreexistingLevelDB
{
347 virtual std::string
EnclosingLevelDBDir() OVERRIDE
{
348 return "ssv_version_987654";
352 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion987654SSVData
,
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
);
361 class IndexedDBBrowserTestWithCorruptLevelDB
: public
362 IndexedDBBrowserTestWithPreexistingLevelDB
{
363 virtual std::string
EnclosingLevelDBDir() OVERRIDE
{
364 return "corrupt_leveldb";
368 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithCorruptLevelDB
,
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
);
377 class IndexedDBBrowserTestWithMissingSSTFile
: public
378 IndexedDBBrowserTestWithPreexistingLevelDB
{
379 virtual std::string
EnclosingLevelDBDir() OVERRIDE
{
380 return "missing_sst";
384 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithMissingSSTFile
,
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
);
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
);
401 EXPECT_TRUE(base::GetFileSize(log_file_path
, &size
));
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"));
416 static void CompactIndexedDBBackingStore(
417 scoped_refptr
<IndexedDBContextImpl
> context
,
418 const GURL
& origin_url
) {
419 IndexedDBFactory
* factory
= context
->GetIDBFactory();
421 std::pair
<IndexedDBFactory::OriginDBMapIterator
,
422 IndexedDBFactory::OriginDBMapIterator
> range
=
423 factory
->GetOpenDatabasesForOrigin(origin_url
);
425 if (range
.first
== range
.second
) // If no open db's for this origin
428 // Compact the first db's backing store since all the db's are in the same
430 IndexedDBDatabase
* db
= range
.first
->second
;
431 IndexedDBBackingStore
* backing_store
= db
->backing_store();
432 backing_store
->Compact();
435 static void CorruptIndexedDBDatabase(
436 IndexedDBContextImpl
* context
,
437 const GURL
& origin_url
,
438 base::WaitableEvent
* signal_when_finished
) {
440 CompactIndexedDBBackingStore(context
, origin_url
);
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()) {
451 GetFileSize(idb_file
, &size
);
453 if (idb_file
.Extension() == FILE_PATH_LITERAL(".ldb")) {
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
);
467 VLOG(0) << "There were " << numFiles
<< " in " << idb_data_path
.value()
468 << " with " << numErrors
<< " errors";
469 signal_when_finished
->Signal();
472 const std::string s_corrupt_db_test_prefix
= "/corrupt/test/";
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());
484 return scoped_ptr
<net::test_server::HttpResponse
>();
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
);
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
),
501 &signal_when_finished
));
502 signal_when_finished
.Wait();
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;
513 std::string fail_class
;
514 std::string fail_method
;
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
));
523 std::string key
= net::UnescapeURLComponent(
525 net::UnescapeRule::NORMAL
| net::UnescapeRule::SPACES
|
526 net::UnescapeRule::URL_SPECIAL_CHARS
);
528 std::string value
= net::UnescapeURLComponent(
530 net::UnescapeRule::NORMAL
| net::UnescapeRule::SPACES
|
531 net::UnescapeRule::URL_SPECIAL_CHARS
);
535 else if (key
== "class")
537 else if (key
== "instNum")
538 instance_num
= atoi(value
.c_str());
539 else if (key
== "callNum")
540 call_num
= atoi(value
.c_str());
542 NOTREACHED() << "Unknown param: \"" << key
<< "\"";
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
;
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
;
558 NOTREACHED() << "Unknown method: \"" << fail_method
<< "\"";
560 NOTREACHED() << "Unknown class: \"" << fail_class
<< "\"";
563 DCHECK_GE(instance_num
, 1);
564 DCHECK_GE(call_num
, 1);
566 test
->FailOperation(failure_class
, failure_method
, instance_num
, call_num
);
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
>();
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
>();
589 class IndexedDBBrowserCorruptionTest
590 : public IndexedDBBrowserTest
,
591 public ::testing::WithParamInterface
<const char*> {};
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()),
602 s_corrupt_db_test_prefix
,
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
));
609 test_file
= s_corrupt_db_test_prefix
+ "corrupted_open_db_recovery.html";
610 SimpleTest(embedded_test_server()->GetURL(test_file
));
613 INSTANTIATE_TEST_CASE_P(IndexedDBBrowserCorruptionTestInstantiation
,
614 IndexedDBBrowserCorruptionTest
,
615 ::testing::Values("failGetBlobJournal",
617 "failWebkitGetDatabaseNames",
619 "failTransactionCommit",
620 "clearObjectStore"));
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);
629 SimpleTest(GURL(test_url
.spec() + "#purge"));
630 int64 after_deleting
= RequestDiskUsage();
631 EXPECT_LT(after_deleting
, after_filling
);
633 // The above tests verify basic assertions - that filling writes data and
634 // deleting reduces the amount stored.
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.
641 const int kTestFillBytes
= 1024 * 1024 * 5; // 5MB
642 EXPECT_GT(after_filling
, kTestFillBytes
);
644 const int kTestCompactBytes
= 1024 * 10; // 10kB
645 EXPECT_LT(after_deleting
, kTestCompactBytes
);
648 // Complex multi-step (converted from pyauto) tests begin here.
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",
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");
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");
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.
680 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest
, VersionChangeCrashResilience
) {
681 NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part3",
682 "pass - part3 - rolled back");
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");
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");
696 base::string16
expected_title16(ASCIIToUTF16("setVersion(3) complete"));
697 TitleWatcher
title_watcher(new_shell
->web_contents(), expected_title16
);
700 shell()->web_contents()->GetRenderProcessHost()->GetHandle(), 0, true);
703 EXPECT_EQ(expected_title16
, title_watcher
.WaitAndGetTitle());
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
,
712 GetContext()->TaskRunner()->PostTask(
714 base::Bind(&IndexedDBContextImpl::DeleteForOrigin
,
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());
724 class IndexedDBBrowserTestSingleProcess
: public IndexedDBBrowserTest
{
726 virtual void SetUpCommandLine(CommandLine
* command_line
) OVERRIDE
{
727 command_line
->AppendSwitch(switches::kSingleProcess
);
731 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestSingleProcess
,
732 RenderThreadShutdownTest
) {
733 SimpleTest(GetTestUrl("indexeddb", "shutdown_with_requests.html"));
736 } // namespace content