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