Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_browsertest.cc
blobe41e281282f36195a41047c3949f8bc267dc2a1b
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/file_util.h"
8 #include "base/files/file_path.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/test/thread_test_helper.h"
13 #include "content/browser/browser_main_loop.h"
14 #include "content/browser/indexed_db/indexed_db_context_impl.h"
15 #include "content/browser/web_contents/web_contents_impl.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_process_host.h"
19 #include "content/public/browser/storage_partition.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/public/common/url_constants.h"
23 #include "content/public/test/browser_test_utils.h"
24 #include "content/shell/browser/shell.h"
25 #include "content/test/content_browser_test.h"
26 #include "content/test/content_browser_test_utils.h"
27 #include "webkit/browser/database/database_util.h"
28 #include "webkit/browser/quota/quota_manager.h"
30 using quota::QuotaManager;
31 using webkit_database::DatabaseUtil;
33 namespace content {
35 // This browser test is aimed towards exercising the IndexedDB bindings and
36 // the actual implementation that lives in the browser side.
37 class IndexedDBBrowserTest : public ContentBrowserTest {
38 public:
39 IndexedDBBrowserTest() : disk_usage_(-1) {}
41 void SimpleTest(const GURL& test_url, bool incognito = false) {
42 // The test page will perform tests on IndexedDB, then navigate to either
43 // a #pass or #fail ref.
44 Shell* the_browser = incognito ? CreateOffTheRecordBrowser() : shell();
46 LOG(INFO) << "Navigating to URL and blocking.";
47 NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2);
48 LOG(INFO) << "Navigation done.";
49 std::string result =
50 the_browser->web_contents()->GetLastCommittedURL().ref();
51 if (result != "pass") {
52 std::string js_result;
53 ASSERT_TRUE(ExecuteScriptAndExtractString(
54 the_browser->web_contents(),
55 "window.domAutomationController.send(getLog())",
56 &js_result));
57 FAIL() << "Failed: " << js_result;
61 void NavigateAndWaitForTitle(Shell* shell,
62 const char* filename,
63 const char* hash,
64 const char* expected_string) {
65 GURL url = GetTestUrl("indexeddb", filename);
66 if (hash)
67 url = GURL(url.spec() + hash);
69 string16 expected_title16(ASCIIToUTF16(expected_string));
70 TitleWatcher title_watcher(shell->web_contents(), expected_title16);
71 NavigateToURL(shell, url);
72 EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
75 IndexedDBContextImpl* GetContext() {
76 StoragePartition* partition =
77 BrowserContext::GetDefaultStoragePartition(
78 shell()->web_contents()->GetBrowserContext());
79 return static_cast<IndexedDBContextImpl*>(partition->GetIndexedDBContext());
82 void SetQuota(int quotaKilobytes) {
83 const int kTemporaryStorageQuotaSize = quotaKilobytes
84 * 1024 * QuotaManager::kPerHostTemporaryPortion;
85 SetTempQuota(kTemporaryStorageQuotaSize,
86 BrowserContext::GetDefaultStoragePartition(
87 shell()->web_contents()->GetBrowserContext())->GetQuotaManager());
90 static void SetTempQuota(int64 bytes, scoped_refptr<QuotaManager> qm) {
91 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
92 BrowserThread::PostTask(
93 BrowserThread::IO, FROM_HERE,
94 base::Bind(&IndexedDBBrowserTest::SetTempQuota, bytes, qm));
95 return;
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
98 qm->SetTemporaryGlobalOverrideQuota(bytes, quota::QuotaCallback());
99 // Don't return until the quota has been set.
100 scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
101 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
102 ASSERT_TRUE(helper->Run());
105 virtual int64 RequestDiskUsage() {
106 PostTaskAndReplyWithResult(
107 GetContext()->TaskRunner(),
108 FROM_HERE,
109 base::Bind(&IndexedDBContext::GetOriginDiskUsage,
110 GetContext(),
111 GURL("file:///")),
112 base::Bind(&IndexedDBBrowserTest::DidGetDiskUsage, this));
113 scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
114 BrowserMainLoop::GetInstance()->indexed_db_thread()->
115 message_loop_proxy()));
116 EXPECT_TRUE(helper->Run());
117 // Wait for DidGetDiskUsage to be called.
118 base::MessageLoop::current()->RunUntilIdle();
119 return disk_usage_;
121 private:
122 virtual void DidGetDiskUsage(int64 bytes) {
123 EXPECT_GT(bytes, 0);
124 disk_usage_ = bytes;
127 int64 disk_usage_;
130 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
131 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"));
134 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) {
135 SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"),
136 true /* incognito */);
139 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorPrefetch) {
140 SimpleTest(GetTestUrl("indexeddb", "cursor_prefetch.html"));
143 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, IndexTest) {
144 SimpleTest(GetTestUrl("indexeddb", "index_test.html"));
147 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyPathTest) {
148 SimpleTest(GetTestUrl("indexeddb", "key_path_test.html"));
151 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
152 SimpleTest(GetTestUrl("indexeddb", "transaction_get_test.html"));
155 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyTypesTest) {
156 SimpleTest(GetTestUrl("indexeddb", "key_types_test.html"));
159 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ObjectStoreTest) {
160 SimpleTest(GetTestUrl("indexeddb", "object_store_test.html"));
163 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
164 SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
167 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionTest) {
168 SimpleTest(GetTestUrl("indexeddb", "transaction_test.html"));
171 // http://crbug.com/239366
172 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_ValueSizeTest) {
173 SimpleTest(GetTestUrl("indexeddb", "value_size_test.html"));
176 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CallbackAccounting) {
177 SimpleTest(GetTestUrl("indexeddb", "callback_accounting.html"));
180 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DoesntHangTest) {
181 SimpleTest(GetTestUrl("indexeddb", "transaction_run_forever.html"));
182 CrashTab(shell()->web_contents());
183 SimpleTest(GetTestUrl("indexeddb", "transaction_not_blocked.html"));
186 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug84933Test) {
187 const GURL url = GetTestUrl("indexeddb", "bug_84933.html");
189 // Just navigate to the URL. Test will crash if it fails.
190 NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
193 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug106883Test) {
194 const GURL url = GetTestUrl("indexeddb", "bug_106883.html");
196 // Just navigate to the URL. Test will crash if it fails.
197 NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
200 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug109187Test) {
201 const GURL url = GetTestUrl("indexeddb", "bug_109187.html");
203 // Just navigate to the URL. Test will crash if it fails.
204 NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
207 class IndexedDBBrowserTestWithLowQuota : public IndexedDBBrowserTest {
208 public:
209 virtual void SetUpOnMainThread() OVERRIDE {
210 const int kInitialQuotaKilobytes = 5000;
211 SetQuota(kInitialQuotaKilobytes);
215 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithLowQuota, QuotaTest) {
216 SimpleTest(GetTestUrl("indexeddb", "quota_test.html"));
219 class IndexedDBBrowserTestWithGCExposed : public IndexedDBBrowserTest {
220 public:
221 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
222 command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
226 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed,
227 DatabaseCallbacksTest) {
228 SimpleTest(GetTestUrl("indexeddb", "database_callbacks_first.html"));
231 static void CopyLevelDBToProfile(Shell* shell,
232 scoped_refptr<IndexedDBContextImpl> context,
233 const std::string& test_directory) {
234 DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
235 base::FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
236 base::FilePath test_data_dir =
237 GetTestFilePath("indexeddb", test_directory.c_str()).Append(leveldb_dir);
238 base::FilePath dest = context->data_path().Append(leveldb_dir);
239 // If we don't create the destination directory first, the contents of the
240 // leveldb directory are copied directly into profile/IndexedDB instead of
241 // profile/IndexedDB/file__0.xxx/
242 ASSERT_TRUE(file_util::CreateDirectory(dest));
243 const bool kRecursive = true;
244 ASSERT_TRUE(base::CopyDirectory(test_data_dir,
245 context->data_path(),
246 kRecursive));
249 class IndexedDBBrowserTestWithPreexistingLevelDB : public IndexedDBBrowserTest {
250 public:
251 virtual void SetUpOnMainThread() OVERRIDE {
252 scoped_refptr<IndexedDBContextImpl> context = GetContext();
253 context->TaskRunner()->PostTask(
254 FROM_HERE,
255 base::Bind(
256 &CopyLevelDBToProfile, shell(), context, EnclosingLevelDBDir()));
257 scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
258 BrowserMainLoop::GetInstance()->indexed_db_thread()->
259 message_loop_proxy()));
260 ASSERT_TRUE(helper->Run());
263 virtual std::string EnclosingLevelDBDir() = 0;
267 class IndexedDBBrowserTestWithVersion0Schema : public
268 IndexedDBBrowserTestWithPreexistingLevelDB {
269 virtual std::string EnclosingLevelDBDir() OVERRIDE {
270 return "migration_from_0";
274 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion0Schema, MigrationTest) {
275 SimpleTest(GetTestUrl("indexeddb", "migration_test.html"));
278 class IndexedDBBrowserTestWithVersion123456Schema : public
279 IndexedDBBrowserTestWithPreexistingLevelDB {
280 virtual std::string EnclosingLevelDBDir() OVERRIDE {
281 return "schema_version_123456";
285 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion123456Schema,
286 DestroyTest) {
287 int64 original_size = RequestDiskUsage();
288 EXPECT_GT(original_size, 0);
289 SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
290 int64 new_size = RequestDiskUsage();
291 EXPECT_NE(original_size, new_size);
294 class IndexedDBBrowserTestWithVersion987654SSVData : public
295 IndexedDBBrowserTestWithPreexistingLevelDB {
296 virtual std::string EnclosingLevelDBDir() OVERRIDE {
297 return "ssv_version_987654";
301 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion987654SSVData,
302 DestroyTest) {
303 int64 original_size = RequestDiskUsage();
304 EXPECT_GT(original_size, 0);
305 SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
306 int64 new_size = RequestDiskUsage();
307 EXPECT_NE(original_size, new_size);
310 class IndexedDBBrowserTestWithCorruptLevelDB : public
311 IndexedDBBrowserTestWithPreexistingLevelDB {
312 virtual std::string EnclosingLevelDBDir() OVERRIDE {
313 return "corrupt_leveldb";
317 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithCorruptLevelDB,
318 DestroyTest) {
319 int64 original_size = RequestDiskUsage();
320 EXPECT_GT(original_size, 0);
321 SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
322 int64 new_size = RequestDiskUsage();
323 EXPECT_NE(original_size, new_size);
326 class IndexedDBBrowserTestWithMissingSSTFile : public
327 IndexedDBBrowserTestWithPreexistingLevelDB {
328 virtual std::string EnclosingLevelDBDir() OVERRIDE {
329 return "missing_sst";
333 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithMissingSSTFile,
334 DestroyTest) {
335 int64 original_size = RequestDiskUsage();
336 EXPECT_GT(original_size, 0);
337 SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
338 int64 new_size = RequestDiskUsage();
339 EXPECT_NE(original_size, new_size);
342 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, LevelDBLogFileTest) {
343 // Any page that opens an IndexedDB will work here.
344 SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
345 base::FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
346 base::FilePath log_file(FILE_PATH_LITERAL("LOG"));
347 base::FilePath log_file_path =
348 GetContext()->data_path().Append(leveldb_dir).Append(log_file);
349 int64 size;
350 EXPECT_TRUE(file_util::GetFileSize(log_file_path, &size));
351 EXPECT_GT(size, 0);
354 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CanDeleteWhenOverQuotaTest) {
355 SimpleTest(GetTestUrl("indexeddb", "fill_up_5k.html"));
356 int64 size = RequestDiskUsage();
357 const int kQuotaKilobytes = 2;
358 EXPECT_GT(size, kQuotaKilobytes * 1024);
359 SetQuota(kQuotaKilobytes);
360 SimpleTest(GetTestUrl("indexeddb", "delete_over_quota.html"));
363 // Complex multi-step (converted from pyauto) tests begin here.
365 // Verify null key path persists after restarting browser.
366 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_NullKeyPathPersistence) {
367 NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part1",
368 "pass - first run");
371 // Verify null key path persists after restarting browser.
372 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, NullKeyPathPersistence) {
373 NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part2",
374 "pass - second run");
377 // Verify that a VERSION_CHANGE transaction is rolled back after a
378 // renderer/browser crash
379 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
380 PRE_PRE_VersionChangeCrashResilience) {
381 NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part1",
382 "pass - part1 - complete");
385 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_VersionChangeCrashResilience) {
386 NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part2",
387 "pass - part2 - crash me");
388 NavigateToURL(shell(), GURL(kChromeUIBrowserCrashHost));
391 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, VersionChangeCrashResilience) {
392 NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part3",
393 "pass - part3 - rolled back");
396 // Verify that open DB connections are closed when a tab is destroyed.
397 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ConnectionsClosedOnTabClose) {
398 NavigateAndWaitForTitle(shell(), "version_change_blocked.html", "#tab1",
399 "setVersion(2) complete");
401 // Start on a different URL to force a new renderer process.
402 Shell* new_shell = CreateBrowser();
403 NavigateToURL(new_shell, GURL(kAboutBlankURL));
404 NavigateAndWaitForTitle(new_shell, "version_change_blocked.html", "#tab2",
405 "setVersion(3) blocked");
407 string16 expected_title16(ASCIIToUTF16("setVersion(3) complete"));
408 TitleWatcher title_watcher(new_shell->web_contents(), expected_title16);
410 base::KillProcess(
411 shell()->web_contents()->GetRenderProcessHost()->GetHandle(), 0, true);
412 shell()->Close();
414 EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
417 // Verify that a "close" event is fired at database connections when
418 // the backing store is deleted.
419 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ForceCloseEventTest) {
420 NavigateAndWaitForTitle(shell(), "force_close_event.html", NULL,
421 "connection ready");
423 GetContext()->TaskRunner()->PostTask(
424 FROM_HERE,
425 base::Bind(&IndexedDBContextImpl::DeleteForOrigin,
426 GetContext(),
427 GURL("file:///")));
429 string16 expected_title16(ASCIIToUTF16("connection closed"));
430 TitleWatcher title_watcher(shell()->web_contents(), expected_title16);
431 EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
434 } // namespace content