Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Unified Diff: content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc

Issue 2784003002: [IndexedDB] Mojo testing harness. (Closed)
Patch Set: comments, removed thread flushing Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a73e010483e2c2093e5e66c9605207db1aeccded
--- /dev/null
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
@@ -0,0 +1,445 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/indexed_db/indexed_db_dispatcher_host.h"
+
+#include "base/barrier_closure.h"
+#include "base/callback.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/utf_offset_string_conversions.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread.h"
+#include "content/browser/browser_thread_impl.h"
+#include "content/browser/indexed_db/indexed_db_callbacks.h"
+#include "content/browser/indexed_db/indexed_db_context_impl.h"
+#include "content/browser/indexed_db/indexed_db_database_callbacks.h"
+#include "content/browser/indexed_db/indexed_db_factory.h"
+#include "content/browser/indexed_db/indexed_db_pending_connection.h"
+#include "content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h"
+#include "content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h"
+#include "content/common/indexed_db/indexed_db.mojom.h"
+#include "content/public/test/test_browser_context.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "mojo/public/cpp/bindings/strong_associated_binding.h"
+#include "net/url_request/url_request_test_util.h"
+#include "storage/browser/test/mock_quota_manager.h"
+#include "storage/browser/test/mock_quota_manager_proxy.h"
+#include "storage/browser/test/mock_special_storage_policy.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/modules/indexeddb/WebIDBDatabaseException.h"
+#include "url/origin.h"
+
+using indexed_db::mojom::Callbacks;
+using indexed_db::mojom::CallbacksAssociatedPtrInfo;
+using indexed_db::mojom::DatabaseAssociatedPtr;
+using indexed_db::mojom::DatabaseAssociatedPtrInfo;
+using indexed_db::mojom::DatabaseAssociatedRequest;
+using indexed_db::mojom::DatabaseCallbacks;
+using indexed_db::mojom::DatabaseCallbacksAssociatedPtrInfo;
+using indexed_db::mojom::Factory;
+using indexed_db::mojom::FactoryAssociatedPtr;
+using indexed_db::mojom::FactoryAssociatedRequest;
+using indexed_db::mojom::KeyPath;
+using indexed_db::mojom::Value;
+using indexed_db::mojom::ValuePtr;
+using mojo::StrongAssociatedBindingPtr;
+using testing::_;
+using testing::StrictMock;
+
+namespace content {
+namespace {
+
+ACTION_TEMPLATE(MoveArg,
+ HAS_1_TEMPLATE_PARAMS(int, k),
+ AND_1_VALUE_PARAMS(out)) {
+ *out = std::move(*::testing::get<k>(args));
+};
+
+ACTION_P(RunClosure, closure) {
+ closure.Run();
+}
+
+MATCHER_P(IsAssociatedInterfacePtrInfoValid,
+ tf,
+ std::string(negation ? "isn't" : "is") + " " +
+ std::string(tf ? "valid" : "invalid")) {
+ return tf == arg->is_valid();
+}
+
+MATCHER_P(MatchesIDBKey, key, "") {
+ return arg.Equals(key);
+}
+
+typedef void (base::Closure::*ClosureRunFcn)() const &;
+
+static const char kDatabaseName[] = "db";
+static const char kOrigin[] = "https://www.example.com";
+static const int kFakeProcessId = 2;
+static const int64_t kTemporaryQuota = 50 * 1024 * 1024;
+static const int64_t kPersistantQuota = 50 * 1024 * 1024;
+
+base::FilePath CreateAndReturnTempDir(base::ScopedTempDir* temp_dir) {
+ CHECK(temp_dir->CreateUniqueTempDir());
+ return temp_dir->GetPath();
+}
+
+// Stores data specific to a connection.
+struct TestDatabaseConnection {
+ TestDatabaseConnection(url::Origin origin,
+ base::string16 db_name,
+ int64_t version,
+ int64_t upgrade_txn_id)
+ : origin(std::move(origin)),
+ db_name(std::move(db_name)),
+ version(version),
+ upgrade_txn_id(upgrade_txn_id),
+ open_callbacks(new StrictMock<MockMojoIndexedDBCallbacks>()),
+ connection_callbacks(
+ new StrictMock<MockMojoIndexedDBDatabaseCallbacks>()){};
+ ~TestDatabaseConnection() {}
+
+ void Open(Factory* factory) {
+ factory->Open(open_callbacks->CreateInterfacePtrAndBind(),
+ connection_callbacks->CreateInterfacePtrAndBind(), origin,
+ db_name, version, upgrade_txn_id);
+ }
+
+ url::Origin origin;
+ base::string16 db_name;
+ int64_t version;
+ int64_t upgrade_txn_id;
+
+ DatabaseAssociatedPtr database;
+
+ std::unique_ptr<MockMojoIndexedDBCallbacks> open_callbacks;
+ std::unique_ptr<MockMojoIndexedDBDatabaseCallbacks> connection_callbacks;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestDatabaseConnection);
+};
+
+} // namespace
+
+class IndexedDBDispatcherHostTest : public testing::Test {
+ public:
+ IndexedDBDispatcherHostTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
+ idb_thread_(new base::Thread("IndexedDB")),
+ io_task_runner_(
+ BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)),
+ idb_task_runner_(idb_thread_->Start() ? idb_thread_->task_runner()
+ : nullptr),
+ request_context_getter_(
+ new net::TestURLRequestContextGetter(io_task_runner_)),
+ special_storage_policy_(new MockSpecialStoragePolicy()),
+ quota_manager_(new MockQuotaManager(false,
+ browser_context_.GetPath(),
+ io_task_runner_,
+ idb_task_runner_,
+ special_storage_policy_)),
+ quota_manager_proxy_(quota_manager_->proxy()),
+ context_impl_(
+ new IndexedDBContextImpl(CreateAndReturnTempDir(&temp_dir_),
+ special_storage_policy_.get(),
+ quota_manager_proxy_.get(),
+ idb_task_runner_.get())),
+ blob_storage_(ChromeBlobStorageContext::GetFor(&browser_context_)),
+ host_(new IndexedDBDispatcherHost(kFakeProcessId,
+ request_context_getter_.get(),
+ context_impl_.get(),
+ blob_storage_.get())) {
+ quota_manager_->SetQuota(GURL(kOrigin), storage::kStorageTypePersistent,
+ kTemporaryQuota);
+ quota_manager_->SetQuota(GURL(kOrigin), storage::kStorageTypeTemporary,
+ kPersistantQuota);
+ }
+
+ void TearDown() override {
Ken Rockot(use gerrit already) 2017/05/16 23:12:47 Thanks, this seems better! One more change here t
+ host_.reset();
+ // In order for idb_thread_.Stop() to not cause thread/taskrunner checking
+ // errors, the handles must be deref'd before we join threads. This ensures
+ // classes that require destruction on the idb thread can be destructed
+ // correctly before scheduling on the the idb thread task runner turns into
+ // a no-op after thread join.
+ blob_storage_ = nullptr;
+ context_impl_ = nullptr;
+ quota_manager_proxy_ = nullptr;
+ quota_manager_ = nullptr;
+ special_storage_policy_ = nullptr;
+ request_context_getter_ = nullptr;
+ // This will run the idb task runner until idle, then join the threads.
+ idb_thread_->Stop();
+ // File are leaked if this doesn't return true.
+ ASSERT_TRUE(temp_dir_.Delete());
+ }
+
+ void SetUp() override {
+ ASSERT_TRUE(idb_task_runner_);
+ FactoryAssociatedRequest request =
+ ::mojo::MakeIsolatedRequest(&idb_mojo_factory_);
+ host_->AddBinding(std::move(request));
+ }
+
+ protected:
+ TestBrowserThreadBundle thread_bundle_;
+ TestBrowserContext browser_context_;
+
+ base::ScopedTempDir temp_dir_;
+ std::unique_ptr<base::Thread> idb_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> idb_task_runner_;
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+ scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
+ scoped_refptr<MockQuotaManager> quota_manager_;
+ scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
+ scoped_refptr<IndexedDBContextImpl> context_impl_;
+ scoped_refptr<ChromeBlobStorageContext> blob_storage_;
+ std::unique_ptr<IndexedDBDispatcherHost, BrowserThread::DeleteOnIOThread>
+ host_;
+ FactoryAssociatedPtr idb_mojo_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherHostTest);
+};
+
+TEST_F(IndexedDBDispatcherHostTest, CloseConnectionBeforeUpgrade) {
+ const int64_t kDBVersion = 1;
+ const int64_t kTransactionId = 1;
+
+ TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
+ base::UTF8ToUTF16(kDatabaseName),
+ kDBVersion, kTransactionId);
+ IndexedDBDatabaseMetadata metadata;
+ DatabaseAssociatedPtrInfo database_info;
+ base::RunLoop loop;
+ EXPECT_CALL(
+ *connection.open_callbacks,
+ MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
+ IndexedDBDatabaseMetadata::NO_VERSION,
+ blink::kWebIDBDataLossNone, std::string(""), _))
+ .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
+ testing::SaveArg<4>(&metadata),
+ RunClosure(loop.QuitClosure())));
+
+ connection.Open(idb_mojo_factory_.get());
+ loop.Run();
+
+ EXPECT_TRUE(database_info.is_valid());
+ EXPECT_EQ(connection.version, metadata.version);
+ EXPECT_EQ(connection.db_name, metadata.name);
+}
+
+TEST_F(IndexedDBDispatcherHostTest, CloseAfterUpgrade) {
+ const int64_t kDBVersion = 1;
+ const int64_t kTransactionId = 1;
+ const int64_t kObjectStoreId = 10;
+ const char kObjectStoreName[] = "os";
+
+ // Open connection.
+ TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
+ base::UTF8ToUTF16(kDatabaseName),
+ kDBVersion, kTransactionId);
+
+ IndexedDBDatabaseMetadata metadata;
+ DatabaseAssociatedPtrInfo database_info;
+ {
+ base::RunLoop loop;
+ EXPECT_CALL(
+ *connection.open_callbacks,
+ MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
+ IndexedDBDatabaseMetadata::NO_VERSION,
+ blink::kWebIDBDataLossNone, std::string(""), _))
+ .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
+ testing::SaveArg<4>(&metadata),
+ RunClosure(loop.QuitClosure())));
+
+ // Queue open request message.
+ connection.Open(idb_mojo_factory_.get());
+ loop.Run();
+ }
+
+ ASSERT_TRUE(database_info.is_valid());
+ EXPECT_EQ(connection.version, metadata.version);
+ EXPECT_EQ(connection.db_name, metadata.name);
+
+ connection.database.Bind(std::move(database_info));
+
+ {
+ ::testing::InSequence dummy;
+ base::RunLoop loop;
+ base::Closure quit_closure = base::BarrierClosure(2, loop.QuitClosure());
+ EXPECT_CALL(*connection.connection_callbacks, Complete(kTransactionId))
+ .Times(1)
+ .WillOnce(RunClosure(quit_closure));
+ EXPECT_CALL(
+ *connection.open_callbacks,
+ MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
+ .Times(1)
+ .WillOnce(RunClosure(quit_closure));
+
+ ASSERT_TRUE(connection.database.is_bound());
+ connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
+ base::UTF8ToUTF16(kObjectStoreName),
+ content::IndexedDBKeyPath(), false);
+ connection.database->Commit(kTransactionId);
+ loop.Run();
+ }
+}
+
+TEST_F(IndexedDBDispatcherHostTest, OpenNewConnectionWhileUpgrading) {
+ const int64_t kDBVersion = 1;
+ const int64_t kTransactionId = 1;
+ const int64_t kObjectStoreId = 10;
+ const char kObjectStoreName[] = "os";
+
+ // Open connection 1, and expect the upgrade needed.
+ TestDatabaseConnection connection1(url::Origin(GURL(kOrigin)),
+ base::UTF8ToUTF16(kDatabaseName),
+ kDBVersion, kTransactionId);
+ DatabaseAssociatedPtrInfo database_info1;
+ {
+ base::RunLoop loop;
+ IndexedDBDatabaseMetadata metadata;
+ EXPECT_CALL(
+ *connection1.open_callbacks,
+ MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
+ IndexedDBDatabaseMetadata::NO_VERSION,
+ blink::kWebIDBDataLossNone, std::string(""), _))
+ .WillOnce(testing::DoAll(MoveArg<0>(&database_info1),
+ testing::SaveArg<4>(&metadata),
+ RunClosure(loop.QuitClosure())));
+
+ // Queue open request message.
+ connection1.Open(idb_mojo_factory_.get());
+ loop.Run();
+ }
+ connection1.database.Bind(std::move(database_info1));
+
+ // Open connection 2, but expect that we won't be called back.
+ DatabaseAssociatedPtrInfo database_info2;
+ IndexedDBDatabaseMetadata metadata2;
+ TestDatabaseConnection connection2(url::Origin(GURL(kOrigin)),
+ base::UTF8ToUTF16(kDatabaseName),
+ kDBVersion, 0);
+ connection2.Open(idb_mojo_factory_.get());
+
+ // Check that we're called in order and the second connection gets it's
+ // database after the first connection completes.
+ {
+ ::testing::InSequence dummy;
+ base::RunLoop loop;
+ base::Closure quit_closure = base::BarrierClosure(3, loop.QuitClosure());
+ EXPECT_CALL(*connection1.connection_callbacks, Complete(kTransactionId))
+ .Times(1)
+ .WillOnce(RunClosure(quit_closure));
+ EXPECT_CALL(
+ *connection1.open_callbacks,
+ MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
+ .Times(1)
+ .WillOnce(RunClosure(quit_closure));
+ EXPECT_CALL(
+ *connection2.open_callbacks,
+ MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(true), _))
+ .WillOnce(testing::DoAll(MoveArg<0>(&database_info2),
+ testing::SaveArg<1>(&metadata2),
+ RunClosure(quit_closure)));
+
+ // Create object store.
+ ASSERT_TRUE(connection1.database.is_bound());
+ connection1.database->CreateObjectStore(kTransactionId, kObjectStoreId,
+ base::UTF8ToUTF16(kObjectStoreName),
+ content::IndexedDBKeyPath(), false);
+ connection1.database->Commit(kTransactionId);
+ loop.Run();
+ }
+
+ EXPECT_TRUE(database_info2.is_valid());
+ EXPECT_EQ(connection2.version, metadata2.version);
+ EXPECT_EQ(connection2.db_name, metadata2.name);
+}
+
+TEST_F(IndexedDBDispatcherHostTest, PutWithInvalidBlob) {
+ const int64_t kDBVersion = 1;
+ const int64_t kTransactionId = 1;
+ const int64_t kObjectStoreId = 10;
+ const char kObjectStoreName[] = "os";
+
+ // Open connection.
+ TestDatabaseConnection connection(url::Origin(GURL(kOrigin)),
+ base::UTF8ToUTF16(kDatabaseName),
+ kDBVersion, kTransactionId);
+
+ IndexedDBDatabaseMetadata metadata;
+ DatabaseAssociatedPtrInfo database_info;
+ {
+ base::RunLoop loop;
+ EXPECT_CALL(
+ *connection.open_callbacks,
+ MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
+ IndexedDBDatabaseMetadata::NO_VERSION,
+ blink::kWebIDBDataLossNone, std::string(""), _))
+ .WillOnce(testing::DoAll(MoveArg<0>(&database_info),
+ testing::SaveArg<4>(&metadata),
+ RunClosure(loop.QuitClosure())));
+
+ // Queue open request message.
+ connection.Open(idb_mojo_factory_.get());
+ loop.Run();
+ }
+
+ ASSERT_TRUE(database_info.is_valid());
+ EXPECT_EQ(connection.version, metadata.version);
+ EXPECT_EQ(connection.db_name, metadata.name);
+
+ connection.database.Bind(std::move(database_info));
+
+ {
+ ::testing::InSequence dummy;
+ base::RunLoop loop;
+ base::Closure quit_closure = base::BarrierClosure(3, loop.QuitClosure());
+
+ auto put_callbacks =
+ base::MakeUnique<StrictMock<MockMojoIndexedDBCallbacks>>();
+
+ EXPECT_CALL(*put_callbacks,
+ Error(blink::kWebIDBDatabaseExceptionUnknownError, _))
+ .Times(1)
+ .WillOnce(RunClosure(quit_closure));
+
+ EXPECT_CALL(
+ *connection.connection_callbacks,
+ Abort(kTransactionId, blink::kWebIDBDatabaseExceptionUnknownError, _))
+ .Times(1)
+ .WillOnce(RunClosure(quit_closure));
+
+ EXPECT_CALL(*connection.open_callbacks,
+ Error(blink::kWebIDBDatabaseExceptionAbortError, _))
+ .Times(1)
+ .WillOnce(RunClosure(quit_closure));
+
+ ASSERT_TRUE(connection.database.is_bound());
+ connection.database->CreateObjectStore(kTransactionId, kObjectStoreId,
+ base::UTF8ToUTF16(kObjectStoreName),
+ content::IndexedDBKeyPath(), false);
+ // Call Put with an invalid blob.
+ std::vector<::indexed_db::mojom::BlobInfoPtr> blobs;
+ blobs.push_back(::indexed_db::mojom::BlobInfo::New(
+ "fakeUUID", base::string16(), 100, nullptr));
+ connection.database->Put(kTransactionId, kObjectStoreId,
+ Value::New("hello", std::move(blobs)),
+ content::IndexedDBKey(base::UTF8ToUTF16("hello")),
+ blink::kWebIDBPutModeAddOnly,
+ std::vector<content::IndexedDBIndexKeys>(),
+ put_callbacks->CreateInterfacePtrAndBind());
+ connection.database->Commit(kTransactionId);
+ loop.Run();
+ }
+}
+
+} // namespace content
« no previous file with comments | « content/browser/indexed_db/indexed_db_dispatcher_host.h ('k') | content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698