Modernize CJK default font prefs on Mac/Windows/Linux
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_browsertest.cc
blob71fa265604fd96c4f99acc54277e0ee3ec5d23a9
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.
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"
40 using base::ASCIIToUTF16;
41 using storage::QuotaManager;
42 using storage::DatabaseUtil;
44 namespace content {
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) {}
52 void SetUp() override {
53 GetTestClassFactory()->Reset();
54 IndexedDBClassFactory::SetIndexedDBClassFactoryGetter(GetIDBClassFactory);
55 ContentBrowserTest::SetUp();
58 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.";
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;
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);
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));
125 return;
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(),
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_;
152 private:
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) {
164 disk_usage_ = bytes;
167 int64 disk_usage_;
169 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTest);
172 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
173 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"));
176 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) {
177 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"),
178 true /* incognito */);
181 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorPrefetch) {
182 SimpleTest(GetTestUrl("indexeddb", "cursor_prefetch.html"));
185 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, IndexTest) {
186 SimpleTest(GetTestUrl("indexeddb", "index_test.html"));
189 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyPathTest) {
190 SimpleTest(GetTestUrl("indexeddb", "key_path_test.html"));
193 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
194 SimpleTest(GetTestUrl("indexeddb", "transaction_get_test.html"));
197 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyTypesTest) {
198 SimpleTest(GetTestUrl("indexeddb", "key_types_test.html"));
201 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ObjectStoreTest) {
202 SimpleTest(GetTestUrl("indexeddb", "object_store_test.html"));
205 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
206 SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
209 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionTest) {
210 SimpleTest(GetTestUrl("indexeddb", "transaction_test.html"));
213 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CallbackAccounting) {
214 SimpleTest(GetTestUrl("indexeddb", "callback_accounting.html"));
217 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DoesntHangTest) {
218 SimpleTest(GetTestUrl("indexeddb", "transaction_run_forever.html"));
219 CrashTab(shell()->web_contents());
220 SimpleTest(GetTestUrl("indexeddb", "transaction_not_blocked.html"));
223 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug84933Test) {
224 const GURL url = GetTestUrl("indexeddb", "bug_84933.html");
226 // Just navigate to the URL. Test will crash if it fails.
227 NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
230 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug106883Test) {
231 const GURL url = GetTestUrl("indexeddb", "bug_106883.html");
233 // Just navigate to the URL. Test will crash if it fails.
234 NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
237 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug109187Test) {
238 const GURL url = GetTestUrl("indexeddb", "bug_109187.html");
240 // Just navigate to the URL. Test will crash if it fails.
241 NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
244 class IndexedDBBrowserTestWithLowQuota : public IndexedDBBrowserTest {
245 public:
246 IndexedDBBrowserTestWithLowQuota() {}
248 void SetUpOnMainThread() override {
249 const int kInitialQuotaKilobytes = 5000;
250 SetQuota(kInitialQuotaKilobytes);
253 private:
254 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTestWithLowQuota);
257 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithLowQuota, QuotaTest) {
258 SimpleTest(GetTestUrl("indexeddb", "quota_test.html"));
261 class IndexedDBBrowserTestWithGCExposed : public IndexedDBBrowserTest {
262 public:
263 IndexedDBBrowserTestWithGCExposed() {}
265 void SetUpCommandLine(CommandLine* command_line) override {
266 command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
269 private:
270 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTestWithGCExposed);
273 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed,
274 DatabaseCallbacksTest) {
275 SimpleTest(GetTestUrl("indexeddb", "database_callbacks_first.html"));
278 static void CopyLevelDBToProfile(Shell* shell,
279 scoped_refptr<IndexedDBContextImpl> context,
280 const std::string& test_directory) {
281 DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
282 base::FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
283 base::FilePath test_data_dir =
284 GetTestFilePath("indexeddb", test_directory.c_str()).Append(leveldb_dir);
285 base::FilePath dest = context->data_path().Append(leveldb_dir);
286 // If we don't create the destination directory first, the contents of the
287 // leveldb directory are copied directly into profile/IndexedDB instead of
288 // profile/IndexedDB/file__0.xxx/
289 ASSERT_TRUE(base::CreateDirectory(dest));
290 const bool kRecursive = true;
291 ASSERT_TRUE(base::CopyDirectory(test_data_dir,
292 context->data_path(),
293 kRecursive));
296 class IndexedDBBrowserTestWithPreexistingLevelDB : public IndexedDBBrowserTest {
297 public:
298 IndexedDBBrowserTestWithPreexistingLevelDB() {}
299 void SetUpOnMainThread() override {
300 scoped_refptr<IndexedDBContextImpl> context = GetContext();
301 context->TaskRunner()->PostTask(
302 FROM_HERE,
303 base::Bind(
304 &CopyLevelDBToProfile, shell(), context, EnclosingLevelDBDir()));
305 scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
306 BrowserMainLoop::GetInstance()->indexed_db_thread()->
307 message_loop_proxy()));
308 ASSERT_TRUE(helper->Run());
311 virtual std::string EnclosingLevelDBDir() = 0;
313 private:
314 DISALLOW_COPY_AND_ASSIGN(IndexedDBBrowserTestWithPreexistingLevelDB);
317 class IndexedDBBrowserTestWithVersion0Schema : public
318 IndexedDBBrowserTestWithPreexistingLevelDB {
319 std::string EnclosingLevelDBDir() override { return "migration_from_0"; }
322 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion0Schema, MigrationTest) {
323 SimpleTest(GetTestUrl("indexeddb", "migration_test.html"));
326 class IndexedDBBrowserTestWithVersion123456Schema : public
327 IndexedDBBrowserTestWithPreexistingLevelDB {
328 std::string EnclosingLevelDBDir() override { return "schema_version_123456"; }
331 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion123456Schema,
332 DestroyTest) {
333 int64 original_size = RequestDiskUsage();
334 EXPECT_GT(original_size, 0);
335 SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
336 int64 new_size = RequestDiskUsage();
337 EXPECT_GT(new_size, 0);
338 EXPECT_NE(original_size, new_size);
341 class IndexedDBBrowserTestWithVersion987654SSVData : public
342 IndexedDBBrowserTestWithPreexistingLevelDB {
343 std::string EnclosingLevelDBDir() override { return "ssv_version_987654"; }
346 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion987654SSVData,
347 DestroyTest) {
348 int64 original_size = RequestDiskUsage();
349 EXPECT_GT(original_size, 0);
350 SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
351 int64 new_size = RequestDiskUsage();
352 EXPECT_GT(new_size, 0);
353 EXPECT_NE(original_size, new_size);
356 class IndexedDBBrowserTestWithCorruptLevelDB : public
357 IndexedDBBrowserTestWithPreexistingLevelDB {
358 std::string EnclosingLevelDBDir() override { return "corrupt_leveldb"; }
361 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithCorruptLevelDB,
362 DestroyTest) {
363 int64 original_size = RequestDiskUsage();
364 EXPECT_GT(original_size, 0);
365 SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
366 int64 new_size = RequestDiskUsage();
367 EXPECT_GT(new_size, 0);
368 EXPECT_NE(original_size, new_size);
371 class IndexedDBBrowserTestWithMissingSSTFile : public
372 IndexedDBBrowserTestWithPreexistingLevelDB {
373 std::string EnclosingLevelDBDir() override { return "missing_sst"; }
376 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithMissingSSTFile,
377 DestroyTest) {
378 int64 original_size = RequestDiskUsage();
379 EXPECT_GT(original_size, 0);
380 SimpleTest(GetTestUrl("indexeddb", "open_missing_table.html"));
381 int64 new_size = RequestDiskUsage();
382 EXPECT_GT(new_size, 0);
383 EXPECT_NE(original_size, new_size);
386 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, LevelDBLogFileTest) {
387 // Any page that opens an IndexedDB will work here.
388 SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
389 base::FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
390 base::FilePath log_file(FILE_PATH_LITERAL("LOG"));
391 base::FilePath log_file_path =
392 GetContext()->data_path().Append(leveldb_dir).Append(log_file);
393 int64 size;
394 EXPECT_TRUE(base::GetFileSize(log_file_path, &size));
395 EXPECT_GT(size, 0);
398 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CanDeleteWhenOverQuotaTest) {
399 SimpleTest(GetTestUrl("indexeddb", "fill_up_5k.html"));
400 int64 size = RequestDiskUsage();
401 const int kQuotaKilobytes = 2;
402 EXPECT_GT(size, kQuotaKilobytes * 1024);
403 SetQuota(kQuotaKilobytes);
404 SimpleTest(GetTestUrl("indexeddb", "delete_over_quota.html"));
407 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, BlobsCountAgainstQuota) {
408 SimpleTest(GetTestUrl("indexeddb", "blobs_use_quota.html"));
411 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DeleteForOriginDeletesBlobs) {
412 SimpleTest(GetTestUrl("indexeddb", "write_20mb_blob.html"));
413 int64 size = RequestDiskUsage();
414 // This assertion assumes that we do not compress blobs.
415 EXPECT_GT(size, 20 << 20 /* 20 MB */);
416 GetContext()->TaskRunner()->PostTask(
417 FROM_HERE, base::Bind(&IndexedDBContextImpl::DeleteForOrigin,
418 GetContext(), GURL("file:///")));
419 scoped_refptr<base::ThreadTestHelper> helper(
420 new base::ThreadTestHelper(BrowserMainLoop::GetInstance()
421 ->indexed_db_thread()
422 ->message_loop_proxy()));
423 ASSERT_TRUE(helper->Run());
424 EXPECT_EQ(0, RequestDiskUsage());
427 namespace {
429 static void CompactIndexedDBBackingStore(
430 scoped_refptr<IndexedDBContextImpl> context,
431 const GURL& origin_url) {
432 IndexedDBFactory* factory = context->GetIDBFactory();
434 std::pair<IndexedDBFactory::OriginDBMapIterator,
435 IndexedDBFactory::OriginDBMapIterator> range =
436 factory->GetOpenDatabasesForOrigin(origin_url);
438 if (range.first == range.second) // If no open db's for this origin
439 return;
441 // Compact the first db's backing store since all the db's are in the same
442 // backing store.
443 IndexedDBDatabase* db = range.first->second;
444 IndexedDBBackingStore* backing_store = db->backing_store();
445 backing_store->Compact();
448 static void CorruptIndexedDBDatabase(
449 IndexedDBContextImpl* context,
450 const GURL& origin_url,
451 base::WaitableEvent* signal_when_finished) {
453 CompactIndexedDBBackingStore(context, origin_url);
455 int numFiles = 0;
456 int numErrors = 0;
457 const bool recursive = false;
458 for (const base::FilePath& idb_data_path :
459 context->GetStoragePaths(origin_url)) {
460 base::FileEnumerator enumerator(
461 idb_data_path, recursive, base::FileEnumerator::FILES);
462 for (base::FilePath idb_file = enumerator.Next(); !idb_file.empty();
463 idb_file = enumerator.Next()) {
464 int64 size(0);
465 GetFileSize(idb_file, &size);
467 if (idb_file.Extension() == FILE_PATH_LITERAL(".ldb")) {
468 numFiles++;
469 base::File file(
470 idb_file, base::File::FLAG_WRITE | base::File::FLAG_OPEN_TRUNCATED);
471 if (file.IsValid()) {
472 // Was opened truncated, expand back to the original
473 // file size and fill with zeros (corrupting the file).
474 file.SetLength(size);
475 } else {
476 numErrors++;
480 VLOG(0) << "There were " << numFiles << " in " << idb_data_path.value()
481 << " with " << numErrors << " errors";
484 signal_when_finished->Signal();
487 const std::string s_corrupt_db_test_prefix = "/corrupt/test/";
489 static scoped_ptr<net::test_server::HttpResponse> CorruptDBRequestHandler(
490 IndexedDBContextImpl* context,
491 const GURL& origin_url,
492 const std::string& path,
493 IndexedDBBrowserTest* test,
494 const net::test_server::HttpRequest& request) {
495 std::string request_path;
496 if (path.find(s_corrupt_db_test_prefix) != std::string::npos)
497 request_path = request.relative_url.substr(s_corrupt_db_test_prefix.size());
498 else
499 return scoped_ptr<net::test_server::HttpResponse>();
501 // Remove the query string if present.
502 std::string request_query;
503 size_t query_pos = request_path.find('?');
504 if (query_pos != std::string::npos) {
505 request_query = request_path.substr(query_pos + 1);
506 request_path = request_path.substr(0, query_pos);
509 if (request_path == "corruptdb" && !request_query.empty()) {
510 VLOG(0) << "Requested to corrupt IndexedDB: " << request_query;
511 base::WaitableEvent signal_when_finished(false, false);
512 context->TaskRunner()->PostTask(FROM_HERE,
513 base::Bind(&CorruptIndexedDBDatabase,
514 base::ConstRef(context),
515 origin_url,
516 &signal_when_finished));
517 signal_when_finished.Wait();
519 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
520 new net::test_server::BasicHttpResponse);
521 http_response->set_code(net::HTTP_OK);
522 return http_response.Pass();
523 } else if (request_path == "fail" && !request_query.empty()) {
524 FailClass failure_class = FAIL_CLASS_NOTHING;
525 FailMethod failure_method = FAIL_METHOD_NOTHING;
526 int instance_num = 1;
527 int call_num = 1;
528 std::string fail_class;
529 std::string fail_method;
531 url::Component query(0, request_query.length()), key_pos, value_pos;
532 while (url::ExtractQueryKeyValue(
533 request_query.c_str(), &query, &key_pos, &value_pos)) {
534 std::string escaped_key(request_query.substr(key_pos.begin, key_pos.len));
535 std::string escaped_value(
536 request_query.substr(value_pos.begin, value_pos.len));
538 std::string key = net::UnescapeURLComponent(
539 escaped_key,
540 net::UnescapeRule::NORMAL | net::UnescapeRule::SPACES |
541 net::UnescapeRule::URL_SPECIAL_CHARS);
543 std::string value = net::UnescapeURLComponent(
544 escaped_value,
545 net::UnescapeRule::NORMAL | net::UnescapeRule::SPACES |
546 net::UnescapeRule::URL_SPECIAL_CHARS);
548 if (key == "method")
549 fail_method = value;
550 else if (key == "class")
551 fail_class = value;
552 else if (key == "instNum")
553 instance_num = atoi(value.c_str());
554 else if (key == "callNum")
555 call_num = atoi(value.c_str());
556 else
557 NOTREACHED() << "Unknown param: \"" << key << "\"";
560 if (fail_class == "LevelDBTransaction") {
561 failure_class = FAIL_CLASS_LEVELDB_TRANSACTION;
562 if (fail_method == "Get")
563 failure_method = FAIL_METHOD_GET;
564 else if (fail_method == "Commit")
565 failure_method = FAIL_METHOD_COMMIT;
566 else
567 NOTREACHED() << "Unknown method: \"" << fail_method << "\"";
568 } else if (fail_class == "LevelDBIterator") {
569 failure_class = FAIL_CLASS_LEVELDB_ITERATOR;
570 if (fail_method == "Seek")
571 failure_method = FAIL_METHOD_SEEK;
572 else
573 NOTREACHED() << "Unknown method: \"" << fail_method << "\"";
574 } else {
575 NOTREACHED() << "Unknown class: \"" << fail_class << "\"";
578 DCHECK_GE(instance_num, 1);
579 DCHECK_GE(call_num, 1);
581 test->FailOperation(failure_class, failure_method, instance_num, call_num);
583 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
584 new net::test_server::BasicHttpResponse);
585 http_response->set_code(net::HTTP_OK);
586 return http_response.Pass();
589 // A request for a test resource
590 base::FilePath resourcePath =
591 content::GetTestFilePath("indexeddb", request_path.c_str());
592 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
593 new net::test_server::BasicHttpResponse);
594 http_response->set_code(net::HTTP_OK);
595 std::string file_contents;
596 if (!base::ReadFileToString(resourcePath, &file_contents))
597 return scoped_ptr<net::test_server::HttpResponse>();
598 http_response->set_content(file_contents);
599 return http_response.Pass();
602 } // namespace
604 class IndexedDBBrowserCorruptionTest
605 : public IndexedDBBrowserTest,
606 public ::testing::WithParamInterface<const char*> {};
608 IN_PROC_BROWSER_TEST_P(IndexedDBBrowserCorruptionTest,
609 OperationOnCorruptedOpenDatabase) {
610 ASSERT_TRUE(embedded_test_server()->Started() ||
611 embedded_test_server()->InitializeAndWaitUntilReady());
612 const GURL& origin_url = embedded_test_server()->base_url();
613 embedded_test_server()->RegisterRequestHandler(
614 base::Bind(&CorruptDBRequestHandler,
615 base::Unretained(GetContext()),
616 origin_url,
617 s_corrupt_db_test_prefix,
618 this));
620 std::string test_file = s_corrupt_db_test_prefix +
621 "corrupted_open_db_detection.html#" + GetParam();
622 SimpleTest(embedded_test_server()->GetURL(test_file));
624 test_file = s_corrupt_db_test_prefix + "corrupted_open_db_recovery.html";
625 SimpleTest(embedded_test_server()->GetURL(test_file));
628 INSTANTIATE_TEST_CASE_P(IndexedDBBrowserCorruptionTestInstantiation,
629 IndexedDBBrowserCorruptionTest,
630 ::testing::Values("failGetBlobJournal",
631 "get",
632 "failWebkitGetDatabaseNames",
633 "iterate",
634 "failTransactionCommit",
635 "clearObjectStore"));
637 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
638 DeleteCompactsBackingStore) {
639 const GURL test_url = GetTestUrl("indexeddb", "delete_compact.html");
640 SimpleTest(GURL(test_url.spec() + "#fill"));
641 int64 after_filling = RequestDiskUsage();
642 EXPECT_GT(after_filling, 0);
644 SimpleTest(GURL(test_url.spec() + "#purge"));
645 int64 after_deleting = RequestDiskUsage();
646 EXPECT_LT(after_deleting, after_filling);
648 // The above tests verify basic assertions - that filling writes data and
649 // deleting reduces the amount stored.
651 // The below tests make assumptions about implementation specifics, such as
652 // data compression, compaction efficiency, and the maximum amount of
653 // metadata and log data remains after a deletion. It is possible that
654 // changes to the implementation may require these constants to be tweaked.
656 const int kTestFillBytes = 1024 * 1024 * 5; // 5MB
657 EXPECT_GT(after_filling, kTestFillBytes);
659 const int kTestCompactBytes = 1024 * 10; // 10kB
660 EXPECT_LT(after_deleting, kTestCompactBytes);
663 // Complex multi-step (converted from pyauto) tests begin here.
665 // Verify null key path persists after restarting browser.
666 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_NullKeyPathPersistence) {
667 NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part1",
668 "pass - first run");
671 // Verify null key path persists after restarting browser.
672 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, NullKeyPathPersistence) {
673 NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part2",
674 "pass - second run");
677 // Verify that a VERSION_CHANGE transaction is rolled back after a
678 // renderer/browser crash
679 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
680 PRE_PRE_VersionChangeCrashResilience) {
681 NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part1",
682 "pass - part1 - complete");
685 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_VersionChangeCrashResilience) {
686 NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part2",
687 "pass - part2 - crash me");
688 // If we actually crash here then googletest will not run the next step
689 // (VersionChangeCrashResilience) as an optimization. googletest's
690 // ASSERT_DEATH/EXIT fails to work properly (on Windows) due to how we
691 // implement the PRE_* test mechanism.
692 exit(0);
695 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, VersionChangeCrashResilience) {
696 NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part3",
697 "pass - part3 - rolled back");
700 // Verify that open DB connections are closed when a tab is destroyed.
701 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ConnectionsClosedOnTabClose) {
702 NavigateAndWaitForTitle(shell(), "version_change_blocked.html", "#tab1",
703 "setVersion(2) complete");
705 // Start on a different URL to force a new renderer process.
706 Shell* new_shell = CreateBrowser();
707 NavigateToURL(new_shell, GURL(url::kAboutBlankURL));
708 NavigateAndWaitForTitle(new_shell, "version_change_blocked.html", "#tab2",
709 "setVersion(3) blocked");
711 base::string16 expected_title16(ASCIIToUTF16("setVersion(3) complete"));
712 TitleWatcher title_watcher(new_shell->web_contents(), expected_title16);
714 shell()->web_contents()->GetRenderProcessHost()->Shutdown(0, true);
715 shell()->Close();
717 EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
720 // Verify that a "close" event is fired at database connections when
721 // the backing store is deleted.
722 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ForceCloseEventTest) {
723 NavigateAndWaitForTitle(shell(), "force_close_event.html", NULL,
724 "connection ready");
726 GetContext()->TaskRunner()->PostTask(
727 FROM_HERE,
728 base::Bind(&IndexedDBContextImpl::DeleteForOrigin,
729 GetContext(),
730 GURL("file:///")));
732 base::string16 expected_title16(ASCIIToUTF16("connection closed"));
733 TitleWatcher title_watcher(shell()->web_contents(), expected_title16);
734 title_watcher.AlsoWaitForTitle(ASCIIToUTF16("connection closed with error"));
735 EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
738 class IndexedDBBrowserTestSingleProcess : public IndexedDBBrowserTest {
739 public:
740 void SetUpCommandLine(CommandLine* command_line) override {
741 command_line->AppendSwitch(switches::kSingleProcess);
745 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestSingleProcess,
746 RenderThreadShutdownTest) {
747 SimpleTest(GetTestUrl("indexeddb", "shutdown_with_requests.html"));
750 } // namespace content