1 // Copyright 2017 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 "content/browser/indexed_db/indexed_db_dispatcher_host.h"
6
7 #include "base/barrier_closure.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/run_loop.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/task/post_task.h"
16 #include "base/test/bind_test_util.h"
17 #include "base/test/gmock_callback_support.h"
18 #include "base/test/mock_callback.h"
19 #include "base/test/task_environment.h"
20 #include "base/test/test_simple_task_runner.h"
21 #include "base/threading/thread.h"
22 #include "base/time/default_clock.h"
23 #include "build/build_config.h"
24 #include "content/browser/indexed_db/indexed_db_callbacks.h"
25 #include "content/browser/indexed_db/indexed_db_context_impl.h"
26 #include "content/browser/indexed_db/indexed_db_database_callbacks.h"
27 #include "content/browser/indexed_db/indexed_db_factory.h"
28 #include "content/browser/indexed_db/indexed_db_leveldb_env.h"
29 #include "content/browser/indexed_db/indexed_db_pending_connection.h"
30 #include "content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h"
31 #include "content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h"
32 #include "mojo/public/cpp/bindings/associated_remote.h"
33 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
34 #include "mojo/public/cpp/bindings/pending_remote.h"
35 #include "mojo/public/cpp/bindings/receiver.h"
36 #include "mojo/public/cpp/bindings/remote.h"
37 #include "storage/browser/test/mock_quota_manager.h"
38 #include "storage/browser/test/mock_quota_manager_proxy.h"
39 #include "storage/browser/test/mock_special_storage_policy.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
43 #include "url/origin.h"
44
45 using base::test::RunClosure;
46 using blink::IndexedDBDatabaseMetadata;
47 using blink::IndexedDBIndexKeys;
48 using blink::IndexedDBKey;
49 using blink::mojom::IDBValue;
50 using blink::mojom::IDBValuePtr;
51 using testing::_;
52 using testing::StrictMock;
53
54 namespace content {
55 namespace {
56
57 // TODO(crbug.com/889590): Replace with common converter.
ToOrigin(const std::string & url)58 url::Origin ToOrigin(const std::string& url) {
59 return url::Origin::Create(GURL(url));
60 }
61
ACTION_TEMPLATE(MoveArgPointee,HAS_1_TEMPLATE_PARAMS (int,k),AND_1_VALUE_PARAMS (out))62 ACTION_TEMPLATE(MoveArgPointee,
63 HAS_1_TEMPLATE_PARAMS(int, k),
64 AND_1_VALUE_PARAMS(out)) {
65 *out = std::move(*::testing::get<k>(args));
66 }
67
ACTION_P(QuitLoop,run_loop)68 ACTION_P(QuitLoop, run_loop) {
69 run_loop->Quit();
70 }
71
72 MATCHER_P(IsAssociatedInterfacePtrInfoValid,
73 tf,
74 std::string(negation ? "isn't" : "is") + " " +
75 std::string(tf ? "valid" : "invalid")) {
76 return tf == arg->is_valid();
77 }
78
79 MATCHER_P(MatchesIDBKey, key, "") {
80 return arg.Equals(key);
81 }
82
83 static const char kDatabaseName[] = "db";
84 static const char kOrigin[] = "https://www.example.com";
85
CreateAndReturnTempDir(base::ScopedTempDir * temp_dir)86 base::FilePath CreateAndReturnTempDir(base::ScopedTempDir* temp_dir) {
87 CHECK(temp_dir->CreateUniqueTempDir());
88 return temp_dir->GetPath();
89 }
90
91 // Stores data specific to a connection.
92 struct TestDatabaseConnection {
93 TestDatabaseConnection() = default;
94
TestDatabaseConnectioncontent::__anon66b7378e0111::TestDatabaseConnection95 TestDatabaseConnection(scoped_refptr<base::SequencedTaskRunner> task_runner,
96 url::Origin origin,
97 base::string16 db_name,
98 int64_t version,
99 int64_t upgrade_txn_id)
100 : task_runner(std::move(task_runner)),
101 origin(std::move(origin)),
102 db_name(std::move(db_name)),
103 version(version),
104 upgrade_txn_id(upgrade_txn_id),
105 open_callbacks(new StrictMock<MockMojoIndexedDBCallbacks>()),
106 connection_callbacks(
107 new StrictMock<MockMojoIndexedDBDatabaseCallbacks>()) {}
108 TestDatabaseConnection& operator=(TestDatabaseConnection&& other) noexcept =
109 default;
~TestDatabaseConnectioncontent::__anon66b7378e0111::TestDatabaseConnection110 ~TestDatabaseConnection() {}
111
Opencontent::__anon66b7378e0111::TestDatabaseConnection112 void Open(blink::mojom::IDBFactory* factory) {
113 factory->Open(
114 open_callbacks->CreateInterfacePtrAndBind(),
115 connection_callbacks->CreateInterfacePtrAndBind(), db_name, version,
116 version_change_transaction.BindNewEndpointAndPassReceiver(task_runner),
117 upgrade_txn_id);
118 }
119
120 scoped_refptr<base::SequencedTaskRunner> task_runner;
121 url::Origin origin;
122 base::string16 db_name;
123 int64_t version;
124 int64_t upgrade_txn_id;
125
126 mojo::AssociatedRemote<blink::mojom::IDBDatabase> database;
127 mojo::AssociatedRemote<blink::mojom::IDBTransaction>
128 version_change_transaction;
129
130 std::unique_ptr<MockMojoIndexedDBCallbacks> open_callbacks;
131 std::unique_ptr<MockMojoIndexedDBDatabaseCallbacks> connection_callbacks;
132
133 private:
134 DISALLOW_COPY_AND_ASSIGN(TestDatabaseConnection);
135 };
136
TestStatusCallback(base::OnceClosure callback,blink::mojom::IDBStatus * status_out,blink::mojom::IDBStatus status)137 void TestStatusCallback(base::OnceClosure callback,
138 blink::mojom::IDBStatus* status_out,
139 blink::mojom::IDBStatus status) {
140 *status_out = status;
141 std::move(callback).Run();
142 }
143
144 class TestIndexedDBObserver : public storage::mojom::IndexedDBObserver {
145 public:
TestIndexedDBObserver(mojo::PendingReceiver<storage::mojom::IndexedDBObserver> receiver)146 explicit TestIndexedDBObserver(
147 mojo::PendingReceiver<storage::mojom::IndexedDBObserver> receiver)
148 : receiver_(this, std::move(receiver)) {}
149
OnIndexedDBListChanged(const url::Origin & origin)150 void OnIndexedDBListChanged(const url::Origin& origin) override {
151 ++notify_list_changed_count;
152 }
153
OnIndexedDBContentChanged(const url::Origin & origin,const base::string16 & database_name,const base::string16 & object_store_name)154 void OnIndexedDBContentChanged(
155 const url::Origin& origin,
156 const base::string16& database_name,
157 const base::string16& object_store_name) override {
158 ++notify_content_changed_count;
159 }
160
161 int notify_list_changed_count = 0;
162 int notify_content_changed_count = 0;
163
164 private:
165 mojo::Receiver<storage::mojom::IndexedDBObserver> receiver_;
166 };
167
168 } // namespace
169
170 class IndexedDBDispatcherHostTest : public testing::Test {
171 public:
IndexedDBDispatcherHostTest()172 IndexedDBDispatcherHostTest()
173 : special_storage_policy_(
174 base::MakeRefCounted<storage::MockSpecialStoragePolicy>()),
175 quota_manager_(base::MakeRefCounted<storage::MockQuotaManager>(
176 false /*is_incognito*/,
177 CreateAndReturnTempDir(&temp_dir_),
178 task_environment_.GetMainThreadTaskRunner(),
179 special_storage_policy_)),
180 context_impl_(base::MakeRefCounted<IndexedDBContextImpl>(
181 temp_dir_.GetPath(),
182 special_storage_policy_,
183 quota_manager_->proxy(),
184 base::DefaultClock::GetInstance(),
185 mojo::NullRemote(),
186 mojo::NullRemote(),
187 task_environment_.GetMainThreadTaskRunner(),
188 nullptr)) {}
189
TearDown()190 void TearDown() override {
191 // Cycle the IndexedDBTaskQueue to remove all IDB tasks.
192 {
193 base::RunLoop loop;
194 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE, loop.QuitClosure());
195 loop.Run();
196 }
197 base::RunLoop loop;
198 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
199 base::BindLambdaForTesting([&]() {
200 idb_mojo_factory_.reset();
201 loop.Quit();
202 }));
203 loop.Run();
204 context_impl_ = nullptr;
205 quota_manager_ = nullptr;
206 task_environment_.RunUntilIdle();
207 // File are leaked if this doesn't return true.
208 ASSERT_TRUE(temp_dir_.Delete());
209 }
210
SetUp()211 void SetUp() override {
212 base::RunLoop loop;
213 context_impl_->IDBTaskRunner()->PostTask(
214 FROM_HERE, base::BindLambdaForTesting([&]() {
215 context_impl_->BindIndexedDB(
216 url::Origin::Create(GURL(kOrigin)),
217 idb_mojo_factory_.BindNewPipeAndPassReceiver());
218 loop.Quit();
219 }));
220 loop.Run();
221 }
222
223 protected:
224 base::test::TaskEnvironment task_environment_;
225 base::ScopedTempDir temp_dir_;
226 scoped_refptr<storage::MockSpecialStoragePolicy> special_storage_policy_;
227 scoped_refptr<storage::MockQuotaManager> quota_manager_;
228 scoped_refptr<IndexedDBContextImpl> context_impl_;
229 mojo::Remote<blink::mojom::IDBFactory> idb_mojo_factory_;
230
231 DISALLOW_COPY_AND_ASSIGN(IndexedDBDispatcherHostTest);
232 };
233
TEST_F(IndexedDBDispatcherHostTest,CloseConnectionBeforeUpgrade)234 TEST_F(IndexedDBDispatcherHostTest, CloseConnectionBeforeUpgrade) {
235 const int64_t kDBVersion = 1;
236 const int64_t kTransactionId = 1;
237 std::unique_ptr<TestDatabaseConnection> connection;
238 IndexedDBDatabaseMetadata metadata;
239 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database;
240
241 base::RunLoop loop;
242 context_impl_->IDBTaskRunner()->PostTask(
243 FROM_HERE, base::BindLambdaForTesting([&]() {
244 connection = std::make_unique<TestDatabaseConnection>(
245 context_impl_->IDBTaskRunner(), url::Origin::Create(GURL(kOrigin)),
246 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
247 EXPECT_CALL(*connection->open_callbacks,
248 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
249 IndexedDBDatabaseMetadata::NO_VERSION,
250 blink::mojom::IDBDataLoss::None,
251 std::string(""), _))
252 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database),
253 testing::SaveArg<4>(&metadata),
254 QuitLoop(&loop)));
255
256 connection->Open(idb_mojo_factory_.get());
257 }));
258 loop.Run();
259
260 EXPECT_TRUE(pending_database.is_valid());
261 EXPECT_EQ(connection->version, metadata.version);
262 EXPECT_EQ(connection->db_name, metadata.name);
263
264 base::RunLoop loop2;
265 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
266 base::BindLambdaForTesting([&]() {
267 connection.reset();
268 loop2.Quit();
269 }));
270 loop2.Run();
271 }
272
273 // Flaky on multiple platforms. http://crbug.com/1001265
TEST_F(IndexedDBDispatcherHostTest,DISABLED_CloseAfterUpgrade)274 TEST_F(IndexedDBDispatcherHostTest, DISABLED_CloseAfterUpgrade) {
275 const int64_t kDBVersion = 1;
276 const int64_t kTransactionId = 1;
277 const int64_t kObjectStoreId = 10;
278 const char kObjectStoreName[] = "os";
279 std::unique_ptr<TestDatabaseConnection> connection;
280 IndexedDBDatabaseMetadata metadata;
281 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database;
282
283 base::RunLoop loop;
284 context_impl_->IDBTaskRunner()->PostTask(
285 FROM_HERE, base::BindLambdaForTesting([&]() {
286 // Open connection.
287 connection = std::make_unique<TestDatabaseConnection>(
288 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
289 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
290
291 EXPECT_CALL(*connection->open_callbacks,
292 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
293 IndexedDBDatabaseMetadata::NO_VERSION,
294 blink::mojom::IDBDataLoss::None,
295 std::string(""), _))
296 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database),
297 testing::SaveArg<4>(&metadata),
298 QuitLoop(&loop)));
299
300 // Queue open request message.
301 connection->Open(idb_mojo_factory_.get());
302 }));
303 loop.Run();
304
305 ASSERT_TRUE(pending_database.is_valid());
306 EXPECT_EQ(connection->version, metadata.version);
307 EXPECT_EQ(connection->db_name, metadata.name);
308
309 base::RunLoop loop2;
310 base::RepeatingClosure quit_closure2 =
311 base::BarrierClosure(2, loop2.QuitClosure());
312 context_impl_->IDBTaskRunner()->PostTask(
313 FROM_HERE, base::BindLambdaForTesting([&]() {
314 ::testing::InSequence dummy;
315 EXPECT_CALL(*connection->connection_callbacks, Complete(kTransactionId))
316 .Times(1)
317 .WillOnce(RunClosure(quit_closure2));
318 EXPECT_CALL(
319 *connection->open_callbacks,
320 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
321 .Times(1)
322 .WillOnce(RunClosure(std::move(quit_closure2)));
323
324 connection->database.Bind(std::move(pending_database));
325 ASSERT_TRUE(connection->database.is_bound());
326 ASSERT_TRUE(connection->version_change_transaction.is_bound());
327 connection->version_change_transaction->CreateObjectStore(
328 kObjectStoreId, base::UTF8ToUTF16(kObjectStoreName),
329 blink::IndexedDBKeyPath(), false);
330 connection->version_change_transaction->Commit(0);
331 }));
332 loop2.Run();
333
334 base::RunLoop loop3;
335 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
336 base::BindLambdaForTesting([&]() {
337 connection.reset();
338 loop3.Quit();
339 }));
340 loop3.Run();
341 }
342
343 // TODO(https://crbug.com/995716) Test is flaky on multiple platforms.
TEST_F(IndexedDBDispatcherHostTest,DISABLED_OpenNewConnectionWhileUpgrading)344 TEST_F(IndexedDBDispatcherHostTest, DISABLED_OpenNewConnectionWhileUpgrading) {
345 const int64_t kDBVersion = 1;
346 const int64_t kTransactionId = 1;
347 const int64_t kObjectStoreId = 10;
348 const char kObjectStoreName[] = "os";
349 std::unique_ptr<TestDatabaseConnection> connection1;
350 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database1;
351 IndexedDBDatabaseMetadata metadata1;
352
353 base::RunLoop loop;
354 context_impl_->IDBTaskRunner()->PostTask(
355 FROM_HERE, base::BindLambdaForTesting([&]() {
356 // Open connection 1, and expect the upgrade needed.
357 connection1 = std::make_unique<TestDatabaseConnection>(
358 context_impl_->IDBTaskRunner(), url::Origin::Create(GURL(kOrigin)),
359 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
360
361 EXPECT_CALL(*connection1->open_callbacks,
362 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
363 IndexedDBDatabaseMetadata::NO_VERSION,
364 blink::mojom::IDBDataLoss::None,
365 std::string(""), _))
366 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database1),
367 testing::SaveArg<4>(&metadata1),
368 QuitLoop(&loop)));
369
370 // Queue open request message.
371 connection1->Open(idb_mojo_factory_.get());
372 }));
373 loop.Run();
374
375 std::unique_ptr<TestDatabaseConnection> connection2;
376 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database2;
377 IndexedDBDatabaseMetadata metadata2;
378
379 base::RunLoop loop2;
380 base::RepeatingClosure quit_closure2 =
381 base::BarrierClosure(3, loop2.QuitClosure());
382 context_impl_->IDBTaskRunner()->PostTask(
383 FROM_HERE, base::BindLambdaForTesting([&]() {
384 connection2 = std::make_unique<TestDatabaseConnection>(
385 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
386 base::UTF8ToUTF16(kDatabaseName), kDBVersion, 0);
387
388 // Check that we're called in order and the second connection gets it's
389 // database after the first connection completes.
390 ::testing::InSequence dummy;
391 EXPECT_CALL(*connection1->connection_callbacks,
392 Complete(kTransactionId))
393 .Times(1)
394 .WillOnce(RunClosure(quit_closure2));
395 EXPECT_CALL(
396 *connection1->open_callbacks,
397 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
398 .Times(1)
399 .WillOnce(RunClosure(quit_closure2));
400 EXPECT_CALL(
401 *connection2->open_callbacks,
402 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(true), _))
403 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database2),
404 testing::SaveArg<1>(&metadata2),
405 RunClosure(std::move(quit_closure2))));
406
407 connection1->database.Bind(std::move(pending_database1));
408 ASSERT_TRUE(connection1->database.is_bound());
409 ASSERT_TRUE(connection1->version_change_transaction.is_bound());
410
411 // Open connection 2, but expect that we won't be called back.
412 connection2->Open(idb_mojo_factory_.get());
413
414 // Create object store.
415 connection1->version_change_transaction->CreateObjectStore(
416 kObjectStoreId, base::UTF8ToUTF16(kObjectStoreName),
417 blink::IndexedDBKeyPath(), false);
418 connection1->version_change_transaction->Commit(0);
419 }));
420 loop2.Run();
421
422 EXPECT_TRUE(pending_database2.is_valid());
423 EXPECT_EQ(connection2->version, metadata2.version);
424 EXPECT_EQ(connection2->db_name, metadata2.name);
425
426 base::RunLoop loop3;
427 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
428 base::BindLambdaForTesting([&]() {
429 connection1.reset();
430 connection2.reset();
431 loop3.Quit();
432 }));
433 loop3.Run();
434 }
435
436 MATCHER_P(IsCallbackError, error_code, "") {
437 if (arg->is_error_result() &&
438 arg->get_error_result()->error_code == error_code)
439 return true;
440 return false;
441 }
442
443 // See https://crbug.com/989723 for more context, this test seems to flake.
TEST_F(IndexedDBDispatcherHostTest,DISABLED_PutWithInvalidBlob)444 TEST_F(IndexedDBDispatcherHostTest, DISABLED_PutWithInvalidBlob) {
445 const int64_t kDBVersion = 1;
446 const int64_t kTransactionId = 1;
447 const int64_t kObjectStoreId = 10;
448 const char kObjectStoreName[] = "os";
449 std::unique_ptr<TestDatabaseConnection> connection;
450 IndexedDBDatabaseMetadata metadata;
451 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database;
452
453 base::RunLoop loop;
454 context_impl_->IDBTaskRunner()->PostTask(
455 FROM_HERE, base::BindLambdaForTesting([&]() {
456 // Open connection.
457 connection = std::make_unique<TestDatabaseConnection>(
458 context_impl_->IDBTaskRunner(), url::Origin::Create(GURL(kOrigin)),
459 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
460
461 EXPECT_CALL(*connection->open_callbacks,
462 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
463 IndexedDBDatabaseMetadata::NO_VERSION,
464 blink::mojom::IDBDataLoss::None,
465 std::string(""), _))
466 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database),
467 testing::SaveArg<4>(&metadata),
468 QuitLoop(&loop)));
469
470 // Queue open request message.
471 connection->Open(idb_mojo_factory_.get());
472 }));
473 loop.Run();
474
475 ASSERT_TRUE(pending_database.is_valid());
476 EXPECT_EQ(connection->version, metadata.version);
477 EXPECT_EQ(connection->db_name, metadata.name);
478
479 base::MockCallback<blink::mojom::IDBTransaction::PutCallback> put_callback;
480
481 base::RunLoop loop2;
482 base::RepeatingClosure quit_closure2 =
483 base::BarrierClosure(3, loop2.QuitClosure());
484 context_impl_->IDBTaskRunner()->PostTask(
485 FROM_HERE, base::BindLambdaForTesting([&]() {
486 ::testing::InSequence dummy;
487
488 EXPECT_CALL(
489 put_callback,
490 Run(IsCallbackError(blink::mojom::IDBException::kUnknownError)))
491 .Times(1)
492 .WillOnce(RunClosure(quit_closure2));
493
494 EXPECT_CALL(
495 *connection->connection_callbacks,
496 Abort(kTransactionId, blink::mojom::IDBException::kUnknownError, _))
497 .Times(1)
498 .WillOnce(RunClosure(quit_closure2));
499
500 EXPECT_CALL(*connection->open_callbacks,
501 Error(blink::mojom::IDBException::kAbortError, _))
502 .Times(1)
503 .WillOnce(RunClosure(std::move(quit_closure2)));
504
505 connection->database.Bind(std::move(pending_database));
506 ASSERT_TRUE(connection->database.is_bound());
507 ASSERT_TRUE(connection->version_change_transaction.is_bound());
508 connection->version_change_transaction->CreateObjectStore(
509 kObjectStoreId, base::UTF8ToUTF16(kObjectStoreName),
510 blink::IndexedDBKeyPath(), false);
511 // Call Put with an invalid blob.
512 std::vector<blink::mojom::IDBExternalObjectPtr> external_objects;
513 mojo::PendingRemote<blink::mojom::Blob> blob;
514 // Ignore the result of InitWithNewPipeAndPassReceiver, to end up with
515 // an invalid blob.
516 ignore_result(blob.InitWithNewPipeAndPassReceiver());
517 external_objects.push_back(
518 blink::mojom::IDBExternalObject::NewBlobOrFile(
519 blink::mojom::IDBBlobInfo::New(std::move(blob), "fakeUUID",
520 base::string16(), 100,
521 nullptr)));
522
523 std::string value = "hello";
524 const char* value_data = value.data();
525 std::vector<uint8_t> value_vector(value_data,
526 value_data + value.length());
527
528 auto new_value = blink::mojom::IDBValue::New();
529 new_value->bits = std::move(value_vector);
530 new_value->external_objects = std::move(external_objects);
531
532 connection->version_change_transaction->Put(
533 kObjectStoreId, std::move(new_value),
534 IndexedDBKey(base::UTF8ToUTF16("hello")),
535 blink::mojom::IDBPutMode::AddOnly,
536 std::vector<IndexedDBIndexKeys>(), put_callback.Get());
537 connection->version_change_transaction->Commit(0);
538 }));
539 loop2.Run();
540
541 base::RunLoop loop3;
542 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
543 base::BindLambdaForTesting([&]() {
544 connection.reset();
545 loop3.Quit();
546 }));
547 loop3.Run();
548 }
549
550 // Disabled for crbug.com/945627.
TEST_F(IndexedDBDispatcherHostTest,DISABLED_CompactDatabaseWithConnection)551 TEST_F(IndexedDBDispatcherHostTest, DISABLED_CompactDatabaseWithConnection) {
552 const int64_t kDBVersion = 1;
553 const int64_t kTransactionId = 1;
554 std::unique_ptr<TestDatabaseConnection> connection;
555 IndexedDBDatabaseMetadata metadata;
556 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database;
557
558 base::RunLoop loop;
559 context_impl_->IDBTaskRunner()->PostTask(
560 FROM_HERE, base::BindLambdaForTesting([&]() {
561 // Open connection.
562 connection = std::make_unique<TestDatabaseConnection>(
563 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
564 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
565 EXPECT_CALL(*connection->open_callbacks,
566 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
567 IndexedDBDatabaseMetadata::NO_VERSION,
568 blink::mojom::IDBDataLoss::None,
569 std::string(), _))
570 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database),
571 testing::SaveArg<4>(&metadata),
572 QuitLoop(&loop)));
573
574 // Queue open request message.
575 connection->Open(idb_mojo_factory_.get());
576 }));
577 loop.Run();
578
579 EXPECT_TRUE(pending_database.is_valid());
580 EXPECT_EQ(connection->version, metadata.version);
581 EXPECT_EQ(connection->db_name, metadata.name);
582
583 blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
584
585 base::RunLoop loop2;
586 base::RepeatingClosure quit_closure2 =
587 base::BarrierClosure(3, loop2.QuitClosure());
588 context_impl_->IDBTaskRunner()->PostTask(
589 FROM_HERE, base::BindLambdaForTesting([&]() {
590 ::testing::InSequence dummy;
591
592 EXPECT_CALL(*connection->connection_callbacks, Complete(kTransactionId))
593 .Times(1)
594 .WillOnce(RunClosure(quit_closure2));
595 EXPECT_CALL(
596 *connection->open_callbacks,
597 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
598 .Times(1)
599 .WillOnce(RunClosure(quit_closure2));
600
601 connection->database.Bind(std::move(pending_database));
602 ASSERT_TRUE(connection->database.is_bound());
603 ASSERT_TRUE(connection->version_change_transaction.is_bound());
604
605 connection->version_change_transaction->Commit(0);
606 idb_mojo_factory_->AbortTransactionsAndCompactDatabase(base::BindOnce(
607 &TestStatusCallback, std::move(quit_closure2), &callback_result));
608 }));
609 loop2.Run();
610 EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
611
612 base::RunLoop loop3;
613 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
614 base::BindLambdaForTesting([&]() {
615 connection.reset();
616 loop3.Quit();
617 }));
618 loop3.Run();
619 }
620
TEST_F(IndexedDBDispatcherHostTest,CompactDatabaseWhileDoingTransaction)621 TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileDoingTransaction) {
622 const int64_t kDBVersion = 1;
623 const int64_t kTransactionId = 1;
624 const int64_t kObjectStoreId = 10;
625 const char kObjectStoreName[] = "os";
626 std::unique_ptr<TestDatabaseConnection> connection;
627 IndexedDBDatabaseMetadata metadata;
628 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database;
629
630 base::RunLoop loop;
631 context_impl_->IDBTaskRunner()->PostTask(
632 FROM_HERE, base::BindLambdaForTesting([&]() {
633 // Open connection.
634 connection = std::make_unique<TestDatabaseConnection>(
635 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
636 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
637 EXPECT_CALL(*connection->open_callbacks,
638 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
639 IndexedDBDatabaseMetadata::NO_VERSION,
640 blink::mojom::IDBDataLoss::None,
641 std::string(), _))
642 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database),
643 testing::SaveArg<4>(&metadata),
644 QuitLoop(&loop)));
645
646 // Queue open request message.
647 connection->Open(idb_mojo_factory_.get());
648 }));
649 loop.Run();
650
651 EXPECT_TRUE(pending_database.is_valid());
652 EXPECT_EQ(connection->version, metadata.version);
653 EXPECT_EQ(connection->db_name, metadata.name);
654
655 blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
656
657 base::RunLoop loop2;
658 base::RepeatingClosure quit_closure2 =
659 base::BarrierClosure(4, loop2.QuitClosure());
660 context_impl_->IDBTaskRunner()->PostTask(
661 FROM_HERE, base::BindLambdaForTesting([&]() {
662 ::testing::InSequence dummy;
663
664 EXPECT_CALL(
665 *connection->connection_callbacks,
666 Abort(kTransactionId, blink::mojom::IDBException::kUnknownError, _))
667 .Times(1)
668 .WillOnce(RunClosure(quit_closure2));
669 EXPECT_CALL(*connection->open_callbacks,
670 Error(blink::mojom::IDBException::kAbortError, _))
671 .Times(1)
672 .WillOnce(RunClosure(quit_closure2));
673 EXPECT_CALL(*connection->connection_callbacks, ForcedClose())
674 .Times(1)
675 .WillOnce(RunClosure(quit_closure2));
676
677 connection->database.Bind(std::move(pending_database));
678 ASSERT_TRUE(connection->database.is_bound());
679 ASSERT_TRUE(connection->version_change_transaction.is_bound());
680 connection->version_change_transaction->CreateObjectStore(
681 kObjectStoreId, base::UTF8ToUTF16(kObjectStoreName),
682 blink::IndexedDBKeyPath(), false);
683 idb_mojo_factory_->AbortTransactionsAndCompactDatabase(base::BindOnce(
684 &TestStatusCallback, std::move(quit_closure2), &callback_result));
685 }));
686 loop2.Run();
687
688 EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
689
690 base::RunLoop loop3;
691 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
692 base::BindLambdaForTesting([&]() {
693 connection.reset();
694 loop3.Quit();
695 }));
696 loop3.Run();
697 }
698
TEST_F(IndexedDBDispatcherHostTest,CompactDatabaseWhileUpgrading)699 TEST_F(IndexedDBDispatcherHostTest, CompactDatabaseWhileUpgrading) {
700 const int64_t kDBVersion = 1;
701 const int64_t kTransactionId = 1;
702 std::unique_ptr<TestDatabaseConnection> connection;
703 IndexedDBDatabaseMetadata metadata;
704 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database;
705
706 base::RunLoop loop;
707 context_impl_->IDBTaskRunner()->PostTask(
708 FROM_HERE, base::BindLambdaForTesting([&]() {
709 // Open connection.
710 connection = std::make_unique<TestDatabaseConnection>(
711 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
712 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
713 EXPECT_CALL(*connection->open_callbacks,
714 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
715 IndexedDBDatabaseMetadata::NO_VERSION,
716 blink::mojom::IDBDataLoss::None,
717 std::string(), _))
718 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database),
719 testing::SaveArg<4>(&metadata),
720 QuitLoop(&loop)));
721
722 // Queue open request message.
723 connection->Open(idb_mojo_factory_.get());
724 }));
725 loop.Run();
726
727 EXPECT_TRUE(pending_database.is_valid());
728 EXPECT_EQ(connection->version, metadata.version);
729 EXPECT_EQ(connection->db_name, metadata.name);
730
731 blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
732
733 base::RunLoop loop2;
734 base::RepeatingClosure quit_closure2 =
735 base::BarrierClosure(4, loop2.QuitClosure());
736 context_impl_->IDBTaskRunner()->PostTask(
737 FROM_HERE, base::BindLambdaForTesting([&]() {
738 ::testing::InSequence dummy;
739
740 EXPECT_CALL(
741 *connection->connection_callbacks,
742 Abort(kTransactionId, blink::mojom::IDBException::kUnknownError, _))
743 .Times(1)
744 .WillOnce(RunClosure(quit_closure2));
745 EXPECT_CALL(*connection->open_callbacks,
746 Error(blink::mojom::IDBException::kAbortError, _))
747 .Times(1)
748 .WillOnce(RunClosure(quit_closure2));
749 EXPECT_CALL(*connection->connection_callbacks, ForcedClose())
750 .Times(1)
751 .WillOnce(RunClosure(quit_closure2));
752
753 connection->database.Bind(std::move(pending_database));
754 ASSERT_TRUE(connection->database.is_bound());
755 ASSERT_TRUE(connection->version_change_transaction.is_bound());
756 idb_mojo_factory_->AbortTransactionsAndCompactDatabase(base::BindOnce(
757 &TestStatusCallback, std::move(quit_closure2), &callback_result));
758 }));
759 loop2.Run();
760
761 EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
762
763 base::RunLoop loop3;
764 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
765 base::BindLambdaForTesting([&]() {
766 connection.reset();
767 loop3.Quit();
768 }));
769 loop3.Run();
770 }
771
TEST_F(IndexedDBDispatcherHostTest,AbortTransactionsAfterCompletingTransaction)772 TEST_F(IndexedDBDispatcherHostTest,
773 AbortTransactionsAfterCompletingTransaction) {
774 const int64_t kDBVersion = 1;
775 const int64_t kTransactionId = 1;
776 std::unique_ptr<TestDatabaseConnection> connection;
777 IndexedDBDatabaseMetadata metadata;
778 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database;
779
780 base::RunLoop loop;
781 context_impl_->IDBTaskRunner()->PostTask(
782 FROM_HERE, base::BindLambdaForTesting([&]() {
783 // Open connection.
784 connection = std::make_unique<TestDatabaseConnection>(
785 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
786 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
787 {
788 EXPECT_CALL(*connection->open_callbacks,
789 MockedUpgradeNeeded(
790 IsAssociatedInterfacePtrInfoValid(true),
791 IndexedDBDatabaseMetadata::NO_VERSION,
792 blink::mojom::IDBDataLoss::None, std::string(), _))
793 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database),
794 testing::SaveArg<4>(&metadata),
795 QuitLoop(&loop)));
796
797 // Queue open request message.
798 connection->Open(idb_mojo_factory_.get());
799 }
800 }));
801 loop.Run();
802
803 EXPECT_TRUE(pending_database.is_valid());
804 EXPECT_EQ(connection->version, metadata.version);
805 EXPECT_EQ(connection->db_name, metadata.name);
806
807 blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
808
809 base::RunLoop loop2;
810 base::RepeatingClosure quit_closure2 =
811 base::BarrierClosure(4, loop2.QuitClosure());
812 context_impl_->IDBTaskRunner()->PostTask(
813 FROM_HERE, base::BindLambdaForTesting([&]() {
814 ::testing::InSequence dummy;
815 EXPECT_CALL(*connection->connection_callbacks, Complete(kTransactionId))
816 .Times(1)
817 .WillOnce(RunClosure(quit_closure2));
818 EXPECT_CALL(
819 *connection->open_callbacks,
820 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
821 .Times(1)
822 .WillOnce(RunClosure(quit_closure2));
823 EXPECT_CALL(*connection->connection_callbacks, ForcedClose())
824 .Times(1)
825 .WillOnce(RunClosure(quit_closure2));
826
827 connection->database.Bind(std::move(pending_database));
828 ASSERT_TRUE(connection->database.is_bound());
829 ASSERT_TRUE(connection->version_change_transaction.is_bound());
830 connection->version_change_transaction->Commit(0);
831 idb_mojo_factory_->AbortTransactionsForDatabase(base::BindOnce(
832 &TestStatusCallback, std::move(quit_closure2), &callback_result));
833 }));
834 loop2.Run();
835
836 EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
837
838 base::RunLoop loop3;
839 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
840 base::BindLambdaForTesting([&]() {
841 connection.reset();
842 loop3.Quit();
843 }));
844 loop3.Run();
845 }
846
TEST_F(IndexedDBDispatcherHostTest,AbortTransactionsWhileDoingTransaction)847 TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileDoingTransaction) {
848 const int64_t kDBVersion = 1;
849 const int64_t kTransactionId = 1;
850 const int64_t kObjectStoreId = 10;
851 const char kObjectStoreName[] = "os";
852 std::unique_ptr<TestDatabaseConnection> connection;
853 IndexedDBDatabaseMetadata metadata;
854 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database;
855
856 base::RunLoop loop;
857 context_impl_->IDBTaskRunner()->PostTask(
858 FROM_HERE, base::BindLambdaForTesting([&]() {
859 // Open connection.
860 connection = std::make_unique<TestDatabaseConnection>(
861 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
862 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
863
864 EXPECT_CALL(*connection->open_callbacks,
865 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
866 IndexedDBDatabaseMetadata::NO_VERSION,
867 blink::mojom::IDBDataLoss::None,
868 std::string(), _))
869 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database),
870 testing::SaveArg<4>(&metadata),
871 QuitLoop(&loop)));
872
873 // Queue open request message.
874 connection->Open(idb_mojo_factory_.get());
875 }));
876 loop.Run();
877
878 EXPECT_TRUE(pending_database.is_valid());
879 EXPECT_EQ(connection->version, metadata.version);
880 EXPECT_EQ(connection->db_name, metadata.name);
881
882 blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
883
884 base::RunLoop loop2;
885 base::RepeatingClosure quit_closure2 =
886 base::BarrierClosure(4, loop2.QuitClosure());
887 context_impl_->IDBTaskRunner()->PostTask(
888 FROM_HERE, base::BindLambdaForTesting([&]() {
889 ::testing::InSequence dummy;
890
891 EXPECT_CALL(
892 *connection->connection_callbacks,
893 Abort(kTransactionId, blink::mojom::IDBException::kUnknownError, _))
894 .Times(1)
895 .WillOnce(RunClosure(quit_closure2));
896 EXPECT_CALL(*connection->open_callbacks,
897 Error(blink::mojom::IDBException::kAbortError, _))
898 .Times(1)
899 .WillOnce(RunClosure(quit_closure2));
900 EXPECT_CALL(*connection->connection_callbacks, ForcedClose())
901 .Times(1)
902 .WillOnce(RunClosure(quit_closure2));
903
904 connection->database.Bind(std::move(pending_database));
905 ASSERT_TRUE(connection->database.is_bound());
906 ASSERT_TRUE(connection->version_change_transaction.is_bound());
907 connection->version_change_transaction->CreateObjectStore(
908 kObjectStoreId, base::UTF8ToUTF16(kObjectStoreName),
909 blink::IndexedDBKeyPath(), false);
910 idb_mojo_factory_->AbortTransactionsForDatabase(base::BindOnce(
911 &TestStatusCallback, std::move(quit_closure2), &callback_result));
912 }));
913 loop2.Run();
914
915 EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
916
917 base::RunLoop loop3;
918 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
919 base::BindLambdaForTesting([&]() {
920 connection.reset();
921 loop3.Quit();
922 }));
923 loop3.Run();
924 }
925
TEST_F(IndexedDBDispatcherHostTest,AbortTransactionsWhileUpgrading)926 TEST_F(IndexedDBDispatcherHostTest, AbortTransactionsWhileUpgrading) {
927 const int64_t kDBVersion = 1;
928 const int64_t kTransactionId = 1;
929 std::unique_ptr<TestDatabaseConnection> connection;
930 IndexedDBDatabaseMetadata metadata;
931 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database;
932
933 base::RunLoop loop;
934 context_impl_->IDBTaskRunner()->PostTask(
935 FROM_HERE, base::BindLambdaForTesting([&]() {
936 // Open connection.
937 connection = std::make_unique<TestDatabaseConnection>(
938 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
939 base::UTF8ToUTF16(kDatabaseName), kDBVersion, kTransactionId);
940
941 EXPECT_CALL(*connection->open_callbacks,
942 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
943 IndexedDBDatabaseMetadata::NO_VERSION,
944 blink::mojom::IDBDataLoss::None,
945 std::string(), _))
946 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database),
947 testing::SaveArg<4>(&metadata),
948 QuitLoop(&loop)));
949
950 // Queue open request message.
951 connection->Open(idb_mojo_factory_.get());
952 }));
953 loop.Run();
954
955 EXPECT_TRUE(pending_database.is_valid());
956 EXPECT_EQ(connection->version, metadata.version);
957 EXPECT_EQ(connection->db_name, metadata.name);
958
959 blink::mojom::IDBStatus callback_result = blink::mojom::IDBStatus::IOError;
960
961 base::RunLoop loop2;
962 base::RepeatingClosure quit_closure2 =
963 base::BarrierClosure(4, loop2.QuitClosure());
964 context_impl_->IDBTaskRunner()->PostTask(
965 FROM_HERE, base::BindLambdaForTesting([&]() {
966 ::testing::InSequence dummy;
967
968 EXPECT_CALL(
969 *connection->connection_callbacks,
970 Abort(kTransactionId, blink::mojom::IDBException::kUnknownError, _))
971 .Times(1)
972 .WillOnce(RunClosure(quit_closure2));
973 EXPECT_CALL(*connection->open_callbacks,
974 Error(blink::mojom::IDBException::kAbortError, _))
975 .Times(1)
976 .WillOnce(RunClosure(quit_closure2));
977 EXPECT_CALL(*connection->connection_callbacks, ForcedClose())
978 .Times(1)
979 .WillOnce(RunClosure(quit_closure2));
980
981 connection->database.Bind(std::move(pending_database));
982 ASSERT_TRUE(connection->database.is_bound());
983 ASSERT_TRUE(connection->version_change_transaction.is_bound());
984 idb_mojo_factory_->AbortTransactionsForDatabase(base::BindOnce(
985 &TestStatusCallback, std::move(quit_closure2), &callback_result));
986 }));
987 loop2.Run();
988
989 EXPECT_EQ(blink::mojom::IDBStatus::OK, callback_result);
990
991 base::RunLoop loop3;
992 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
993 base::BindLambdaForTesting([&]() {
994 connection.reset();
995 loop3.Quit();
996 }));
997 loop3.Run();
998 }
999
1000 // Flaky: crbug.com/772067
TEST_F(IndexedDBDispatcherHostTest,DISABLED_NotifyIndexedDBListChanged)1001 TEST_F(IndexedDBDispatcherHostTest, DISABLED_NotifyIndexedDBListChanged) {
1002 const int64_t kDBVersion1 = 1;
1003 const int64_t kDBVersion2 = 2;
1004 const int64_t kDBVersion3 = 3;
1005 const int64_t kTransactionId1 = 1;
1006 const int64_t kTransactionId2 = 2;
1007 const int64_t kTransactionId3 = 3;
1008 const int64_t kObjectStoreId = 10;
1009 const int64_t kIndexId = 100;
1010 const char kObjectStoreName[] = "os";
1011 const char kIndexName[] = "index";
1012
1013 mojo::PendingReceiver<storage::mojom::IndexedDBObserver> receiver;
1014 mojo::PendingRemote<storage::mojom::IndexedDBObserver> remote;
1015 TestIndexedDBObserver observer(remote.InitWithNewPipeAndPassReceiver());
1016 context_impl_->AddObserver(std::move(remote));
1017
1018 // Open connection 1.
1019 std::unique_ptr<TestDatabaseConnection> connection1;
1020
1021 IndexedDBDatabaseMetadata metadata1;
1022 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database1;
1023 EXPECT_EQ(0, observer.notify_list_changed_count);
1024 {
1025 base::RunLoop loop;
1026 context_impl_->IDBTaskRunner()->PostTask(
1027 FROM_HERE, base::BindLambdaForTesting([&]() {
1028 connection1 = std::make_unique<TestDatabaseConnection>(
1029 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
1030 base::UTF8ToUTF16(kDatabaseName), kDBVersion1, kTransactionId1);
1031
1032 EXPECT_CALL(*connection1->open_callbacks,
1033 MockedUpgradeNeeded(
1034 IsAssociatedInterfacePtrInfoValid(true),
1035 IndexedDBDatabaseMetadata::NO_VERSION,
1036 blink::mojom::IDBDataLoss::None, std::string(), _))
1037 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database1),
1038 testing::SaveArg<4>(&metadata1),
1039 QuitLoop(&loop)));
1040
1041 // Queue open request message.
1042 connection1->Open(idb_mojo_factory_.get());
1043 }));
1044 loop.Run();
1045 }
1046 EXPECT_TRUE(pending_database1.is_valid());
1047 EXPECT_EQ(connection1->version, metadata1.version);
1048 EXPECT_EQ(connection1->db_name, metadata1.name);
1049
1050 {
1051 ::testing::InSequence dummy;
1052 base::RunLoop loop;
1053 base::RepeatingClosure quit_closure =
1054 base::BarrierClosure(2, loop.QuitClosure());
1055 context_impl_->IDBTaskRunner()->PostTask(
1056 FROM_HERE, base::BindLambdaForTesting([&]() {
1057 // Create object store and index.
1058 connection1->database.Bind(std::move(pending_database1));
1059 ASSERT_TRUE(connection1->database.is_bound());
1060 ASSERT_TRUE(connection1->version_change_transaction.is_bound());
1061
1062 EXPECT_CALL(*connection1->connection_callbacks,
1063 Complete(kTransactionId1))
1064 .Times(1)
1065 .WillOnce(RunClosure(quit_closure));
1066 EXPECT_CALL(*connection1->open_callbacks,
1067 MockedSuccessDatabase(
1068 IsAssociatedInterfacePtrInfoValid(false), _))
1069 .Times(1)
1070 .WillOnce(RunClosure(std::move(quit_closure)));
1071
1072 ASSERT_TRUE(connection1->database.is_bound());
1073 connection1->version_change_transaction->CreateObjectStore(
1074 kObjectStoreId, base::UTF8ToUTF16(kObjectStoreName),
1075 blink::IndexedDBKeyPath(), false);
1076 connection1->database->CreateIndex(
1077 kTransactionId1, kObjectStoreId, kIndexId,
1078 base::UTF8ToUTF16(kIndexName), blink::IndexedDBKeyPath(), false,
1079 false);
1080 connection1->version_change_transaction->Commit(0);
1081 }));
1082 loop.Run();
1083 }
1084
1085 EXPECT_EQ(2, observer.notify_list_changed_count);
1086
1087 // Open connection 2.
1088 std::unique_ptr<TestDatabaseConnection> connection2;
1089
1090 IndexedDBDatabaseMetadata metadata2;
1091 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database2;
1092 {
1093 ::testing::InSequence dummy;
1094 base::RunLoop loop;
1095 base::RepeatingClosure quit_closure =
1096 base::BarrierClosure(2, loop.QuitClosure());
1097 context_impl_->IDBTaskRunner()->PostTask(
1098 FROM_HERE, base::BindLambdaForTesting([&]() {
1099 connection1->database->Close();
1100
1101 connection2 = std::make_unique<TestDatabaseConnection>(
1102 context_impl_->IDBTaskRunner(),
1103 url::Origin::Create(GURL(kOrigin)),
1104 base::UTF8ToUTF16(kDatabaseName), kDBVersion2, kTransactionId2);
1105
1106 EXPECT_CALL(*connection2->open_callbacks,
1107 MockedUpgradeNeeded(
1108 IsAssociatedInterfacePtrInfoValid(true), kDBVersion1,
1109 blink::mojom::IDBDataLoss::None, std::string(), _))
1110 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database2),
1111 testing::SaveArg<4>(&metadata2),
1112 QuitLoop(&loop)));
1113
1114 // Queue open request message.
1115 connection2->Open(idb_mojo_factory_.get());
1116 }));
1117 loop.Run();
1118 }
1119 EXPECT_TRUE(pending_database2.is_valid());
1120 EXPECT_EQ(connection2->version, metadata2.version);
1121 EXPECT_EQ(connection2->db_name, metadata2.name);
1122
1123 {
1124 ::testing::InSequence dummy;
1125 base::RunLoop loop;
1126 base::RepeatingClosure quit_closure =
1127 base::BarrierClosure(2, loop.QuitClosure());
1128 context_impl_->IDBTaskRunner()->PostTask(
1129 FROM_HERE, base::BindLambdaForTesting([&]() {
1130 // Delete index.
1131 connection2->database.Bind(std::move(pending_database2));
1132 ASSERT_TRUE(connection2->database.is_bound());
1133 ASSERT_TRUE(connection2->version_change_transaction.is_bound());
1134
1135 EXPECT_CALL(*connection2->connection_callbacks,
1136 Complete(kTransactionId2))
1137 .Times(1)
1138 .WillOnce(RunClosure(quit_closure));
1139 EXPECT_CALL(*connection2->open_callbacks,
1140 MockedSuccessDatabase(
1141 IsAssociatedInterfacePtrInfoValid(false), _))
1142 .Times(1)
1143 .WillOnce(RunClosure(std::move(quit_closure)));
1144
1145 ASSERT_TRUE(connection2->database.is_bound());
1146 connection2->database->DeleteIndex(kTransactionId2, kObjectStoreId,
1147 kIndexId);
1148 connection2->version_change_transaction->Commit(0);
1149 }));
1150 loop.Run();
1151 }
1152 EXPECT_EQ(3, observer.notify_list_changed_count);
1153
1154 // Open connection 3.
1155 std::unique_ptr<TestDatabaseConnection> connection3;
1156
1157 IndexedDBDatabaseMetadata metadata3;
1158 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database3;
1159 {
1160 ::testing::InSequence dummy;
1161 base::RunLoop loop;
1162 context_impl_->IDBTaskRunner()->PostTask(
1163 FROM_HERE, base::BindLambdaForTesting([&]() {
1164 connection2->database->Close();
1165 connection3 = std::make_unique<TestDatabaseConnection>(
1166 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
1167 base::UTF8ToUTF16(kDatabaseName), kDBVersion3, kTransactionId3);
1168
1169 EXPECT_CALL(*connection3->open_callbacks,
1170 MockedUpgradeNeeded(
1171 IsAssociatedInterfacePtrInfoValid(true), kDBVersion2,
1172 blink::mojom::IDBDataLoss::None, std::string(), _))
1173 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database3),
1174 testing::SaveArg<4>(&metadata3),
1175 QuitLoop(&loop)));
1176
1177 // Queue open request message.
1178 connection3->Open(idb_mojo_factory_.get());
1179 }));
1180 loop.Run();
1181 }
1182 EXPECT_TRUE(pending_database3.is_valid());
1183 EXPECT_EQ(connection3->version, metadata3.version);
1184 EXPECT_EQ(connection3->db_name, metadata3.name);
1185
1186 {
1187 ::testing::InSequence dummy;
1188 base::RunLoop loop;
1189 base::RepeatingClosure quit_closure =
1190 base::BarrierClosure(2, loop.QuitClosure());
1191 context_impl_->IDBTaskRunner()->PostTask(
1192 FROM_HERE, base::BindLambdaForTesting([&]() {
1193 // Delete object store.
1194 connection3->database.Bind(std::move(pending_database3));
1195 ASSERT_TRUE(connection3->database.is_bound());
1196 ASSERT_TRUE(connection3->version_change_transaction.is_bound());
1197
1198 EXPECT_CALL(*connection3->connection_callbacks,
1199 Complete(kTransactionId3))
1200 .Times(1)
1201 .WillOnce(RunClosure(quit_closure));
1202 EXPECT_CALL(*connection3->open_callbacks,
1203 MockedSuccessDatabase(
1204 IsAssociatedInterfacePtrInfoValid(false), _))
1205 .Times(1)
1206 .WillOnce(RunClosure(std::move(quit_closure)));
1207
1208 ASSERT_TRUE(connection3->database.is_bound());
1209 connection3->version_change_transaction->DeleteObjectStore(
1210 kObjectStoreId);
1211 connection3->version_change_transaction->Commit(0);
1212 }));
1213 loop.Run();
1214 }
1215 EXPECT_EQ(4, observer.notify_list_changed_count);
1216
1217 {
1218 base::RunLoop loop;
1219 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
1220 base::BindLambdaForTesting([&]() {
1221 connection1.reset();
1222 connection2.reset();
1223 connection3.reset();
1224 loop.Quit();
1225 }));
1226 loop.Run();
1227 }
1228 }
1229
1230 MATCHER(IsSuccessKey, "") {
1231 return arg->is_key();
1232 }
1233
1234 // The test is flaky. See https://crbug.com/879213
TEST_F(IndexedDBDispatcherHostTest,DISABLED_NotifyIndexedDBContentChanged)1235 TEST_F(IndexedDBDispatcherHostTest, DISABLED_NotifyIndexedDBContentChanged) {
1236 const int64_t kDBVersion1 = 1;
1237 const int64_t kDBVersion2 = 2;
1238 const int64_t kTransactionId1 = 1;
1239 const int64_t kTransactionId2 = 2;
1240 const int64_t kObjectStoreId = 10;
1241 const char kObjectStoreName[] = "os";
1242
1243 mojo::PendingReceiver<storage::mojom::IndexedDBObserver> receiver;
1244 mojo::PendingRemote<storage::mojom::IndexedDBObserver> remote;
1245 TestIndexedDBObserver observer(remote.InitWithNewPipeAndPassReceiver());
1246 context_impl_->AddObserver(std::move(remote));
1247 EXPECT_EQ(0, observer.notify_list_changed_count);
1248 EXPECT_EQ(0, observer.notify_content_changed_count);
1249
1250 std::unique_ptr<TestDatabaseConnection> connection1;
1251 IndexedDBDatabaseMetadata metadata1;
1252 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database1;
1253
1254 base::RunLoop loop;
1255 context_impl_->IDBTaskRunner()->PostTask(
1256 FROM_HERE, base::BindLambdaForTesting([&]() {
1257 // Open connection 1.
1258 connection1 = std::make_unique<TestDatabaseConnection>(
1259 context_impl_->IDBTaskRunner(), url::Origin::Create(GURL(kOrigin)),
1260 base::UTF8ToUTF16(kDatabaseName), kDBVersion1, kTransactionId1);
1261
1262 EXPECT_CALL(*connection1->open_callbacks,
1263 MockedUpgradeNeeded(IsAssociatedInterfacePtrInfoValid(true),
1264 IndexedDBDatabaseMetadata::NO_VERSION,
1265 blink::mojom::IDBDataLoss::None,
1266 std::string(), _))
1267 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database1),
1268 testing::SaveArg<4>(&metadata1),
1269 QuitLoop(&loop)));
1270
1271 // Queue open request message.
1272 connection1->Open(idb_mojo_factory_.get());
1273 }));
1274 loop.Run();
1275
1276 EXPECT_TRUE(pending_database1.is_valid());
1277 EXPECT_EQ(connection1->version, metadata1.version);
1278 EXPECT_EQ(connection1->db_name, metadata1.name);
1279
1280 base::MockCallback<blink::mojom::IDBTransaction::PutCallback> put_callback;
1281
1282 // Add object store entry.
1283 base::RunLoop loop2;
1284 base::RepeatingClosure quit_closure2 =
1285 base::BarrierClosure(3, loop2.QuitClosure());
1286 context_impl_->IDBTaskRunner()->PostTask(
1287 FROM_HERE, base::BindLambdaForTesting([&]() {
1288 ::testing::InSequence dummy;
1289
1290 EXPECT_CALL(put_callback, Run(IsSuccessKey()))
1291 .Times(1)
1292 .WillOnce(RunClosure(quit_closure2));
1293 EXPECT_CALL(*connection1->connection_callbacks,
1294 Complete(kTransactionId1))
1295 .Times(1)
1296 .WillOnce(RunClosure(quit_closure2));
1297 EXPECT_CALL(
1298 *connection1->open_callbacks,
1299 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
1300 .Times(1)
1301 .WillOnce(RunClosure(std::move(quit_closure2)));
1302
1303 connection1->database.Bind(std::move(pending_database1));
1304 ASSERT_TRUE(connection1->database.is_bound());
1305 ASSERT_TRUE(connection1->version_change_transaction.is_bound());
1306 connection1->version_change_transaction->CreateObjectStore(
1307 kObjectStoreId, base::UTF8ToUTF16(kObjectStoreName),
1308 blink::IndexedDBKeyPath(), false);
1309
1310 std::string value = "value";
1311 const char* value_data = value.data();
1312 std::vector<uint8_t> value_vector(value_data,
1313 value_data + value.length());
1314
1315 auto new_value = blink::mojom::IDBValue::New();
1316 new_value->bits = std::move(value_vector);
1317
1318 connection1->version_change_transaction->Put(
1319 kObjectStoreId, std::move(new_value),
1320 IndexedDBKey(base::UTF8ToUTF16("key")),
1321 blink::mojom::IDBPutMode::AddOnly,
1322 std::vector<IndexedDBIndexKeys>(), put_callback.Get());
1323 connection1->version_change_transaction->Commit(0);
1324 }));
1325 loop2.Run();
1326
1327 EXPECT_EQ(2, observer.notify_list_changed_count);
1328 EXPECT_EQ(1, observer.notify_content_changed_count);
1329
1330 base::RunLoop loop3;
1331 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
1332 base::BindLambdaForTesting([&]() {
1333 connection1->database->Close();
1334 connection1.reset();
1335 loop3.Quit();
1336 }));
1337 loop3.Run();
1338
1339 std::unique_ptr<TestDatabaseConnection> connection2;
1340 IndexedDBDatabaseMetadata metadata2;
1341 mojo::PendingAssociatedRemote<blink::mojom::IDBDatabase> pending_database2;
1342
1343 // Open connection 2.
1344 base::RunLoop loop4;
1345 context_impl_->IDBTaskRunner()->PostTask(
1346 FROM_HERE, base::BindLambdaForTesting([&]() {
1347 ::testing::InSequence dummy;
1348
1349 connection2 = std::make_unique<TestDatabaseConnection>(
1350 context_impl_->IDBTaskRunner(), ToOrigin(kOrigin),
1351 base::UTF8ToUTF16(kDatabaseName), kDBVersion2, kTransactionId2);
1352
1353 EXPECT_CALL(*connection2->open_callbacks,
1354 MockedUpgradeNeeded(
1355 IsAssociatedInterfacePtrInfoValid(true), kDBVersion1,
1356 blink::mojom::IDBDataLoss::None, std::string(), _))
1357 .WillOnce(testing::DoAll(MoveArgPointee<0>(&pending_database2),
1358 testing::SaveArg<4>(&metadata2),
1359 QuitLoop(&loop4)));
1360
1361 // Queue open request message.
1362 connection2->Open(idb_mojo_factory_.get());
1363 }));
1364 loop4.Run();
1365
1366 EXPECT_TRUE(pending_database2.is_valid());
1367 EXPECT_EQ(connection2->version, metadata2.version);
1368 EXPECT_EQ(connection2->db_name, metadata2.name);
1369
1370 std::unique_ptr<StrictMock<MockMojoIndexedDBCallbacks>> clear_callbacks;
1371
1372 // Clear object store.
1373 base::RunLoop loop5;
1374 base::RepeatingClosure quit_closure5 =
1375 base::BarrierClosure(3, loop5.QuitClosure());
1376 context_impl_->IDBTaskRunner()->PostTask(
1377 FROM_HERE, base::BindLambdaForTesting([&]() {
1378 ::testing::InSequence dummy;
1379
1380 clear_callbacks =
1381 std::make_unique<StrictMock<MockMojoIndexedDBCallbacks>>();
1382
1383 EXPECT_CALL(*clear_callbacks, Success())
1384 .Times(1)
1385 .WillOnce(RunClosure(quit_closure5));
1386 EXPECT_CALL(*connection2->connection_callbacks,
1387 Complete(kTransactionId2))
1388 .Times(1)
1389 .WillOnce(RunClosure(quit_closure5));
1390 EXPECT_CALL(
1391 *connection2->open_callbacks,
1392 MockedSuccessDatabase(IsAssociatedInterfacePtrInfoValid(false), _))
1393 .Times(1)
1394 .WillOnce(RunClosure(std::move(quit_closure5)));
1395
1396 connection2->database.Bind(std::move(pending_database2));
1397 ASSERT_TRUE(connection2->database.is_bound());
1398 ASSERT_TRUE(connection2->version_change_transaction.is_bound());
1399 connection2->database->Clear(
1400 kTransactionId2, kObjectStoreId,
1401 clear_callbacks->CreateInterfacePtrAndBind());
1402 connection2->version_change_transaction->Commit(0);
1403 }));
1404 loop5.Run();
1405
1406 // +2 list changed, one for the transaction, the other for the ~DatabaseImpl
1407 EXPECT_EQ(4, observer.notify_list_changed_count);
1408 EXPECT_EQ(2, observer.notify_content_changed_count);
1409
1410 base::RunLoop loop6;
1411 context_impl_->IDBTaskRunner()->PostTask(FROM_HERE,
1412 base::BindLambdaForTesting([&]() {
1413 clear_callbacks.reset();
1414 connection2.reset();
1415 loop6.Quit();
1416 }));
1417 loop6.Run();
1418 }
1419
1420 } // namespace content
1421