Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / indexed_db / indexed_db_factory_unittest.cc
blobf30f45128bb8a83a50385b9c4292f48abb593247
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.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 IndexedDBFactory {
30 public:
31 MockIDBFactory(IndexedDBContextImpl* context) : IndexedDBFactory(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 scoped_refptr<IndexedDBBackingStore> backing_store =
40 OpenBackingStore(origin,
41 data_directory,
42 NULL /* request_context */,
43 &data_loss,
44 &data_loss_message,
45 &disk_full);
46 EXPECT_EQ(blink::WebIDBDataLossNone, data_loss);
47 return backing_store;
50 void TestCloseBackingStore(IndexedDBBackingStore* backing_store) {
51 CloseBackingStore(backing_store->origin_url());
54 void TestReleaseBackingStore(IndexedDBBackingStore* backing_store,
55 bool immediate) {
56 ReleaseBackingStore(backing_store->origin_url(), immediate);
59 private:
60 virtual ~MockIDBFactory() {}
63 } // namespace
65 class IndexedDBFactoryTest : public testing::Test {
66 public:
67 IndexedDBFactoryTest() {
68 task_runner_ = new base::TestSimpleTaskRunner();
69 context_ = new IndexedDBContextImpl(base::FilePath(),
70 NULL /* special_storage_policy */,
71 NULL /* quota_manager_proxy */,
72 task_runner_.get());
73 idb_factory_ = new MockIDBFactory(context_.get());
76 protected:
77 // For timers to post events.
78 base::MessageLoop loop_;
80 MockIDBFactory* factory() const { return idb_factory_.get(); }
81 void clear_factory() { idb_factory_ = NULL; }
82 IndexedDBContextImpl* context() const { return context_.get(); }
84 private:
85 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
86 scoped_refptr<IndexedDBContextImpl> context_;
87 scoped_refptr<MockIDBFactory> idb_factory_;
89 DISALLOW_COPY_AND_ASSIGN(IndexedDBFactoryTest);
92 TEST_F(IndexedDBFactoryTest, BackingStoreLifetime) {
93 GURL origin1("http://localhost:81");
94 GURL origin2("http://localhost:82");
96 base::ScopedTempDir temp_directory;
97 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
98 scoped_refptr<IndexedDBBackingStore> disk_store1 =
99 factory()->TestOpenBackingStore(origin1, temp_directory.path());
101 scoped_refptr<IndexedDBBackingStore> disk_store2 =
102 factory()->TestOpenBackingStore(origin1, temp_directory.path());
103 EXPECT_EQ(disk_store1.get(), disk_store2.get());
105 scoped_refptr<IndexedDBBackingStore> disk_store3 =
106 factory()->TestOpenBackingStore(origin2, temp_directory.path());
108 factory()->TestCloseBackingStore(disk_store1);
109 factory()->TestCloseBackingStore(disk_store3);
111 EXPECT_FALSE(disk_store1->HasOneRef());
112 EXPECT_FALSE(disk_store2->HasOneRef());
113 EXPECT_TRUE(disk_store3->HasOneRef());
115 disk_store2 = NULL;
116 EXPECT_TRUE(disk_store1->HasOneRef());
119 TEST_F(IndexedDBFactoryTest, BackingStoreLazyClose) {
120 GURL origin("http://localhost:81");
122 base::ScopedTempDir temp_directory;
123 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
124 scoped_refptr<IndexedDBBackingStore> store =
125 factory()->TestOpenBackingStore(origin, temp_directory.path());
127 // Give up the local refptr so that the factory has the only
128 // outstanding reference.
129 IndexedDBBackingStore* store_ptr = store.get();
130 store = NULL;
131 EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
132 factory()->TestReleaseBackingStore(store_ptr, false);
133 EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
135 factory()->TestOpenBackingStore(origin, temp_directory.path());
136 EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
137 factory()->TestReleaseBackingStore(store_ptr, false);
138 EXPECT_TRUE(store_ptr->close_timer()->IsRunning());
140 // Take back a ref ptr and ensure that the actual close
141 // stops a running timer.
142 store = store_ptr;
143 factory()->TestCloseBackingStore(store_ptr);
144 EXPECT_FALSE(store_ptr->close_timer()->IsRunning());
147 TEST_F(IndexedDBFactoryTest, MemoryBackingStoreLifetime) {
148 GURL origin1("http://localhost:81");
149 GURL origin2("http://localhost:82");
151 scoped_refptr<IndexedDBBackingStore> mem_store1 =
152 factory()->TestOpenBackingStore(origin1, base::FilePath());
154 scoped_refptr<IndexedDBBackingStore> mem_store2 =
155 factory()->TestOpenBackingStore(origin1, base::FilePath());
156 EXPECT_EQ(mem_store1.get(), mem_store2.get());
158 scoped_refptr<IndexedDBBackingStore> mem_store3 =
159 factory()->TestOpenBackingStore(origin2, base::FilePath());
161 factory()->TestCloseBackingStore(mem_store1);
162 factory()->TestCloseBackingStore(mem_store3);
164 EXPECT_FALSE(mem_store1->HasOneRef());
165 EXPECT_FALSE(mem_store2->HasOneRef());
166 EXPECT_FALSE(mem_store3->HasOneRef());
168 clear_factory();
169 EXPECT_FALSE(mem_store1->HasOneRef()); // mem_store1 and 2
170 EXPECT_FALSE(mem_store2->HasOneRef()); // mem_store1 and 2
171 EXPECT_TRUE(mem_store3->HasOneRef());
173 mem_store2 = NULL;
174 EXPECT_TRUE(mem_store1->HasOneRef());
177 TEST_F(IndexedDBFactoryTest, RejectLongOrigins) {
178 base::ScopedTempDir temp_directory;
179 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
180 const base::FilePath base_path = temp_directory.path();
182 int limit = base::GetMaximumPathComponentLength(base_path);
183 EXPECT_GT(limit, 0);
185 std::string origin(limit + 1, 'x');
186 GURL too_long_origin("http://" + origin + ":81/");
187 scoped_refptr<IndexedDBBackingStore> diskStore1 =
188 factory()->TestOpenBackingStore(too_long_origin, base_path);
189 EXPECT_FALSE(diskStore1);
191 GURL ok_origin("http://someorigin.com:82/");
192 scoped_refptr<IndexedDBBackingStore> diskStore2 =
193 factory()->TestOpenBackingStore(ok_origin, base_path);
194 EXPECT_TRUE(diskStore2);
197 class DiskFullFactory : public IndexedDBFactory {
198 public:
199 DiskFullFactory(IndexedDBContextImpl* context) : IndexedDBFactory(context) {}
201 private:
202 virtual ~DiskFullFactory() {}
203 virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStore(
204 const GURL& origin_url,
205 const base::FilePath& data_directory,
206 net::URLRequestContext* request_context,
207 blink::WebIDBDataLoss* data_loss,
208 std::string* data_loss_message,
209 bool* disk_full) OVERRIDE {
210 *disk_full = true;
211 return scoped_refptr<IndexedDBBackingStore>();
215 class LookingForQuotaErrorMockCallbacks : public IndexedDBCallbacks {
216 public:
217 LookingForQuotaErrorMockCallbacks()
218 : IndexedDBCallbacks(NULL, 0, 0), error_called_(false) {}
219 virtual void OnError(const IndexedDBDatabaseError& error) OVERRIDE {
220 error_called_ = true;
221 EXPECT_EQ(blink::WebIDBDatabaseExceptionQuotaError, error.code());
223 bool error_called() const { return error_called_; }
225 private:
226 virtual ~LookingForQuotaErrorMockCallbacks() {}
227 bool error_called_;
230 TEST_F(IndexedDBFactoryTest, QuotaErrorOnDiskFull) {
231 const GURL origin("http://localhost:81");
232 base::ScopedTempDir temp_directory;
233 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
235 scoped_refptr<DiskFullFactory> factory = new DiskFullFactory(context());
236 scoped_refptr<LookingForQuotaErrorMockCallbacks> callbacks =
237 new LookingForQuotaErrorMockCallbacks;
238 scoped_refptr<IndexedDBDatabaseCallbacks> dummy_database_callbacks =
239 new IndexedDBDatabaseCallbacks(NULL, 0, 0);
240 const base::string16 name(ASCIIToUTF16("name"));
241 IndexedDBPendingConnection connection(callbacks,
242 dummy_database_callbacks,
243 0, /* child_process_id */
244 2, /* transaction_id */
245 1 /* version */);
246 factory->Open(name,
247 connection,
248 NULL /* request_context */,
249 origin,
250 temp_directory.path());
251 EXPECT_TRUE(callbacks->error_called());
254 TEST_F(IndexedDBFactoryTest, BackingStoreReleasedOnForcedClose) {
255 GURL origin("http://localhost:81");
257 base::ScopedTempDir temp_directory;
258 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
260 scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
261 scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
262 new MockIndexedDBDatabaseCallbacks());
263 const int64 transaction_id = 1;
264 IndexedDBPendingConnection connection(
265 callbacks,
266 db_callbacks,
267 0, /* child_process_id */
268 transaction_id,
269 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
270 factory()->Open(ASCIIToUTF16("db"),
271 connection,
272 NULL /* request_context */,
273 origin,
274 temp_directory.path());
276 EXPECT_TRUE(callbacks->connection());
278 EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
279 EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
281 callbacks->connection()->ForceClose();
283 EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
284 EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
287 TEST_F(IndexedDBFactoryTest, BackingStoreReleaseDelayedOnClose) {
288 GURL origin("http://localhost:81");
290 base::ScopedTempDir temp_directory;
291 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
293 scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
294 scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
295 new MockIndexedDBDatabaseCallbacks());
296 const int64 transaction_id = 1;
297 IndexedDBPendingConnection connection(
298 callbacks,
299 db_callbacks,
300 0, /* child_process_id */
301 transaction_id,
302 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
303 factory()->Open(ASCIIToUTF16("db"),
304 connection,
305 NULL /* request_context */,
306 origin,
307 temp_directory.path());
309 EXPECT_TRUE(callbacks->connection());
310 IndexedDBBackingStore* store =
311 callbacks->connection()->database()->backing_store();
312 EXPECT_FALSE(store->HasOneRef()); // Factory and database.
314 EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
315 callbacks->connection()->Close();
316 EXPECT_TRUE(store->HasOneRef()); // Factory.
317 EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
318 EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
319 EXPECT_TRUE(store->close_timer()->IsRunning());
321 // Take a ref so it won't be destroyed out from under the test.
322 scoped_refptr<IndexedDBBackingStore> store_ref = store;
323 // Now simulate shutdown, which should stop the timer.
324 factory()->ContextDestroyed();
325 EXPECT_TRUE(store->HasOneRef()); // Local.
326 EXPECT_FALSE(store->close_timer()->IsRunning());
327 EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
328 EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
331 TEST_F(IndexedDBFactoryTest, DeleteDatabaseClosesBackingStore) {
332 GURL origin("http://localhost:81");
334 base::ScopedTempDir temp_directory;
335 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
337 EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
339 const bool expect_connection = false;
340 scoped_refptr<MockIndexedDBCallbacks> callbacks(
341 new MockIndexedDBCallbacks(expect_connection));
342 factory()->DeleteDatabase(ASCIIToUTF16("db"),
343 NULL /* request_context */,
344 callbacks,
345 origin,
346 temp_directory.path());
348 EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
349 EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
351 // Now simulate shutdown, which should stop the timer.
352 factory()->ContextDestroyed();
354 EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
355 EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
358 TEST_F(IndexedDBFactoryTest, GetDatabaseNamesClosesBackingStore) {
359 GURL origin("http://localhost:81");
361 base::ScopedTempDir temp_directory;
362 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
364 EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
366 const bool expect_connection = false;
367 scoped_refptr<MockIndexedDBCallbacks> callbacks(
368 new MockIndexedDBCallbacks(expect_connection));
369 factory()->GetDatabaseNames(
370 callbacks, origin, temp_directory.path(), NULL /* request_context */);
372 EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
373 EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
375 // Now simulate shutdown, which should stop the timer.
376 factory()->ContextDestroyed();
378 EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
379 EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
382 TEST_F(IndexedDBFactoryTest, ForceCloseReleasesBackingStore) {
383 GURL origin("http://localhost:81");
385 base::ScopedTempDir temp_directory;
386 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
388 scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks());
389 scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks(
390 new MockIndexedDBDatabaseCallbacks());
391 const int64 transaction_id = 1;
392 IndexedDBPendingConnection connection(
393 callbacks,
394 db_callbacks,
395 0, /* child_process_id */
396 transaction_id,
397 IndexedDBDatabaseMetadata::DEFAULT_INT_VERSION);
398 factory()->Open(ASCIIToUTF16("db"),
399 connection,
400 NULL /* request_context */,
401 origin,
402 temp_directory.path());
404 EXPECT_TRUE(callbacks->connection());
405 EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
406 EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
408 callbacks->connection()->Close();
410 EXPECT_TRUE(factory()->IsBackingStoreOpen(origin));
411 EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin));
413 factory()->ForceClose(origin);
415 EXPECT_FALSE(factory()->IsBackingStoreOpen(origin));
416 EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin));
418 // Ensure it is safe if the store is not open.
419 factory()->ForceClose(origin);
422 class UpgradeNeededCallbacks : public MockIndexedDBCallbacks {
423 public:
424 virtual void OnSuccess(scoped_ptr<IndexedDBConnection> connection,
425 const IndexedDBDatabaseMetadata& metadata) OVERRIDE {
426 EXPECT_TRUE(connection_.get());
427 EXPECT_FALSE(connection.get());
430 virtual void OnUpgradeNeeded(
431 int64 old_version,
432 scoped_ptr<IndexedDBConnection> connection,
433 const content::IndexedDBDatabaseMetadata& metadata) OVERRIDE {
434 connection_ = connection.Pass();
437 protected:
438 virtual ~UpgradeNeededCallbacks() {}
441 class ErrorCallbacks : public MockIndexedDBCallbacks {
442 public:
443 ErrorCallbacks() : MockIndexedDBCallbacks(false), saw_error_(false) {}
445 virtual void OnError(const IndexedDBDatabaseError& error) OVERRIDE {
446 saw_error_= true;
448 bool saw_error() const { return saw_error_; }
450 private:
451 virtual ~ErrorCallbacks() {}
452 bool saw_error_;
455 TEST_F(IndexedDBFactoryTest, DatabaseFailedOpen) {
456 GURL origin("http://localhost:81");
458 base::ScopedTempDir temp_directory;
459 ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
461 const base::string16 db_name(ASCIIToUTF16("db"));
462 const int64 db_version = 2;
463 const int64 transaction_id = 1;
464 scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks(
465 new MockIndexedDBDatabaseCallbacks());
467 // Open at version 2, then close.
469 scoped_refptr<MockIndexedDBCallbacks> callbacks(
470 new UpgradeNeededCallbacks());
471 IndexedDBPendingConnection connection(callbacks,
472 db_callbacks,
473 0, /* child_process_id */
474 transaction_id,
475 db_version);
476 factory()->Open(db_name,
477 connection,
478 NULL /* request_context */,
479 origin,
480 temp_directory.path());
481 EXPECT_TRUE(factory()->IsDatabaseOpen(origin, db_name));
483 // Pump the message loop so the upgrade transaction can run.
484 base::MessageLoop::current()->RunUntilIdle();
485 EXPECT_TRUE(callbacks->connection());
486 callbacks->connection()->database()->Commit(transaction_id);
488 callbacks->connection()->Close();
489 EXPECT_FALSE(factory()->IsDatabaseOpen(origin, db_name));
492 // Open at version < 2, which will fail; ensure factory doesn't retain
493 // the database object.
495 scoped_refptr<ErrorCallbacks> callbacks(new ErrorCallbacks());
496 IndexedDBPendingConnection connection(callbacks,
497 db_callbacks,
498 0, /* child_process_id */
499 transaction_id,
500 db_version - 1);
501 factory()->Open(db_name,
502 connection,
503 NULL /* request_context */,
504 origin,
505 temp_directory.path());
506 EXPECT_TRUE(callbacks->saw_error());
507 EXPECT_FALSE(factory()->IsDatabaseOpen(origin, db_name));
510 // Terminate all pending-close timers.
511 factory()->ForceClose(origin);
514 } // namespace content