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