Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / indexed_db / indexed_db_factory_unittest.cc
1 // Copyright 2013 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/files/file_util.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/logging.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/test/test_simple_task_runner.h"
11 #include "content/browser/indexed_db/indexed_db_connection.h"
12 #include "content/browser/indexed_db/indexed_db_context_impl.h"
13 #include "content/browser/indexed_db/indexed_db_factory_impl.h"
14 #include "content/browser/indexed_db/mock_indexed_db_callbacks.h"
15 #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h"
16 #include "storage/common/database/database_identifier.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/WebKit/public/platform/WebIDBDatabaseException.h"
19 #include "third_party/WebKit/public/platform/WebIDBTypes.h"
20 #include "url/gurl.h"
21
22 using base::ASCIIToUTF16;
23
24 namespace content {
25
26 namespace {
27
28 class MockIDBFactory : public IndexedDBFactoryImpl {
29  public:
30   explicit MockIDBFactory(IndexedDBContextImpl* context)
31       : IndexedDBFactoryImpl(context) {}
32   scoped_refptr<IndexedDBBackingStore> TestOpenBackingStore(
33       const GURL& origin,
34       const base::FilePath& data_directory) {
35     blink::WebIDBDataLoss data_loss =
36         blink::WebIDBDataLossNone;
37     std::string data_loss_message;
38     bool disk_full;
39     leveldb::Status s;
40     scoped_refptr<IndexedDBBackingStore> backing_store =
41         OpenBackingStore(origin,
42                          data_directory,
43                          NULL /* request_context */,
44                          &data_loss,
45                          &data_loss_message,
46                          &disk_full,
47                          &s);
48     EXPECT_EQ(blink::WebIDBDataLossNone, data_loss);
49     return backing_store;
50   }
51
52   void TestCloseBackingStore(IndexedDBBackingStore* backing_store) {
53     CloseBackingStore(backing_store->origin_url());
54   }
55
56   void TestReleaseBackingStore(IndexedDBBackingStore* backing_store,
57                                bool immediate) {
58     ReleaseBackingStore(backing_store->origin_url(), immediate);
59   }
60
61  private:
62   ~MockIDBFactory() override {}
63
64   DISALLOW_COPY_AND_ASSIGN(MockIDBFactory);
65 };
66
67 }  // namespace
68
69 class IndexedDBFactoryTest : public testing::Test {
70  public:
71   IndexedDBFactoryTest() {
72     task_runner_ = new base::TestSimpleTaskRunner();
73     context_ = new IndexedDBContextImpl(base::FilePath(),
74                                         NULL /* special_storage_policy */,
75                                         NULL /* quota_manager_proxy */,
76                                         task_runner_.get());
77     idb_factory_ = new MockIDBFactory(context_.get());
78   }
79
80  protected:
81   // For timers to post events.
82   base::MessageLoop loop_;
83
84   MockIDBFactory* factory() const { return idb_factory_.get(); }
85   void clear_factory() { idb_factory_ = NULL; }
86   IndexedDBContextImpl* context() const { return context_.get(); }
87
88  private:
89   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
90   scoped_refptr<IndexedDBContextImpl> context_;
91   scoped_refptr<MockIDBFactory> idb_factory_;
92
93   DISALLOW_COPY_AND_ASSIGN(IndexedDBFactoryTest);
94 };
95
96 TEST_F(IndexedDBFactoryTest, BackingStoreLifetime) {
97   GURL origin1("http://localhost:81");
98   GURL origin2("http://localhost:82");
99
100   base::ScopedTempDir temp_directory;
101   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
102   scoped_refptr<IndexedDBBackingStore> disk_store1 =
103       factory()->TestOpenBackingStore(origin1, temp_directory.path());
104
105   scoped_refptr<IndexedDBBackingStore> disk_store2 =
106       factory()->TestOpenBackingStore(origin1, temp_directory.path());
107   EXPECT_EQ(disk_store1.get(), disk_store2.get());
108
109   scoped_refptr<IndexedDBBackingStore> disk_store3 =
110       factory()->TestOpenBackingStore(origin2, temp_directory.path());
111
112   factory()->TestCloseBackingStore(disk_store1.get());
113   factory()->TestCloseBackingStore(disk_store3.get());
114
115   EXPECT_FALSE(disk_store1->HasOneRef());
116   EXPECT_FALSE(disk_store2->HasOneRef());
117   EXPECT_TRUE(disk_store3->HasOneRef());
118
119   disk_store2 = NULL;
120   EXPECT_TRUE(disk_store1->HasOneRef());
121 }
122
123 TEST_F(IndexedDBFactoryTest, BackingStoreLazyClose) {
124   GURL origin("http://localhost:81");
125
126   base::ScopedTempDir temp_directory;
127   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
128   scoped_refptr<IndexedDBBackingStore> store =
129       factory()->TestOpenBackingStore(origin, temp_directory.path());
130
131   // Give up the local refptr so that the factory has the only
132   // outstanding reference.
133   IndexedDBBackingStore* store_ptr = store.get();
134   store = NULL;
135   EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
136   factory()->TestReleaseBackingStore(store_ptr, false);
137   EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
138
139   factory()->TestOpenBackingStore(origin, temp_directory.path());
140   EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
141   factory()->TestReleaseBackingStore(store_ptr, false);
142   EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
143
144   // Take back a ref ptr and ensure that the actual close
145   // stops a running timer.
146   store = store_ptr;
147   factory()->TestCloseBackingStore(store_ptr);
148   EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
149 }
150
151 TEST_F(IndexedDBFactoryTest, MemoryBackingStoreLifetime) {
152   GURL origin1("http://localhost:81");
153   GURL origin2("http://localhost:82");
154
155   scoped_refptr<IndexedDBBackingStore> mem_store1 =
156       factory()->TestOpenBackingStore(origin1, base::FilePath());
157
158   scoped_refptr<IndexedDBBackingStore> mem_store2 =
159       factory()->TestOpenBackingStore(origin1, base::FilePath());
160   EXPECT_EQ(mem_store1.get(), mem_store2.get());
161
162   scoped_refptr<IndexedDBBackingStore> mem_store3 =
163       factory()->TestOpenBackingStore(origin2, base::FilePath());
164
165   factory()->TestCloseBackingStore(mem_store1.get());
166   factory()->TestCloseBackingStore(mem_store3.get());
167
168   EXPECT_FALSE(mem_store1->HasOneRef());
169   EXPECT_FALSE(mem_store2->HasOneRef());
170   EXPECT_FALSE(mem_store3->HasOneRef());
171
172   clear_factory();
173   EXPECT_FALSE(mem_store1->HasOneRef());  // mem_store1 and 2
174   EXPECT_FALSE(mem_store2->HasOneRef());  // mem_store1 and 2
175   EXPECT_TRUE(mem_store3->HasOneRef());
176
177   mem_store2 = NULL;
178   EXPECT_TRUE(mem_store1->HasOneRef());
179 }
180
181 TEST_F(IndexedDBFactoryTest, RejectLongOrigins) {
182   base::ScopedTempDir temp_directory;
183   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
184   const base::FilePath base_path = temp_directory.path();
185
186   int limit = base::GetMaximumPathComponentLength(base_path);
187   EXPECT_GT(limit, 0);
188
189   std::string origin(limit + 1, 'x');
190   GURL too_long_origin("http://" + origin + ":81/");
191   scoped_refptr<IndexedDBBackingStore> diskStore1 =
192       factory()->TestOpenBackingStore(too_long_origin, base_path);
193   EXPECT_FALSE(diskStore1.get());
194
195   GURL ok_origin("http://someorigin.com:82/");
196   scoped_refptr<IndexedDBBackingStore> diskStore2 =
197       factory()->TestOpenBackingStore(ok_origin, base_path);
198   EXPECT_TRUE(diskStore2.get());
199 }
200
201 class DiskFullFactory : public IndexedDBFactoryImpl {
202  public:
203   explicit DiskFullFactory(IndexedDBContextImpl* context)
204       : IndexedDBFactoryImpl(context) {}
205
206  private:
207   ~DiskFullFactory() override {}
208   scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
209       const GURL& origin_url,
210       const base::FilePath& data_directory,
211       net::URLRequestContext* request_context,
212       blink::WebIDBDataLoss* data_loss,
213       std::string* data_loss_message,
214       bool* disk_full,
215       leveldb::Status* s) override {
216     *disk_full = true;
217     *s = leveldb::Status::IOError("Disk is full");
218     return scoped_refptr<IndexedDBBackingStore>();
219   }
220
221   DISALLOW_COPY_AND_ASSIGN(DiskFullFactory);
222 };
223
224 class LookingForQuotaErrorMockCallbacks : public IndexedDBCallbacks {
225  public:
226   LookingForQuotaErrorMockCallbacks()
227       : IndexedDBCallbacks(NULL, 0, 0), error_called_(false) {}
228   void OnError(const IndexedDBDatabaseError& error) override {
229     error_called_ = true;
230     EXPECT_EQ(blink::WebIDBDatabaseExceptionQuotaError, error.code());
231   }
232   bool error_called() const { return error_called_; }
233
234  private:
235   ~LookingForQuotaErrorMockCallbacks() override {}
236   bool error_called_;
237
238   DISALLOW_COPY_AND_ASSIGN(LookingForQuotaErrorMockCallbacks);
239 };
240
241 TEST_F(IndexedDBFactoryTest, QuotaErrorOnDiskFull) {
242   const GURL origin("http://localhost:81");
243   base::ScopedTempDir temp_directory;
244   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
245
246   scoped_refptr<DiskFullFactory> factory = new DiskFullFactory(context());
247   scoped_refptr<LookingForQuotaErrorMockCallbacks> callbacks =
248       new LookingForQuotaErrorMockCallbacks;
249   scoped_refptr<IndexedDBDatabaseCallbacks> dummy_database_callbacks =
250       new IndexedDBDatabaseCallbacks(NULL, 0, 0);
251   const base::string16 name(ASCIIToUTF16("name"));
252   IndexedDBPendingConnection connection(callbacks,
253                                         dummy_database_callbacks,
254                                         0, /* child_process_id */
255                                         2, /* transaction_id */
256                                         1 /* version */);
257   factory->Open(name,
258                 connection,
259                 NULL /* request_context */,
260                 origin,
261                 temp_directory.path());
262   EXPECT_TRUE(callbacks->error_called());
263 }
264
265 TEST_F(IndexedDBFactoryTest, BackingStoreReleasedOnForcedClose) {
266   GURL origin("http://localhost:81");
267
268   base::ScopedTempDir temp_directory;
269   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
270
271   scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
272   scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
273       new MockIndexedDBDatabaseCallbacks());
274   const int64 transaction_id = 1;
275   IndexedDBPendingConnection connection(
276       callbacks,
277       db_callbacks,
278       0, /* child_process_id */
279       transaction_id,
280       IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
281   factory()->Open(ASCIIToUTF16("db"),
282                   connection,
283                   NULL /* request_context */,
284                   origin,
285                   temp_directory.path());
286
287   EXPECT_TRUE(callbacks->connection());
288
289   EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
290   EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
291
292   callbacks->connection()->ForceClose();
293
294   EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
295   EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
296 }
297
298 TEST_F(IndexedDBFactoryTest, BackingStoreReleaseDelayedOnClose) {
299   GURL origin("http://localhost:81");
300
301   base::ScopedTempDir temp_directory;
302   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
303
304   scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
305   scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
306       new MockIndexedDBDatabaseCallbacks());
307   const int64 transaction_id = 1;
308   IndexedDBPendingConnection connection(
309       callbacks,
310       db_callbacks,
311       0, /* child_process_id */
312       transaction_id,
313       IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
314   factory()->Open(ASCIIToUTF16("db"),
315                   connection,
316                   NULL /* request_context */,
317                   origin,
318                   temp_directory.path());
319
320   EXPECT_TRUE(callbacks->connection());
321   IndexedDBBackingStore* store =
322       callbacks->connection()->database()->backing_store();
323   EXPECT_FALSE(store->HasOneRef());  // Factory and database.
324
325   EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
326   callbacks->connection()->Close();
327   EXPECT_TRUE(store->HasOneRef());  // Factory.
328   EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
329   EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
330   EXPECT_TRUE(store->close_timer()->IsRunning());
331
332   // Take a ref so it won't be destroyed out from under the test.
333   scoped_refptr<IndexedDBBackingStore> store_ref = store;
334   // Now simulate shutdown, which should stop the timer.
335   factory()->ContextDestroyed();
336   EXPECT_TRUE(store->HasOneRef());  // Local.
337   EXPECT_FALSE(store->close_timer()->IsRunning());
338   EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
339   EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
340 }
341
342 TEST_F(IndexedDBFactoryTest, DeleteDatabaseClosesBackingStore) {
343   GURL origin("http://localhost:81");
344
345   base::ScopedTempDir temp_directory;
346   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
347
348   EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
349
350   const bool expect_connection = false;
351   scoped_refptr<MockIndexedDBCallbacks> callbacks(
352       new MockIndexedDBCallbacks(expect_connection));
353   factory()->DeleteDatabase(ASCIIToUTF16("db"),
354                             NULL /* request_context */,
355                             callbacks,
356                             origin,
357                             temp_directory.path());
358
359   EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
360   EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
361
362   // Now simulate shutdown, which should stop the timer.
363   factory()->ContextDestroyed();
364
365   EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
366   EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
367 }
368
369 TEST_F(IndexedDBFactoryTest, GetDatabaseNamesClosesBackingStore) {
370   GURL origin("http://localhost:81");
371
372   base::ScopedTempDir temp_directory;
373   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
374
375   EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
376
377   const bool expect_connection = false;
378   scoped_refptr<MockIndexedDBCallbacks> callbacks(
379       new MockIndexedDBCallbacks(expect_connection));
380   factory()->GetDatabaseNames(
381       callbacks, origin, temp_directory.path(), NULL /* request_context */);
382
383   EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
384   EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
385
386   // Now simulate shutdown, which should stop the timer.
387   factory()->ContextDestroyed();
388
389   EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
390   EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
391 }
392
393 TEST_F(IndexedDBFactoryTest, ForceCloseReleasesBackingStore) {
394   GURL origin("http://localhost:81");
395
396   base::ScopedTempDir temp_directory;
397   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
398
399   scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
400   scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
401       new MockIndexedDBDatabaseCallbacks());
402   const int64 transaction_id = 1;
403   IndexedDBPendingConnection connection(
404       callbacks,
405       db_callbacks,
406       0, /* child_process_id */
407       transaction_id,
408       IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
409   factory()->Open(ASCIIToUTF16("db"),
410                   connection,
411                   NULL /* request_context */,
412                   origin,
413                   temp_directory.path());
414
415   EXPECT_TRUE(callbacks->connection());
416   EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
417   EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
418
419   callbacks->connection()->Close();
420
421   EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
422   EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
423
424   factory()->ForceClose(origin);
425
426   EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
427   EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
428
429   // Ensure it is safe if the store is not open.
430   factory()->ForceClose(origin);
431 }
432
433 class UpgradeNeededCallbacks : public MockIndexedDBCallbacks {
434  public:
435   UpgradeNeededCallbacks() {}
436
437   void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
438                  const IndexedDBDatabaseMetadata& metadata) override {
439     EXPECT_TRUE(connection_.get());
440     EXPECT_FALSE(connection.get());
441   }
442
443   void OnUpgradeNeeded(
444       int64 old_version,
445       scoped_ptr<IndexedDBConnection> connection,
446       const content::IndexedDBDatabaseMetadata& metadata) override {
447     connection_ = connection.Pass();
448   }
449
450  protected:
451   ~UpgradeNeededCallbacks() override {}
452
453  private:
454   DISALLOW_COPY_AND_ASSIGN(UpgradeNeededCallbacks);
455 };
456
457 class ErrorCallbacks : public MockIndexedDBCallbacks {
458  public:
459   ErrorCallbacks() : MockIndexedDBCallbacks(false), saw_error_(false) {}
460
461   void OnError(const IndexedDBDatabaseError& error) override {
462     saw_error_= true;
463   }
464   bool saw_error() const { return saw_error_; }
465
466  private:
467   ~ErrorCallbacks() override {}
468   bool saw_error_;
469
470   DISALLOW_COPY_AND_ASSIGN(ErrorCallbacks);
471 };
472
473 TEST_F(IndexedDBFactoryTest, DatabaseFailedOpen) {
474   GURL origin("http://localhost:81");
475
476   base::ScopedTempDir temp_directory;
477   ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
478
479   const base::string16 db_name(ASCIIToUTF16("db"));
480   const int64 db_version = 2;
481   const int64 transaction_id = 1;
482   scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks(
483       new MockIndexedDBDatabaseCallbacks());
484
485   // Open at version 2, then close.
486   {
487     scoped_refptr<MockIndexedDBCallbacks> callbacks(
488         new UpgradeNeededCallbacks());
489     IndexedDBPendingConnection connection(callbacks,
490                                           db_callbacks,
491                                           0, /* child_process_id */
492                                           transaction_id,
493                                           db_version);
494     factory()->Open(db_name,
495                     connection,
496                     NULL /* request_context */,
497                     origin,
498                     temp_directory.path());
499     EXPECT_TRUE(factory()->IsDatabaseOpen(origin, db_name));
500
501     // Pump the message loop so the upgrade transaction can run.
502     base::MessageLoop::current()->RunUntilIdle();
503     EXPECT_TRUE(callbacks->connection());
504     callbacks->connection()->database()->Commit(transaction_id);
505
506     callbacks->connection()->Close();
507     EXPECT_FALSE(factory()->IsDatabaseOpen(origin, db_name));
508   }
509
510   // Open at version < 2, which will fail; ensure factory doesn't retain
511   // the database object.
512   {
513     scoped_refptr<ErrorCallbacks> callbacks(new ErrorCallbacks());
514     IndexedDBPendingConnection connection(callbacks,
515                                           db_callbacks,
516                                           0, /* child_process_id */
517                                           transaction_id,
518                                           db_version - 1);
519     factory()->Open(db_name,
520                     connection,
521                     NULL /* request_context */,
522                     origin,
523                     temp_directory.path());
524     EXPECT_TRUE(callbacks->saw_error());
525     EXPECT_FALSE(factory()->IsDatabaseOpen(origin, db_name));
526   }
527
528   // Terminate all pending-close timers.
529   factory()->ForceClose(origin);
530 }
531
532 }  // namespace content