Chromium Code Reviews| Index: content/browser/indexed_db/indexed_db_factory_unittest.cc |
| diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc |
| index 374143ad3b935d4c7102bb4ac0e1398f883329ad..1c872813917b94c3eab85a3507a5d29feb2ff4f3 100644 |
| --- a/content/browser/indexed_db/indexed_db_factory_unittest.cc |
| +++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc |
| @@ -14,7 +14,7 @@ |
| #include "base/run_loop.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/test_simple_task_runner.h" |
| -#include "base/threading/thread_task_runner_handle.h" |
| +#include "base/threading/sequenced_task_runner_handle.h" |
| #include "content/browser/indexed_db/indexed_db_connection.h" |
| #include "content/browser/indexed_db/indexed_db_context_impl.h" |
| #include "content/browser/indexed_db/indexed_db_data_format_version.h" |
| @@ -22,6 +22,7 @@ |
| #include "content/browser/indexed_db/mock_indexed_db_callbacks.h" |
| #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| +#include "content/public/test/test_utils.h" |
| #include "storage/browser/test/mock_quota_manager_proxy.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h" |
| @@ -72,14 +73,15 @@ class MockIDBFactory : public IndexedDBFactoryImpl { |
| class IndexedDBFactoryTest : public testing::Test { |
| public: |
| + IndexedDBFactoryTest() |
| + : quota_manager_proxy_( |
| + base::MakeRefCounted<MockQuotaManagerProxy>(nullptr, nullptr)) {} |
| + |
| void SetUp() override { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| - task_runner_ = new base::TestSimpleTaskRunner(); |
| - quota_manager_proxy_ = new MockQuotaManagerProxy(nullptr, nullptr); |
| - context_ = new IndexedDBContextImpl( |
| + context_ = base::MakeRefCounted<IndexedDBContextImpl>( |
| temp_dir_.GetPath(), nullptr /* special_storage_policy */, |
| - quota_manager_proxy_.get(), task_runner_.get()); |
| - idb_factory_ = new MockIDBFactory(context_.get()); |
| + quota_manager_proxy_.get()); |
| } |
| void TearDown() override { |
| @@ -87,127 +89,164 @@ class IndexedDBFactoryTest : public testing::Test { |
| } |
| protected: |
| - IndexedDBFactoryTest() {} |
| - MockIDBFactory* factory() const { return idb_factory_.get(); } |
| - void clear_factory() { idb_factory_ = nullptr; } |
| IndexedDBContextImpl* context() const { return context_.get(); } |
| private: |
| + TestBrowserThreadBundle thread_bundle_; |
| + |
| base::ScopedTempDir temp_dir_; |
| - scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
| - scoped_refptr<IndexedDBContextImpl> context_; |
| - scoped_refptr<MockIDBFactory> idb_factory_; |
| scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_; |
| - TestBrowserThreadBundle thread_bundle_; |
| + scoped_refptr<IndexedDBContextImpl> context_; |
| DISALLOW_COPY_AND_ASSIGN(IndexedDBFactoryTest); |
| }; |
| TEST_F(IndexedDBFactoryTest, BackingStoreLifetime) { |
| - const Origin origin1(GURL("http://localhost:81")); |
| - const Origin origin2(GURL("http://localhost:82")); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context) { |
| + scoped_refptr<MockIDBFactory> factory = |
| + base::MakeRefCounted<MockIDBFactory>(context); |
| + |
| + const Origin origin1(GURL("http://localhost:81")); |
| + const Origin origin2(GURL("http://localhost:82")); |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| - scoped_refptr<IndexedDBBackingStore> disk_store1 = |
| - factory()->TestOpenBackingStore(origin1, temp_directory.GetPath()); |
| + scoped_refptr<IndexedDBBackingStore> disk_store1 = |
| + factory->TestOpenBackingStore(origin1, context->data_path()); |
| - scoped_refptr<IndexedDBBackingStore> disk_store2 = |
| - factory()->TestOpenBackingStore(origin1, temp_directory.GetPath()); |
| - EXPECT_EQ(disk_store1.get(), disk_store2.get()); |
| + scoped_refptr<IndexedDBBackingStore> disk_store2 = |
| + factory->TestOpenBackingStore(origin1, context->data_path()); |
| + EXPECT_EQ(disk_store1.get(), disk_store2.get()); |
| - scoped_refptr<IndexedDBBackingStore> disk_store3 = |
| - factory()->TestOpenBackingStore(origin2, temp_directory.GetPath()); |
| + scoped_refptr<IndexedDBBackingStore> disk_store3 = |
| + factory->TestOpenBackingStore(origin2, context->data_path()); |
| - factory()->TestCloseBackingStore(disk_store1.get()); |
| - factory()->TestCloseBackingStore(disk_store3.get()); |
| + factory->TestCloseBackingStore(disk_store1.get()); |
| + factory->TestCloseBackingStore(disk_store3.get()); |
| - EXPECT_FALSE(disk_store1->HasOneRef()); |
| - EXPECT_FALSE(disk_store2->HasOneRef()); |
| - EXPECT_TRUE(disk_store3->HasOneRef()); |
| + EXPECT_FALSE(disk_store1->HasOneRef()); |
| + EXPECT_FALSE(disk_store2->HasOneRef()); |
| + EXPECT_TRUE(disk_store3->HasOneRef()); |
| - disk_store2 = nullptr; |
| - EXPECT_TRUE(disk_store1->HasOneRef()); |
| + disk_store2 = nullptr; |
| + EXPECT_TRUE(disk_store1->HasOneRef()); |
| + }, |
| + base::Unretained(context()))); |
| + |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| TEST_F(IndexedDBFactoryTest, BackingStoreLazyClose) { |
| - const Origin origin(GURL("http://localhost:81")); |
| - |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| - scoped_refptr<IndexedDBBackingStore> store = |
| - factory()->TestOpenBackingStore(origin, temp_directory.GetPath()); |
| - |
| - // Give up the local refptr so that the factory has the only |
| - // outstanding reference. |
| - IndexedDBBackingStore* store_ptr = store.get(); |
| - store = nullptr; |
| - EXPECT_FALSE(store_ptr->close_timer()->IsRunning()); |
| - factory()->TestReleaseBackingStore(store_ptr, false); |
| - EXPECT_TRUE(store_ptr->close_timer()->IsRunning()); |
| - |
| - factory()->TestOpenBackingStore(origin, temp_directory.GetPath()); |
| - EXPECT_FALSE(store_ptr->close_timer()->IsRunning()); |
| - factory()->TestReleaseBackingStore(store_ptr, false); |
| - EXPECT_TRUE(store_ptr->close_timer()->IsRunning()); |
| - |
| - // Take back a ref ptr and ensure that the actual close |
| - // stops a running timer. |
| - store = store_ptr; |
| - factory()->TestCloseBackingStore(store_ptr); |
| - EXPECT_FALSE(store_ptr->close_timer()->IsRunning()); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context) { |
| + |
| + scoped_refptr<MockIDBFactory> factory = |
| + base::MakeRefCounted<MockIDBFactory>(context); |
| + |
| + const Origin origin(GURL("http://localhost:81")); |
| + |
| + scoped_refptr<IndexedDBBackingStore> store = |
| + factory->TestOpenBackingStore(origin, context->data_path()); |
| + |
| + // Give up the local refptr so that the factory has the only |
| + // outstanding reference. |
| + IndexedDBBackingStore* store_ptr = store.get(); |
| + store = nullptr; |
| + EXPECT_FALSE(store_ptr->close_timer()->IsRunning()); |
| + factory->TestReleaseBackingStore(store_ptr, false); |
| + EXPECT_TRUE(store_ptr->close_timer()->IsRunning()); |
| + |
| + factory->TestOpenBackingStore(origin, context->data_path()); |
| + EXPECT_FALSE(store_ptr->close_timer()->IsRunning()); |
| + factory->TestReleaseBackingStore(store_ptr, false); |
| + EXPECT_TRUE(store_ptr->close_timer()->IsRunning()); |
| + |
| + // Take back a ref ptr and ensure that the actual close |
| + // stops a running timer. |
| + store = store_ptr; |
| + factory->TestCloseBackingStore(store_ptr); |
| + EXPECT_FALSE(store_ptr->close_timer()->IsRunning()); |
| + }, |
| + base::Unretained(context()))); |
| + |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| TEST_F(IndexedDBFactoryTest, MemoryBackingStoreLifetime) { |
| - const Origin origin1(GURL("http://localhost:81")); |
| - const Origin origin2(GURL("http://localhost:82")); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context) { |
| + |
| + scoped_refptr<MockIDBFactory> factory = |
| + base::MakeRefCounted<MockIDBFactory>(context); |
| - scoped_refptr<IndexedDBBackingStore> mem_store1 = |
| - factory()->TestOpenBackingStore(origin1, base::FilePath()); |
| + const Origin origin1(GURL("http://localhost:81")); |
| + const Origin origin2(GURL("http://localhost:82")); |
| - scoped_refptr<IndexedDBBackingStore> mem_store2 = |
| - factory()->TestOpenBackingStore(origin1, base::FilePath()); |
| - EXPECT_EQ(mem_store1.get(), mem_store2.get()); |
| + scoped_refptr<IndexedDBBackingStore> mem_store1 = |
| + factory->TestOpenBackingStore(origin1, base::FilePath()); |
| - scoped_refptr<IndexedDBBackingStore> mem_store3 = |
| - factory()->TestOpenBackingStore(origin2, base::FilePath()); |
| + scoped_refptr<IndexedDBBackingStore> mem_store2 = |
| + factory->TestOpenBackingStore(origin1, base::FilePath()); |
| + EXPECT_EQ(mem_store1.get(), mem_store2.get()); |
| - factory()->TestCloseBackingStore(mem_store1.get()); |
| - factory()->TestCloseBackingStore(mem_store3.get()); |
| + scoped_refptr<IndexedDBBackingStore> mem_store3 = |
| + factory->TestOpenBackingStore(origin2, base::FilePath()); |
| - EXPECT_FALSE(mem_store1->HasOneRef()); |
| - EXPECT_FALSE(mem_store2->HasOneRef()); |
| - EXPECT_FALSE(mem_store3->HasOneRef()); |
| + factory->TestCloseBackingStore(mem_store1.get()); |
| + factory->TestCloseBackingStore(mem_store3.get()); |
| - clear_factory(); |
| - EXPECT_FALSE(mem_store1->HasOneRef()); // mem_store1 and 2 |
| - EXPECT_FALSE(mem_store2->HasOneRef()); // mem_store1 and 2 |
| - EXPECT_TRUE(mem_store3->HasOneRef()); |
| + EXPECT_FALSE(mem_store1->HasOneRef()); |
| + EXPECT_FALSE(mem_store2->HasOneRef()); |
| + EXPECT_FALSE(mem_store3->HasOneRef()); |
| - mem_store2 = nullptr; |
| - EXPECT_TRUE(mem_store1->HasOneRef()); |
| + factory = nullptr; |
| + EXPECT_FALSE(mem_store1->HasOneRef()); // mem_store1 and 2 |
| + EXPECT_FALSE(mem_store2->HasOneRef()); // mem_store1 and 2 |
| + EXPECT_TRUE(mem_store3->HasOneRef()); |
| + |
| + mem_store2 = nullptr; |
| + EXPECT_TRUE(mem_store1->HasOneRef()); |
| + }, |
| + base::Unretained(context()))); |
| + |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| TEST_F(IndexedDBFactoryTest, RejectLongOrigins) { |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| - const base::FilePath base_path = temp_directory.GetPath(); |
| - |
| - int limit = base::GetMaximumPathComponentLength(base_path); |
| - EXPECT_GT(limit, 0); |
| - |
| - std::string origin(limit + 1, 'x'); |
| - Origin too_long_origin(GURL("http://" + origin + ":81/")); |
| - scoped_refptr<IndexedDBBackingStore> diskStore1 = |
| - factory()->TestOpenBackingStore(too_long_origin, base_path); |
| - EXPECT_FALSE(diskStore1.get()); |
| - |
| - Origin ok_origin(GURL("http://someorigin.com:82/")); |
| - scoped_refptr<IndexedDBBackingStore> diskStore2 = |
| - factory()->TestOpenBackingStore(ok_origin, base_path); |
| - EXPECT_TRUE(diskStore2.get()); |
| - // We need a manual close or Windows can't delete the temp directory. |
| - factory()->TestCloseBackingStore(diskStore2.get()); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context) { |
| + base::FilePath temp_dir = context->data_path().DirName(); |
| + int limit = base::GetMaximumPathComponentLength(temp_dir); |
| + EXPECT_GT(limit, 0); |
| + |
| + scoped_refptr<MockIDBFactory> factory = |
| + base::MakeRefCounted<MockIDBFactory>(context); |
| + |
| + std::string origin(limit + 1, 'x'); |
| + Origin too_long_origin(GURL("http://" + origin + ":81/")); |
| + scoped_refptr<IndexedDBBackingStore> diskStore1 = |
| + factory->TestOpenBackingStore(too_long_origin, |
| + context->data_path()); |
| + EXPECT_FALSE(diskStore1.get()); |
| + |
| + Origin ok_origin(GURL("http://someorigin.com:82/")); |
| + scoped_refptr<IndexedDBBackingStore> diskStore2 = |
| + factory->TestOpenBackingStore(ok_origin, context->data_path()); |
| + EXPECT_TRUE(diskStore2.get()); |
| + // We need a manual close or Windows can't delete the temp |
| + // directory. |
| + factory->TestCloseBackingStore(diskStore2.get()); |
| + }, |
| + base::Unretained(context()))); |
| + |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| class DiskFullFactory : public IndexedDBFactoryImpl { |
| @@ -238,7 +277,7 @@ class LookingForQuotaErrorMockCallbacks : public IndexedDBCallbacks { |
| : IndexedDBCallbacks(nullptr, |
| url::Origin(), |
| nullptr, |
| - base::ThreadTaskRunnerHandle::Get()), |
| + base::SequencedTaskRunnerHandle::Get()), |
| error_called_(false) {} |
| void OnError(const IndexedDBDatabaseError& error) override { |
| error_called_ = true; |
| @@ -254,177 +293,232 @@ class LookingForQuotaErrorMockCallbacks : public IndexedDBCallbacks { |
| }; |
| TEST_F(IndexedDBFactoryTest, QuotaErrorOnDiskFull) { |
| - const Origin origin(GURL("http://localhost:81")); |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| - |
| - scoped_refptr<DiskFullFactory> factory = new DiskFullFactory(context()); |
| scoped_refptr<LookingForQuotaErrorMockCallbacks> callbacks = |
| - new LookingForQuotaErrorMockCallbacks; |
| + base::MakeRefCounted<LookingForQuotaErrorMockCallbacks>(); |
| scoped_refptr<IndexedDBDatabaseCallbacks> dummy_database_callbacks = |
| - new IndexedDBDatabaseCallbacks(nullptr, nullptr); |
| - const base::string16 name(ASCIIToUTF16("name")); |
| - std::unique_ptr<IndexedDBPendingConnection> connection( |
| - base::MakeUnique<IndexedDBPendingConnection>( |
| - callbacks, dummy_database_callbacks, 0 /* child_process_id */, |
| - 2 /* transaction_id */, 1 /* version */)); |
| - factory->Open(name, std::move(connection), nullptr /* request_context */, |
| - origin, temp_directory.GetPath()); |
| - EXPECT_TRUE(callbacks->error_called()); |
| + base::MakeRefCounted<IndexedDBDatabaseCallbacks>(nullptr, nullptr); |
| + |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context, |
| + scoped_refptr<LookingForQuotaErrorMockCallbacks> callbacks, |
| + scoped_refptr<IndexedDBDatabaseCallbacks> |
| + dummy_database_callbacks) { |
| + |
| + const Origin origin(GURL("http://localhost:81")); |
| + scoped_refptr<DiskFullFactory> factory = |
| + base::MakeRefCounted<DiskFullFactory>(context); |
| + const base::string16 name(ASCIIToUTF16("name")); |
| + std::unique_ptr<IndexedDBPendingConnection> connection( |
| + base::MakeUnique<IndexedDBPendingConnection>( |
| + callbacks, dummy_database_callbacks, |
| + 0 /* child_process_id */, 2 /* transaction_id */, |
| + 1 /* version */)); |
| + factory->Open(name, std::move(connection), |
| + nullptr /* request_context */, origin, |
| + context->data_path()); |
| + EXPECT_TRUE(callbacks->error_called()); |
| + }, |
| + base::Unretained(context()), std::move(callbacks), |
| + std::move(dummy_database_callbacks))); |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| TEST_F(IndexedDBFactoryTest, BackingStoreReleasedOnForcedClose) { |
| - const Origin origin(GURL("http://localhost:81")); |
| - |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| - |
| - scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks()); |
| - scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks( |
| - new MockIndexedDBDatabaseCallbacks()); |
| - const int64_t transaction_id = 1; |
| - std::unique_ptr<IndexedDBPendingConnection> connection( |
| - base::MakeUnique<IndexedDBPendingConnection>( |
| - callbacks, db_callbacks, 0 /* child_process_id */, transaction_id, |
| - IndexedDBDatabaseMetadata::DEFAULT_VERSION)); |
| - factory()->Open(ASCIIToUTF16("db"), std::move(connection), |
| - nullptr /* request_context */, origin, |
| - temp_directory.GetPath()); |
| - |
| - EXPECT_TRUE(callbacks->connection()); |
| - |
| - EXPECT_TRUE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin)); |
| - |
| - callbacks->connection()->ForceClose(); |
| - |
| - EXPECT_FALSE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin)); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context, |
| + scoped_refptr<MockIndexedDBCallbacks> callbacks, |
| + scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks) { |
| + |
| + scoped_refptr<MockIDBFactory> factory = |
| + base::MakeRefCounted<MockIDBFactory>(context); |
| + |
| + const Origin origin(GURL("http://localhost:81")); |
| + const int64_t transaction_id = 1; |
| + std::unique_ptr<IndexedDBPendingConnection> connection( |
| + base::MakeUnique<IndexedDBPendingConnection>( |
| + callbacks, db_callbacks, 0 /* child_process_id */, |
| + transaction_id, |
| + IndexedDBDatabaseMetadata::DEFAULT_VERSION)); |
| + factory->Open(ASCIIToUTF16("db"), std::move(connection), |
| + nullptr /* request_context */, origin, |
| + context->data_path()); |
| + |
| + EXPECT_TRUE(callbacks->connection()); |
| + |
| + EXPECT_TRUE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_FALSE(factory->IsBackingStorePendingClose(origin)); |
| + |
| + callbacks->connection()->ForceClose(); |
| + |
| + EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_FALSE(factory->IsBackingStorePendingClose(origin)); |
| + }, |
| + base::Unretained(context()), |
| + base::MakeRefCounted<MockIndexedDBCallbacks>(), |
| + base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>())); |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| TEST_F(IndexedDBFactoryTest, BackingStoreReleaseDelayedOnClose) { |
| - const Origin origin(GURL("http://localhost:81")); |
| - |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| - |
| - scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks()); |
| - scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks( |
| - new MockIndexedDBDatabaseCallbacks()); |
| - const int64_t transaction_id = 1; |
| - std::unique_ptr<IndexedDBPendingConnection> connection( |
| - base::MakeUnique<IndexedDBPendingConnection>( |
| - callbacks, db_callbacks, 0 /* child_process_id */, transaction_id, |
| - IndexedDBDatabaseMetadata::DEFAULT_VERSION)); |
| - factory()->Open(ASCIIToUTF16("db"), std::move(connection), |
| - nullptr /* request_context */, origin, |
| - temp_directory.GetPath()); |
| - |
| - EXPECT_TRUE(callbacks->connection()); |
| - IndexedDBBackingStore* store = |
| - callbacks->connection()->database()->backing_store(); |
| - EXPECT_FALSE(store->HasOneRef()); // Factory and database. |
| - |
| - EXPECT_TRUE(factory()->IsBackingStoreOpen(origin)); |
| - callbacks->connection()->Close(); |
| - EXPECT_TRUE(store->HasOneRef()); // Factory. |
| - EXPECT_TRUE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin)); |
| - EXPECT_TRUE(store->close_timer()->IsRunning()); |
| - |
| - // Take a ref so it won't be destroyed out from under the test. |
| - scoped_refptr<IndexedDBBackingStore> store_ref = store; |
| - // Now simulate shutdown, which should stop the timer. |
| - factory()->ContextDestroyed(); |
| - EXPECT_TRUE(store->HasOneRef()); // Local. |
| - EXPECT_FALSE(store->close_timer()->IsRunning()); |
| - EXPECT_FALSE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin)); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context, |
| + scoped_refptr<MockIndexedDBCallbacks> callbacks, |
| + scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks) { |
| + |
| + scoped_refptr<MockIDBFactory> factory = |
| + base::MakeRefCounted<MockIDBFactory>(context); |
| + |
| + const Origin origin(GURL("http://localhost:81")); |
| + const int64_t transaction_id = 1; |
| + std::unique_ptr<IndexedDBPendingConnection> connection( |
| + base::MakeUnique<IndexedDBPendingConnection>( |
| + callbacks, db_callbacks, 0 /* child_process_id */, |
| + transaction_id, |
| + IndexedDBDatabaseMetadata::DEFAULT_VERSION)); |
| + factory->Open(ASCIIToUTF16("db"), std::move(connection), |
| + nullptr /* request_context */, origin, |
| + context->data_path()); |
| + |
| + EXPECT_TRUE(callbacks->connection()); |
| + IndexedDBBackingStore* store = |
| + callbacks->connection()->database()->backing_store(); |
| + EXPECT_FALSE(store->HasOneRef()); // Factory and database. |
| + |
| + EXPECT_TRUE(factory->IsBackingStoreOpen(origin)); |
| + callbacks->connection()->Close(); |
| + EXPECT_TRUE(store->HasOneRef()); // Factory. |
| + EXPECT_TRUE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_TRUE(factory->IsBackingStorePendingClose(origin)); |
| + EXPECT_TRUE(store->close_timer()->IsRunning()); |
| + |
| + // Take a ref so it won't be destroyed out from under the test. |
| + scoped_refptr<IndexedDBBackingStore> store_ref = store; |
| + // Now simulate shutdown, which should stop the timer. |
| + factory->ContextDestroyed(); |
| + EXPECT_TRUE(store->HasOneRef()); // Local. |
| + EXPECT_FALSE(store->close_timer()->IsRunning()); |
| + EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_FALSE(factory->IsBackingStorePendingClose(origin)); |
| + }, |
| + base::Unretained(context()), |
| + base::MakeRefCounted<MockIndexedDBCallbacks>(), |
| + base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>())); |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| TEST_F(IndexedDBFactoryTest, DeleteDatabaseClosesBackingStore) { |
| - const Origin origin(GURL("http://localhost:81")); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context, |
| + scoped_refptr<MockIndexedDBCallbacks> callbacks) { |
| + |
| + scoped_refptr<MockIDBFactory> factory = |
| + base::MakeRefCounted<MockIDBFactory>(context); |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| + const Origin origin(GURL("http://localhost:81")); |
| + EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); |
| - EXPECT_FALSE(factory()->IsBackingStoreOpen(origin)); |
| + factory->DeleteDatabase( |
| + ASCIIToUTF16("db"), nullptr /* request_context */, callbacks, |
| + origin, context->data_path(), false /* force_close */); |
| - const bool expect_connection = false; |
| - scoped_refptr<MockIndexedDBCallbacks> callbacks( |
| - new MockIndexedDBCallbacks(expect_connection)); |
| - factory()->DeleteDatabase(ASCIIToUTF16("db"), nullptr /* request_context */, |
| - callbacks, origin, temp_directory.GetPath(), |
| - false /* force_close */); |
| + EXPECT_TRUE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_TRUE(factory->IsBackingStorePendingClose(origin)); |
| - EXPECT_TRUE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin)); |
| + // Now simulate shutdown, which should stop the timer. |
| + factory->ContextDestroyed(); |
| - // Now simulate shutdown, which should stop the timer. |
| - factory()->ContextDestroyed(); |
| + EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_FALSE(factory->IsBackingStorePendingClose(origin)); |
| - EXPECT_FALSE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin)); |
| + }, |
| + base::Unretained(context()), |
| + base::MakeRefCounted<MockIndexedDBCallbacks>( |
| + false /*expect_connection*/))); |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| TEST_F(IndexedDBFactoryTest, GetDatabaseNamesClosesBackingStore) { |
| - const Origin origin(GURL("http://localhost:81")); |
| - |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| - |
| - EXPECT_FALSE(factory()->IsBackingStoreOpen(origin)); |
| - |
| - const bool expect_connection = false; |
| - scoped_refptr<MockIndexedDBCallbacks> callbacks( |
| - new MockIndexedDBCallbacks(expect_connection)); |
| - factory()->GetDatabaseNames(callbacks, origin, temp_directory.GetPath(), |
| - nullptr /* request_context */); |
| - |
| - EXPECT_TRUE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin)); |
| - |
| - // Now simulate shutdown, which should stop the timer. |
| - factory()->ContextDestroyed(); |
| - |
| - EXPECT_FALSE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin)); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context, |
| + scoped_refptr<MockIndexedDBCallbacks> callbacks) { |
| + scoped_refptr<MockIDBFactory> factory = |
| + base::MakeRefCounted<MockIDBFactory>(context); |
| + |
| + const Origin origin(GURL("http://localhost:81")); |
| + EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); |
| + |
| + factory->GetDatabaseNames(callbacks, origin, context->data_path(), |
| + nullptr /* request_context */); |
| + |
| + EXPECT_TRUE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_TRUE(factory->IsBackingStorePendingClose(origin)); |
| + |
| + // Now simulate shutdown, which should stop the timer. |
| + factory->ContextDestroyed(); |
| + |
| + EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_FALSE(factory->IsBackingStorePendingClose(origin)); |
| + |
| + }, |
| + base::Unretained(context()), |
| + base::MakeRefCounted<MockIndexedDBCallbacks>( |
| + false /*expect_connection*/))); |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| TEST_F(IndexedDBFactoryTest, ForceCloseReleasesBackingStore) { |
| - const Origin origin(GURL("http://localhost:81")); |
| - |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| - |
| - scoped_refptr<MockIndexedDBCallbacks> callbacks(new MockIndexedDBCallbacks()); |
| - scoped_refptr<MockIndexedDBDatabaseCallbacks> db_callbacks( |
| - new MockIndexedDBDatabaseCallbacks()); |
| - const int64_t transaction_id = 1; |
| - std::unique_ptr<IndexedDBPendingConnection> connection( |
| - base::MakeUnique<IndexedDBPendingConnection>( |
| - callbacks, db_callbacks, 0 /* child_process_id */, transaction_id, |
| - IndexedDBDatabaseMetadata::DEFAULT_VERSION)); |
| - factory()->Open(ASCIIToUTF16("db"), std::move(connection), |
| - nullptr /* request_context */, origin, |
| - temp_directory.GetPath()); |
| - |
| - EXPECT_TRUE(callbacks->connection()); |
| - EXPECT_TRUE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin)); |
| - |
| - callbacks->connection()->Close(); |
| - |
| - EXPECT_TRUE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_TRUE(factory()->IsBackingStorePendingClose(origin)); |
| - |
| - factory()->ForceClose(origin); |
| - |
| - EXPECT_FALSE(factory()->IsBackingStoreOpen(origin)); |
| - EXPECT_FALSE(factory()->IsBackingStorePendingClose(origin)); |
| - |
| - // Ensure it is safe if the store is not open. |
| - factory()->ForceClose(origin); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context, |
| + scoped_refptr<MockIndexedDBCallbacks> callbacks, |
| + scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks) { |
| + scoped_refptr<MockIDBFactory> factory = |
| + base::MakeRefCounted<MockIDBFactory>(context); |
| + |
| + const Origin origin(GURL("http://localhost:81")); |
| + const int64_t transaction_id = 1; |
| + std::unique_ptr<IndexedDBPendingConnection> connection( |
| + base::MakeUnique<IndexedDBPendingConnection>( |
| + callbacks, db_callbacks, 0 /* child_process_id */, |
| + transaction_id, |
| + IndexedDBDatabaseMetadata::DEFAULT_VERSION)); |
| + factory->Open(ASCIIToUTF16("db"), std::move(connection), |
| + nullptr /* request_context */, origin, |
| + context->data_path()); |
| + |
| + EXPECT_TRUE(callbacks->connection()); |
| + EXPECT_TRUE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_FALSE(factory->IsBackingStorePendingClose(origin)); |
| + |
| + callbacks->connection()->Close(); |
| + |
| + EXPECT_TRUE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_TRUE(factory->IsBackingStorePendingClose(origin)); |
| + |
| + factory->ForceClose(origin); |
| + |
| + EXPECT_FALSE(factory->IsBackingStoreOpen(origin)); |
| + EXPECT_FALSE(factory->IsBackingStorePendingClose(origin)); |
| + |
| + // Ensure it is safe if the store is not open. |
| + factory->ForceClose(origin); |
| + |
| + }, |
| + base::Unretained(context()), |
| + base::MakeRefCounted<MockIndexedDBCallbacks>(), |
| + base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>())); |
| + RunAllBlockingPoolTasksUntilIdle(); |
| } |
| class UpgradeNeededCallbacks : public MockIndexedDBCallbacks { |
| @@ -469,56 +563,93 @@ class ErrorCallbacks : public MockIndexedDBCallbacks { |
| TEST_F(IndexedDBFactoryTest, DatabaseFailedOpen) { |
| const Origin origin(GURL("http://localhost:81")); |
| - |
| - base::ScopedTempDir temp_directory; |
| - ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| - |
| const base::string16 db_name(ASCIIToUTF16("db")); |
| - const int64_t db_version = 2; |
| const int64_t transaction_id = 1; |
| - scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks( |
| - new MockIndexedDBDatabaseCallbacks()); |
| - |
| - // Open at version 2, then close. |
| - { |
| - scoped_refptr<UpgradeNeededCallbacks> callbacks( |
| - new UpgradeNeededCallbacks()); |
| - std::unique_ptr<IndexedDBPendingConnection> connection( |
| - base::MakeUnique<IndexedDBPendingConnection>( |
| - callbacks, db_callbacks, 0 /* child_process_id */, transaction_id, |
| - db_version)); |
| - factory()->Open(db_name, std::move(connection), |
| - nullptr /* request_context */, origin, |
| - temp_directory.GetPath()); |
| - EXPECT_TRUE(factory()->IsDatabaseOpen(origin, db_name)); |
| - |
| - // Pump the message loop so the upgrade transaction can run. |
| - base::RunLoop().RunUntilIdle(); |
| - EXPECT_TRUE(callbacks->connection()); |
| - callbacks->connection()->database()->Commit( |
| - callbacks->connection()->GetTransaction(transaction_id)); |
| - |
| - callbacks->connection()->Close(); |
| - EXPECT_FALSE(factory()->IsDatabaseOpen(origin, db_name)); |
| - } |
| - |
| - // Open at version < 2, which will fail; ensure factory doesn't retain |
| - // the database object. |
| - { |
| - scoped_refptr<ErrorCallbacks> callbacks(new ErrorCallbacks()); |
| - std::unique_ptr<IndexedDBPendingConnection> connection( |
| - base::MakeUnique<IndexedDBPendingConnection>( |
| - callbacks, db_callbacks, 0 /* child_process_id */, transaction_id, |
| - db_version - 1)); |
| - factory()->Open(db_name, std::move(connection), |
| - nullptr /* request_context */, origin, |
| - temp_directory.GetPath()); |
| - EXPECT_TRUE(callbacks->saw_error()); |
| - EXPECT_FALSE(factory()->IsDatabaseOpen(origin, db_name)); |
| - } |
| - // Terminate all pending-close timers. |
| - factory()->ForceClose(origin); |
| + // These objects are retained across posted tasks, so despite being used |
| + // exclusively on the IDB sequence. |
| + |
| + // Created and used on IDB sequence. |
| + scoped_refptr<MockIDBFactory> factory; |
| + // Created on IO thread, used on IDB sequence. |
| + scoped_refptr<UpgradeNeededCallbacks> upgrade_callbacks = |
| + base::MakeRefCounted<UpgradeNeededCallbacks>(); |
| + |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context, |
| + scoped_refptr<MockIDBFactory>* factory, |
| + scoped_refptr<UpgradeNeededCallbacks>* upgrade_callbacks, |
| + scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks, |
| + const base::string16& db_name, int64_t transaction_id, |
| + const Origin& origin) { |
| + |
| + *factory = base::MakeRefCounted<MockIDBFactory>(context); |
| + |
| + // Open at version 2. |
| + const int64_t db_version = 2; |
| + (*factory)->Open( |
| + db_name, |
| + base::MakeUnique<IndexedDBPendingConnection>( |
| + *upgrade_callbacks, db_callbacks, 0 /* child_process_id */, |
| + transaction_id, db_version), |
| + nullptr /* request_context */, origin, context->data_path()); |
| + |
| + EXPECT_TRUE((*factory)->IsDatabaseOpen(origin, db_name)); |
| + }, |
| + base::Unretained(context()), base::Unretained(&factory), |
| + base::Unretained(&upgrade_callbacks), |
| + base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>(), db_name, |
| + transaction_id, origin)); |
| + |
| + // Pump the message loop so the upgrade transaction can run. |
| + RunAllBlockingPoolTasksUntilIdle(); |
| + |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context, |
| + scoped_refptr<MockIDBFactory> factory, |
| + scoped_refptr<UpgradeNeededCallbacks> upgrade_callbacks, |
| + scoped_refptr<ErrorCallbacks> failed_open_callbacks, |
| + scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks, |
| + const base::string16& db_name, int64_t transaction_id, |
| + const Origin& origin) { |
| + // Close the connection. |
| + { |
| + EXPECT_TRUE(upgrade_callbacks->connection()); |
| + upgrade_callbacks->connection()->database()->Commit( |
| + upgrade_callbacks->connection()->GetTransaction( |
| + transaction_id)); |
| + upgrade_callbacks->connection()->Close(); |
| + EXPECT_FALSE(factory->IsDatabaseOpen(origin, db_name)); |
| + } |
| + |
| + // Open at version < 2, which will fail; ensure factory doesn't |
| + // retain the database object. |
| + { |
| + const int64_t db_version = 1; |
| + std::unique_ptr<IndexedDBPendingConnection> connection( |
| + base::MakeUnique<IndexedDBPendingConnection>( |
| + failed_open_callbacks, db_callbacks, |
| + 0 /* child_process_id */, transaction_id, db_version)); |
| + factory->Open(db_name, std::move(connection), |
| + nullptr /* request_context */, origin, |
| + context->data_path()); |
| + EXPECT_TRUE(failed_open_callbacks->saw_error()); |
| + EXPECT_FALSE(factory->IsDatabaseOpen(origin, db_name)); |
| + } |
| + |
| + // Terminate all pending-close timers. |
| + factory->ForceClose(origin); |
| + }, |
| + base::Unretained(context()), std::move(factory), |
| + std::move(upgrade_callbacks), base::MakeRefCounted<ErrorCallbacks>(), |
| + base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>(), db_name, |
| + transaction_id, origin)); |
| + |
| + RunAllBlockingPoolTasksUntilIdle(); |
|
dmurph
2017/07/07 18:28:59
I'd be a little more comfortable if you do somethi
jsbell
2017/07/07 21:35:44
Per gab@ (email thread to scheduler-dev@) the sche
|
| } |
| namespace { |
| @@ -552,22 +683,58 @@ TEST_F(IndexedDBFactoryTest, DataFormatVersion) { |
| const IndexedDBDataFormatVersion& version) { |
| base::AutoReset<IndexedDBDataFormatVersion> override_version( |
| &IndexedDBDataFormatVersion::GetMutableCurrentForTesting(), version); |
| - auto db_callbacks = base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>(); |
| - auto callbacks = base::MakeRefCounted<DataLossCallbacks>(); |
| + |
| + // These objects are retained across posted tasks, so despite being used |
| + // exclusively on the IDB sequence. |
| + |
| + // Created and used on IDB sequence. |
| + scoped_refptr<MockIDBFactory> factory; |
| + // Created on IO thread, used on IDB sequence. |
| + scoped_refptr<DataLossCallbacks> callbacks = |
| + base::MakeRefCounted<DataLossCallbacks>(); |
| + |
| const int64_t transaction_id = 1; |
| - factory()->Open(ASCIIToUTF16("test_db"), |
| - base::MakeUnique<IndexedDBPendingConnection>( |
| - callbacks, db_callbacks, 0 /* child_process_id */, |
| - transaction_id, 1 /* version */), |
| - nullptr /* request_context */, origin, |
| - context()->data_path()); |
| - base::RunLoop().RunUntilIdle(); |
| - auto* connection = callbacks->connection(); |
| - EXPECT_TRUE(connection); |
| - connection->database()->Commit(connection->GetTransaction(transaction_id)); |
| - connection->Close(); |
| - factory()->ForceClose(origin); |
| - return callbacks->data_loss(); |
| + blink::WebIDBDataLoss result; |
| + |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](IndexedDBContextImpl* context, |
| + scoped_refptr<MockIDBFactory>* factory, |
| + scoped_refptr<DataLossCallbacks>* callbacks, |
| + scoped_refptr<IndexedDBDatabaseCallbacks> db_callbacks, |
| + const Origin& origin, int64_t transaction_id) { |
| + *factory = base::MakeRefCounted<MockIDBFactory>(context); |
| + (*factory)->Open( |
| + ASCIIToUTF16("test_db"), |
| + base::MakeUnique<IndexedDBPendingConnection>( |
| + *callbacks, db_callbacks, 0 /* child_process_id */, |
| + transaction_id, 1 /* version */), |
| + nullptr /* request_context */, origin, context->data_path()); |
| + }, |
| + base::Unretained(context()), base::Unretained(&factory), |
| + base::Unretained(&callbacks), |
| + base::MakeRefCounted<MockIndexedDBDatabaseCallbacks>(), origin, |
| + transaction_id)); |
| + RunAllBlockingPoolTasksUntilIdle(); |
| + context()->TaskRunner()->PostTask( |
| + FROM_HERE, |
| + base::BindOnce( |
| + [](scoped_refptr<MockIDBFactory> factory, |
| + scoped_refptr<DataLossCallbacks> callbacks, const Origin& origin, |
| + int64_t transaction_id, blink::WebIDBDataLoss* result) { |
| + auto* connection = callbacks->connection(); |
| + EXPECT_TRUE(connection); |
| + connection->database()->Commit( |
| + connection->GetTransaction(transaction_id)); |
| + connection->Close(); |
| + factory->ForceClose(origin); |
| + *result = callbacks->data_loss(); |
| + }, |
| + std::move(factory), std::move(callbacks), origin, transaction_id, |
| + base::Unretained(&result))); |
| + RunAllBlockingPoolTasksUntilIdle(); |
| + return result; |
| }; |
| using blink::kWebIDBDataLossNone; |