Upstream version 5.34.104.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_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"
29
30 using base::ASCIIToUTF16;
31 using quota::QuotaManager;
32 using webkit_database::DatabaseUtil;
33
34 namespace content {
35
36 // This browser test is aimed towards exercising the IndexedDB bindings and
37 // the actual implementation that lives in the browser side.
38 class IndexedDBBrowserTest : public ContentBrowserTest {
39  public:
40   IndexedDBBrowserTest() : disk_usage_(-1) {}
41
42   void SimpleTest(const GURL& test_url, bool incognito = false) {
43     // The test page will perform tests on IndexedDB, then navigate to either
44     // a #pass or #fail ref.
45     Shell* the_browser = incognito ? CreateOffTheRecordBrowser() : shell();
46
47     VLOG(0) << "Navigating to URL and blocking.";
48     NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2);
49     VLOG(0) << "Navigation done.";
50     std::string result =
51         the_browser->web_contents()->GetLastCommittedURL().ref();
52     if (result != "pass") {
53       std::string js_result;
54       ASSERT_TRUE(ExecuteScriptAndExtractString(
55           the_browser->web_contents(),
56           "window.domAutomationController.send(getLog())",
57           &js_result));
58       FAIL() << "Failed: " << js_result;
59     }
60   }
61
62   void NavigateAndWaitForTitle(Shell* shell,
63                                const char* filename,
64                                const char* hash,
65                                const char* expected_string) {
66     GURL url = GetTestUrl("indexeddb", filename);
67     if (hash)
68       url = GURL(url.spec() + hash);
69
70     base::string16 expected_title16(ASCIIToUTF16(expected_string));
71     TitleWatcher title_watcher(shell->web_contents(), expected_title16);
72     NavigateToURL(shell, url);
73     EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
74   }
75
76   IndexedDBContextImpl* GetContext() {
77     StoragePartition* partition =
78         BrowserContext::GetDefaultStoragePartition(
79             shell()->web_contents()->GetBrowserContext());
80     return static_cast<IndexedDBContextImpl*>(partition->GetIndexedDBContext());
81   }
82
83   void SetQuota(int quotaKilobytes) {
84     const int kTemporaryStorageQuotaSize = quotaKilobytes
85         * 1024 * QuotaManager::kPerHostTemporaryPortion;
86     SetTempQuota(kTemporaryStorageQuotaSize,
87         BrowserContext::GetDefaultStoragePartition(
88             shell()->web_contents()->GetBrowserContext())->GetQuotaManager());
89   }
90
91   static void SetTempQuota(int64 bytes, scoped_refptr<QuotaManager> qm) {
92     if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
93       BrowserThread::PostTask(
94           BrowserThread::IO, FROM_HERE,
95           base::Bind(&IndexedDBBrowserTest::SetTempQuota, bytes, qm));
96       return;
97     }
98     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
99     qm->SetTemporaryGlobalOverrideQuota(bytes, quota::QuotaCallback());
100     // Don't return until the quota has been set.
101     scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
102         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)));
103     ASSERT_TRUE(helper->Run());
104   }
105
106   virtual int64 RequestDiskUsage() {
107     PostTaskAndReplyWithResult(
108         GetContext()->TaskRunner(),
109         FROM_HERE,
110         base::Bind(&IndexedDBContext::GetOriginDiskUsage,
111                    GetContext(),
112                    GURL("file:///")),
113         base::Bind(&IndexedDBBrowserTest::DidGetDiskUsage, this));
114     scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
115         BrowserMainLoop::GetInstance()->indexed_db_thread()->
116             message_loop_proxy()));
117     EXPECT_TRUE(helper->Run());
118     // Wait for DidGetDiskUsage to be called.
119     base::MessageLoop::current()->RunUntilIdle();
120     return disk_usage_;
121   }
122  private:
123   virtual void DidGetDiskUsage(int64 bytes) {
124     EXPECT_GT(bytes, 0);
125     disk_usage_ = bytes;
126   }
127
128   int64 disk_usage_;
129 };
130
131 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
132   SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"));
133 }
134
135 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTestIncognito) {
136   SimpleTest(GetTestUrl("indexeddb", "cursor_test.html"),
137              true /* incognito */);
138 }
139
140 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorPrefetch) {
141   SimpleTest(GetTestUrl("indexeddb", "cursor_prefetch.html"));
142 }
143
144 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, IndexTest) {
145   SimpleTest(GetTestUrl("indexeddb", "index_test.html"));
146 }
147
148 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyPathTest) {
149   SimpleTest(GetTestUrl("indexeddb", "key_path_test.html"));
150 }
151
152 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
153   SimpleTest(GetTestUrl("indexeddb", "transaction_get_test.html"));
154 }
155
156 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, KeyTypesTest) {
157   SimpleTest(GetTestUrl("indexeddb", "key_types_test.html"));
158 }
159
160 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ObjectStoreTest) {
161   SimpleTest(GetTestUrl("indexeddb", "object_store_test.html"));
162 }
163
164 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
165   SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
166 }
167
168 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionTest) {
169   SimpleTest(GetTestUrl("indexeddb", "transaction_test.html"));
170 }
171
172 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CallbackAccounting) {
173   SimpleTest(GetTestUrl("indexeddb", "callback_accounting.html"));
174 }
175
176 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DoesntHangTest) {
177   SimpleTest(GetTestUrl("indexeddb", "transaction_run_forever.html"));
178   CrashTab(shell()->web_contents());
179   SimpleTest(GetTestUrl("indexeddb", "transaction_not_blocked.html"));
180 }
181
182 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug84933Test) {
183   const GURL url = GetTestUrl("indexeddb", "bug_84933.html");
184
185   // Just navigate to the URL. Test will crash if it fails.
186   NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
187 }
188
189 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug106883Test) {
190   const GURL url = GetTestUrl("indexeddb", "bug_106883.html");
191
192   // Just navigate to the URL. Test will crash if it fails.
193   NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
194 }
195
196 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, Bug109187Test) {
197   const GURL url = GetTestUrl("indexeddb", "bug_109187.html");
198
199   // Just navigate to the URL. Test will crash if it fails.
200   NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
201 }
202
203 class IndexedDBBrowserTestWithLowQuota : public IndexedDBBrowserTest {
204  public:
205   virtual void SetUpOnMainThread() OVERRIDE {
206     const int kInitialQuotaKilobytes = 5000;
207     SetQuota(kInitialQuotaKilobytes);
208   }
209 };
210
211 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithLowQuota, QuotaTest) {
212   SimpleTest(GetTestUrl("indexeddb", "quota_test.html"));
213 }
214
215 class IndexedDBBrowserTestWithGCExposed : public IndexedDBBrowserTest {
216  public:
217   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
218     command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
219   }
220 };
221
222 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithGCExposed,
223                        DatabaseCallbacksTest) {
224   SimpleTest(GetTestUrl("indexeddb", "database_callbacks_first.html"));
225 }
226
227 static void CopyLevelDBToProfile(Shell* shell,
228                                  scoped_refptr<IndexedDBContextImpl> context,
229                                  const std::string& test_directory) {
230   DCHECK(context->TaskRunner()->RunsTasksOnCurrentThread());
231   base::FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
232   base::FilePath test_data_dir =
233       GetTestFilePath("indexeddb", test_directory.c_str()).Append(leveldb_dir);
234   base::FilePath dest = context->data_path().Append(leveldb_dir);
235   // If we don't create the destination directory first, the contents of the
236   // leveldb directory are copied directly into profile/IndexedDB instead of
237   // profile/IndexedDB/file__0.xxx/
238   ASSERT_TRUE(base::CreateDirectory(dest));
239   const bool kRecursive = true;
240   ASSERT_TRUE(base::CopyDirectory(test_data_dir,
241                                   context->data_path(),
242                                   kRecursive));
243 }
244
245 class IndexedDBBrowserTestWithPreexistingLevelDB : public IndexedDBBrowserTest {
246  public:
247   virtual void SetUpOnMainThread() OVERRIDE {
248     scoped_refptr<IndexedDBContextImpl> context = GetContext();
249     context->TaskRunner()->PostTask(
250         FROM_HERE,
251         base::Bind(
252             &CopyLevelDBToProfile, shell(), context, EnclosingLevelDBDir()));
253     scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
254         BrowserMainLoop::GetInstance()->indexed_db_thread()->
255             message_loop_proxy()));
256     ASSERT_TRUE(helper->Run());
257   }
258
259   virtual std::string EnclosingLevelDBDir() = 0;
260
261 };
262
263 class IndexedDBBrowserTestWithVersion0Schema : public
264     IndexedDBBrowserTestWithPreexistingLevelDB {
265   virtual std::string EnclosingLevelDBDir() OVERRIDE {
266     return "migration_from_0";
267   }
268 };
269
270 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion0Schema, MigrationTest) {
271   SimpleTest(GetTestUrl("indexeddb", "migration_test.html"));
272 }
273
274 class IndexedDBBrowserTestWithVersion123456Schema : public
275     IndexedDBBrowserTestWithPreexistingLevelDB {
276   virtual std::string EnclosingLevelDBDir() OVERRIDE {
277     return "schema_version_123456";
278   }
279 };
280
281 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion123456Schema,
282                        DestroyTest) {
283   int64 original_size = RequestDiskUsage();
284   EXPECT_GT(original_size, 0);
285   SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
286   int64 new_size = RequestDiskUsage();
287   EXPECT_NE(original_size, new_size);
288 }
289
290 class IndexedDBBrowserTestWithVersion987654SSVData : public
291     IndexedDBBrowserTestWithPreexistingLevelDB {
292   virtual std::string EnclosingLevelDBDir() OVERRIDE {
293     return "ssv_version_987654";
294   }
295 };
296
297 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithVersion987654SSVData,
298                        DestroyTest) {
299   int64 original_size = RequestDiskUsage();
300   EXPECT_GT(original_size, 0);
301   SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
302   int64 new_size = RequestDiskUsage();
303   EXPECT_NE(original_size, new_size);
304 }
305
306 class IndexedDBBrowserTestWithCorruptLevelDB : public
307     IndexedDBBrowserTestWithPreexistingLevelDB {
308   virtual std::string EnclosingLevelDBDir() OVERRIDE {
309     return "corrupt_leveldb";
310   }
311 };
312
313 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithCorruptLevelDB,
314                        DestroyTest) {
315   int64 original_size = RequestDiskUsage();
316   EXPECT_GT(original_size, 0);
317   SimpleTest(GetTestUrl("indexeddb", "open_bad_db.html"));
318   int64 new_size = RequestDiskUsage();
319   EXPECT_NE(original_size, new_size);
320 }
321
322 class IndexedDBBrowserTestWithMissingSSTFile : public
323     IndexedDBBrowserTestWithPreexistingLevelDB {
324   virtual std::string EnclosingLevelDBDir() OVERRIDE {
325     return "missing_sst";
326   }
327 };
328
329 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestWithMissingSSTFile,
330                        DestroyTest) {
331   int64 original_size = RequestDiskUsage();
332   EXPECT_GT(original_size, 0);
333   SimpleTest(GetTestUrl("indexeddb", "open_missing_table.html"));
334   int64 new_size = RequestDiskUsage();
335   EXPECT_NE(original_size, new_size);
336 }
337
338 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, LevelDBLogFileTest) {
339   // Any page that opens an IndexedDB will work here.
340   SimpleTest(GetTestUrl("indexeddb", "database_test.html"));
341   base::FilePath leveldb_dir(FILE_PATH_LITERAL("file__0.indexeddb.leveldb"));
342   base::FilePath log_file(FILE_PATH_LITERAL("LOG"));
343   base::FilePath log_file_path =
344       GetContext()->data_path().Append(leveldb_dir).Append(log_file);
345   int64 size;
346   EXPECT_TRUE(base::GetFileSize(log_file_path, &size));
347   EXPECT_GT(size, 0);
348 }
349
350 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CanDeleteWhenOverQuotaTest) {
351   SimpleTest(GetTestUrl("indexeddb", "fill_up_5k.html"));
352   int64 size = RequestDiskUsage();
353   const int kQuotaKilobytes = 2;
354   EXPECT_GT(size, kQuotaKilobytes * 1024);
355   SetQuota(kQuotaKilobytes);
356   SimpleTest(GetTestUrl("indexeddb", "delete_over_quota.html"));
357 }
358
359 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DeleteCompactsBackingStore) {
360   const GURL test_url = GetTestUrl("indexeddb", "delete_compact.html");
361   SimpleTest(GURL(test_url.spec() + "#fill"));
362   int64 after_filling = RequestDiskUsage();
363   EXPECT_GT(after_filling, 0);
364
365   SimpleTest(GURL(test_url.spec() + "#purge"));
366   int64 after_deleting = RequestDiskUsage();
367   EXPECT_LT(after_deleting, after_filling);
368
369   // The above tests verify basic assertions - that filling writes data and
370   // deleting reduces the amount stored.
371
372   // The below tests make assumptions about implementation specifics, such as
373   // data compression, compaction efficiency, and the maximum amount of
374   // metadata and log data remains after a deletion. It is possible that
375   // changes to the implementation may require these constants to be tweaked.
376
377   const int kTestFillBytes = 1024 * 1024 * 5;  // 5MB
378   EXPECT_GT(after_filling, kTestFillBytes);
379
380   const int kTestCompactBytes = 1024 * 1024 * 1;  // 1MB
381   EXPECT_LT(after_deleting, kTestCompactBytes);
382 }
383
384 // Complex multi-step (converted from pyauto) tests begin here.
385
386 // Verify null key path persists after restarting browser.
387 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_NullKeyPathPersistence) {
388   NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part1",
389                           "pass - first run");
390 }
391
392 // Verify null key path persists after restarting browser.
393 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, NullKeyPathPersistence) {
394   NavigateAndWaitForTitle(shell(), "bug_90635.html", "#part2",
395                           "pass - second run");
396 }
397
398 // Verify that a VERSION_CHANGE transaction is rolled back after a
399 // renderer/browser crash
400 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest,
401                        PRE_PRE_VersionChangeCrashResilience) {
402   NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part1",
403                           "pass - part1 - complete");
404 }
405
406 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, PRE_VersionChangeCrashResilience) {
407   NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part2",
408                           "pass - part2 - crash me");
409   NavigateToURL(shell(), GURL(kChromeUIBrowserCrashHost));
410 }
411
412 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, VersionChangeCrashResilience) {
413   NavigateAndWaitForTitle(shell(), "version_change_crash.html", "#part3",
414                           "pass - part3 - rolled back");
415 }
416
417 // Verify that open DB connections are closed when a tab is destroyed.
418 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ConnectionsClosedOnTabClose) {
419   NavigateAndWaitForTitle(shell(), "version_change_blocked.html", "#tab1",
420                           "setVersion(2) complete");
421
422   // Start on a different URL to force a new renderer process.
423   Shell* new_shell = CreateBrowser();
424   NavigateToURL(new_shell, GURL(kAboutBlankURL));
425   NavigateAndWaitForTitle(new_shell, "version_change_blocked.html", "#tab2",
426                           "setVersion(3) blocked");
427
428   base::string16 expected_title16(ASCIIToUTF16("setVersion(3) complete"));
429   TitleWatcher title_watcher(new_shell->web_contents(), expected_title16);
430
431   base::KillProcess(
432       shell()->web_contents()->GetRenderProcessHost()->GetHandle(), 0, true);
433   shell()->Close();
434
435   EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
436 }
437
438 // Verify that a "close" event is fired at database connections when
439 // the backing store is deleted.
440 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ForceCloseEventTest) {
441   NavigateAndWaitForTitle(shell(), "force_close_event.html", NULL,
442                           "connection ready");
443
444   GetContext()->TaskRunner()->PostTask(
445       FROM_HERE,
446       base::Bind(&IndexedDBContextImpl::DeleteForOrigin,
447                  GetContext(),
448                  GURL("file:///")));
449
450   base::string16 expected_title16(ASCIIToUTF16("connection closed"));
451   TitleWatcher title_watcher(shell()->web_contents(), expected_title16);
452   EXPECT_EQ(expected_title16, title_watcher.WaitAndGetTitle());
453 }
454
455 class IndexedDBBrowserTestSingleProcess : public IndexedDBBrowserTest {
456  public:
457   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
458     command_line->AppendSwitch(switches::kSingleProcess);
459   }
460 };
461
462 // Crashing on Android due to kSingleProcess flag: http://crbug.com/342525
463 #if defined(OS_ANDROID)
464 #define MAYBE_RenderThreadShutdownTest DISABLED_RenderThreadShutdownTest
465 #else
466 #define MAYBE_RenderThreadShutdownTest RenderThreadShutdownTest
467 #endif
468 IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTestSingleProcess,
469                        MAYBE_RenderThreadShutdownTest) {
470   SimpleTest(GetTestUrl("indexeddb", "shutdown_with_requests.html"));
471 }
472
473 }  // namespace content