blob: 57a73c7db882c0fc83fae6b2c654e1430f982dc5 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/process_util.h"
#include "base/test/thread_test_helper.h"
#include "base/utf_string_conversions.h"
#include "content/browser/in_process_webkit/indexed_db_context_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
#include "content/shell/shell.h"
#include "content/test/content_browser_test.h"
#include "content/test/content_browser_test_utils.h"
#include "webkit/database/database_util.h"
#include "webkit/quota/quota_manager.h"
using quota::QuotaManager;
using webkit_database::DatabaseUtil;
namespace content {
// This browser test is aimed towards exercising the IndexedDB bindings and
// the actual implementation that lives in the browser side (in_process_webkit).
class IndexedDBBrowserTest : public ContentBrowserTest {
public:
IndexedDBBrowserTest() {}
void SimpleTest(const GURL& test_url, bool incognito = false) {
// The test page will perform tests on IndexedDB, then navigate to either
// a #pass or #fail ref.
Shell* the_browser = incognito ? CreateOffTheRecordBrowser() : shell();
LOG(INFO) << "Navigating to URL and blocking.";
NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2);
LOG(INFO) << "Navigation done.";
std::string result = the_browser->web_contents()->GetURL().ref();
if (result != "pass") {
std::string js_result;
ASSERT_TRUE(ExecuteJavaScriptAndExtractString(
the_browser->web_contents()->GetRenderViewHost(), L"",
L"window.domAutomationController.send(getLog())", &js_result));
FAIL() << "Failed: " << js_result;
}
}
void NavigateAndWaitForTitle(Shell* shell,
const char* filename,
const char* hash,
const char* expected_string) {
GURL url = GetTestUrl("indexeddb", filename);
if (hash)
url = GURL(url.spec() + hash);
string16 expected_title16(ASCIIToUTF16(expected_string));
TitleWatcher title_watcher(shell->web_contents(), expected_title16);
NavigateToURL(shell, url);
EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
}
};
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) {
SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"),
true /* incognito */);
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorPrefetch) {
SimpleTest(GetTestUrl("indexeddb", "cursor_prefetch.html"));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, IndexTest) {
SimpleTest(GetTestUrl("indexeddb", "index_test.html"));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyPathTest) {
SimpleTest(GetTestUrl("indexeddb", "key_path_test.html"));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
SimpleTest(GetTestUrl("indexeddb", "transaction_get_test.html"));
}
// Needs to be disabled until after WK 129037 rolls into chromium and we can
// update this expectation.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_KeyTypesTest) {
SimpleTest(GetTestUrl("indexeddb", "key_types_test.html"));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ObjectStoreTest) {
SimpleTest(GetTestUrl("indexeddb", "object_store_test.html"));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionTest) {
SimpleTest(GetTestUrl("indexeddb", "transaction_test.html"));
}
// Appears flaky/slow, see: http://crbug.com/120298
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_ValueSizeTest) {
SimpleTest(GetTestUrl("indexeddb", "value_size_test.html"));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DoesntHangTest) {
SimpleTest(GetTestUrl("indexeddb", "transaction_run_forever.html"));
CrashTab(shell()->web_contents());
SimpleTest(GetTestUrl("indexeddb", "transaction_test.html"));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug84933Test) {
const GURL url = GetTestUrl("indexeddb", "bug_84933.html");
// Just navigate to the URL. Test will crash if it fails.
NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug106883Test) {
const GURL url = GetTestUrl("indexeddb", "bug_106883.html");
// Just navigate to the URL. Test will crash if it fails.
NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug109187Test) {
const GURL url = GetTestUrl("indexeddb", "bug_109187.html");
// Just navigate to the URL. Test will crash if it fails.
NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
}
class IndexedDBBrowserTestWithLowQuota : public IndexedDBBrowserTest {
public:
virtual void SetUpOnMainThread() {
const int kInitialQuotaKilobytes = 5000;
const int kTemporaryStorageQuotaMaxSize = kInitialQuotaKilobytes
* 1024 * QuotaManager::kPerHostTemporaryPortion;
SetTempQuota(
kTemporaryStorageQuotaMaxSize,
BrowserContext::GetDefaultStoragePartition(
shell()->web_contents()->GetBrowserContext())->GetQuotaManager());
}
static void SetTempQuota(int64 bytes, scoped_refptr<QuotaManager> qm) {
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&IndexedDBBrowserTestWithLowQuota::SetTempQuota, bytes,
qm));
return;
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
qm->SetTemporaryGlobalOverrideQuota(bytes, quota::QuotaCallback());
// Don't return until the quota has been set.
scoped_refptr<base::ThreadTestHelper> helper(
new base::ThreadTestHelper(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
ASSERT_TRUE(helper->Run());
}
};
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithLowQuota, QuotaTest) {
SimpleTest(GetTestUrl("indexeddb", "quota_test.html"));
}
class IndexedDBBrowserTestWithGCExposed : public IndexedDBBrowserTest {
public:
virtual void SetUpCommandLine(CommandLine* command_line) {
command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
}
};
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed,
DatabaseCallbacksTest) {
SimpleTest(GetTestUrl("indexeddb", "database_callbacks_first.html"));
}
class IndexedDBBrowserTestWithVersion0Schema : public IndexedDBBrowserTest {
public:
virtual void SetUpOnMainThread() {
scoped_refptr<IndexedDBContext> context =
BrowserContext::GetDefaultStoragePartition(
shell()->web_contents()->GetBrowserContext())->
GetIndexedDBContext();
BrowserThread::PostTask(
BrowserThread::WEBKIT_DEPRECATED, FROM_HERE,
base::Bind(
&IndexedDBBrowserTestWithVersion0Schema::CopyLevelDBToProfile,
shell(),
context));
scoped_refptr<base::ThreadTestHelper> helper(
new base::ThreadTestHelper(BrowserThread::GetMessageLoopProxyForThread(
BrowserThread::WEBKIT_DEPRECATED)));
ASSERT_TRUE(helper->Run());
}
static void CopyLevelDBToProfile(Shell* shell,
scoped_refptr<IndexedDBContext> context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT_DEPRECATED));
FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
FilePath test_data_dir =
GetTestFilePath("indexeddb", "migration_from_0").Append(leveldb_dir);
IndexedDBContextImpl* context_impl =
static_cast<IndexedDBContextImpl*>(context.get());
FilePath dest = context_impl->data_path().Append(leveldb_dir);
// If we don't create the destination directory first, the contents of the
// leveldb directory are copied directly into profile/IndexedDB instead of
// profile/IndexedDB/file__0.xxx/
ASSERT_TRUE(file_util::CreateDirectory(dest));
const bool kRecursive = true;
ASSERT_TRUE(file_util::CopyDirectory(test_data_dir,
context_impl->data_path(),
kRecursive));
}
};
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion0Schema, MigrationTest) {
SimpleTest(GetTestUrl("indexeddb", "migration_test.html"));
}
// Verify null key path persists after restarting browser.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_NullKeyPathPersistence) {
NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part1",
"pass - first run");
}
// Verify null key path persists after restarting browser.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, NullKeyPathPersistence) {
NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part2",
"pass - second run");
}
// Verify that a VERSION_CHANGE transaction is rolled back after a
// renderer/browser crash
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
PRE_PRE_VersionChangeCrashResilience) {
NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part1",
"pass - part1 - complete");
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_VersionChangeCrashResilience) {
NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part2",
"pass - part2 - crash me");
NavigateToURL(shell(), GURL(chrome::kChromeUIBrowserCrashHost));
}
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, VersionChangeCrashResilience) {
NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part3",
"pass - part3 - rolled back");
}
// Verify that open DB connections are closed when a tab is destroyed.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ConnectionsClosedOnTabClose) {
NavigateAndWaitForTitle(shell(), "version_change_blocked.html", "#tab1",
"setVersion(1) complete");
// Start on a different URL to force a new renderer process.
Shell* new_shell = CreateBrowser();
NavigateToURL(new_shell, GURL(chrome::kAboutBlankURL));
NavigateAndWaitForTitle(new_shell, "version_change_blocked.html", "#tab2",
"setVersion(2) blocked");
string16 expected_title16(ASCIIToUTF16("setVersion(2) complete"));
TitleWatcher title_watcher(new_shell->web_contents(), expected_title16);
base::KillProcess(
shell()->web_contents()->GetRenderProcessHost()->GetHandle(), 0, true);
shell()->Close();
EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
}
} // namespace content