blob: 23d5523418b733a5ee6b3554a99f5b35089f415d [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2013 The Chromium Authors
[email protected]26811ea2013-06-04 07:33:302// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Evan Stade1a8d9d42024-09-10 19:37:195#include "content/browser/indexed_db/instance/database.h"
[email protected]26811ea2013-06-04 07:33:306
avib7348942015-12-25 20:57:107#include <stdint.h>
Evan Stade22f9c2642024-02-04 00:35:288
Arthur Sonzognid5ce01f72024-12-13 13:35:289#include <array>
Steve Becker4848af32024-10-29 22:57:1910#include <optional>
[email protected]4cfd02d2014-06-11 18:08:4011#include <set>
Jan Wilken Dörriead587c32021-03-11 14:09:2712#include <string>
dcheng36b6aec92015-12-26 06:16:3613#include <utility>
[email protected]4cfd02d2014-06-11 18:08:4014
[email protected]26811ea2013-06-04 07:33:3015#include "base/auto_reset.h"
Steve Becker4848af32024-10-29 22:57:1916#include "base/containers/span.h"
Ayu Ishiifa357142022-12-22 02:11:2717#include "base/files/scoped_temp_dir.h"
Avi Drissmanadac21992023-01-11 23:46:3918#include "base/functional/bind.h"
Keishi Hattori0e45c022021-11-27 09:25:5219#include "base/memory/raw_ptr.h"
Victor Costan158ce94c2021-02-25 19:57:2820#include "base/memory/scoped_refptr.h"
[email protected]12c337722014-05-22 19:42:4221#include "base/run_loop.h"
Steve Becker4848af32024-10-29 22:57:1922#include "base/sequence_checker.h"
23#include "base/strings/stringprintf.h"
Sean Maher52fa5a72022-11-14 15:53:2524#include "base/task/sequenced_task_runner.h"
Sean Maher5b9af51f2022-11-21 15:32:4725#include "base/task/single_thread_task_runner.h"
Evan Stade9dc36392024-10-29 13:10:3926#include "base/task/updateable_sequenced_task_runner.h"
Guido Urdanetaef4e91942020-11-09 15:06:2427#include "base/test/bind.h"
Evan Stadec24dbfe92023-11-01 20:04:3428#include "base/test/gmock_callback_support.h"
Chase Phillips5615c262019-07-29 21:42:3829#include "base/test/mock_callback.h"
Adrienne Walker94390682020-02-26 01:08:3030#include "base/test/task_environment.h"
Nathan Memmottca05bf752022-10-20 18:01:3431#include "components/services/storage/indexed_db/locks/partitioned_lock_manager.h"
Evan Stade9f5e401c2024-01-04 23:58:3532#include "components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom.h"
Ari Chivukulaa62fcaeb2022-04-26 18:33:5433#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
Daniel Murphya6d1c4f92019-01-16 18:41:1034#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
[email protected]12c337722014-05-22 19:42:4235#include "content/browser/indexed_db/indexed_db_value.h"
Evan Stade2ab4ae72025-04-18 17:58:4436#include "content/browser/indexed_db/instance/backing_store.h"
Evan Stade1a8d9d42024-09-10 19:37:1937#include "content/browser/indexed_db/instance/bucket_context.h"
38#include "content/browser/indexed_db/instance/connection.h"
39#include "content/browser/indexed_db/instance/cursor.h"
40#include "content/browser/indexed_db/instance/database_callbacks.h"
41#include "content/browser/indexed_db/instance/factory_client.h"
42#include "content/browser/indexed_db/instance/fake_transaction.h"
43#include "content/browser/indexed_db/instance/mock_factory_client.h"
Evan Stade822bdb42025-08-07 18:37:4144#include "content/browser/indexed_db/instance/mock_file_system_access_context.h"
Evan Stade1a8d9d42024-09-10 19:37:1945#include "content/browser/indexed_db/instance/transaction.h"
Evan Stadec24dbfe92023-11-01 20:04:3446#include "content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h"
Mingyu Lei0fe8df72022-12-16 06:44:4847#include "mojo/public/cpp/bindings/associated_remote.h"
Ayu Ishiifa357142022-12-22 02:11:2748#include "storage/browser/test/mock_quota_manager.h"
Evan Stadedfd32862023-09-12 21:51:5349#include "storage/browser/test/mock_quota_manager_proxy.h"
[email protected]d5516bfe2013-07-10 01:31:5650#include "testing/gtest/include/gtest/gtest.h"
Ari Chivukula61873b7f2021-06-09 19:29:2351#include "third_party/blink/public/common/storage_key/storage_key.h"
[email protected]26811ea2013-06-04 07:33:3052
Chase Phillips33d161d62018-08-28 19:44:1253using blink::IndexedDBDatabaseMetadata;
Chase Phillips68ecf5512018-08-16 01:59:1354using blink::IndexedDBIndexKeys;
55using blink::IndexedDBKey;
Chase Phillips850b96f72018-08-24 19:44:1656using blink::IndexedDBKeyPath;
[email protected]32956122013-12-25 07:29:2457
Evan Stadecbb1e002024-09-13 20:06:5758namespace content::indexed_db {
[email protected]26811ea2013-06-04 07:33:3059
Steve Becker4848af32024-10-29 22:57:1960namespace {
61constexpr int64_t kTestObjectStoreId = 1001;
62constexpr int64_t kTestIndexId = 2002;
Mingyu Lei87210bc2025-04-17 09:35:5063constexpr char kTestForceCloseMessage[] =
64 "The database's connection is force-closed.";
Steve Becker4848af32024-10-29 22:57:1965
66// Contains a record's keys and value that tests use to populate the database.
67struct TestIDBRecord {
Evan Stade46c8dab2025-05-07 17:05:1468 TestIDBRecord(IndexedDBKey primary_key,
69 const IndexedDBValue& value,
70 std::optional<IndexedDBKey> index_key)
Evan Stadeca999b12025-05-09 19:09:1171 : primary_key(std::move(primary_key)),
72 value(value.Clone()),
73 index_key(std::move(index_key)) {}
Evan Stade46c8dab2025-05-07 17:05:1474
75 TestIDBRecord(const TestIDBRecord& other) {
Evan Stadeca999b12025-05-09 19:09:1176 primary_key = other.primary_key.Clone();
Evan Stade46c8dab2025-05-07 17:05:1477 value = other.value.Clone();
Evan Stadeca999b12025-05-09 19:09:1178 if (other.index_key) {
79 index_key = other.index_key->Clone();
80 }
Evan Stade46c8dab2025-05-07 17:05:1481 }
82
Steve Becker4848af32024-10-29 22:57:1983 IndexedDBKey primary_key;
84 IndexedDBValue value;
85 // Optional. Tests may skip index creation.
86 std::optional<IndexedDBKey> index_key;
87};
88
89// Contains the options used to create an object store. Initializes members
90// to reasonable defaults that tests may override.
91struct TestObjectStoreParameters {
92 int64_t object_store_id = 0;
93 std::u16string name{u"store"};
94 IndexedDBKeyPath key_path;
95 bool auto_increment = false;
96};
97
98// Contains the options used to create an index. Optional. Test setup skips
99// index creation when `index_id` is `kInvalidId`. Initializes members to
100// reasonable defaults that tests may override.
101struct TestIndexParameters {
102 int64_t index_id = blink::IndexedDBIndexMetadata::kInvalidId;
103 std::u16string name{u"index"};
104 bool unique = false;
105 bool multi_entry = false;
106 IndexedDBKeyPath key_path;
107 bool auto_increment = false;
108};
109
110// Describes how test setup should create and populate an object store and
111// optionally an index.
112struct TestDatabaseParameters {
113 TestObjectStoreParameters object_store_parameters;
114 TestIndexParameters index_parameters;
115 std::vector<TestIDBRecord> records;
116};
117
118// Contains the arguments needed to call `Database::GetAllOperation`.
119// Initializes members to reasonable defaults that tests may override.
120struct TestGetAllParameters {
121 blink::mojom::IDBGetAllResultType result_type =
122 blink::mojom::IDBGetAllResultType::Keys;
123
124 blink::IndexedDBKeyRange key_range;
125
126 int64_t max_count = std::numeric_limits<int64_t>::max();
127
128 blink::mojom::IDBCursorDirection direction =
129 blink::mojom::IDBCursorDirection::Next;
130};
131
132// `Database::GetAllOperation` streams record results to a sink. This fake
133// implementation enables test to wait for all the results and inspect them.
134class FakeGetAllResultSink final
135 : public blink::mojom::IDBDatabaseGetAllResultSink {
136 public:
137 FakeGetAllResultSink() = default;
138
139 ~FakeGetAllResultSink() final {
140 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
141 }
142
143 FakeGetAllResultSink(const FakeGetAllResultSink&) = delete;
144 FakeGetAllResultSink& operator=(const FakeGetAllResultSink&) = delete;
145
146 blink::mojom::IDBError* GetError() const {
147 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
148 CHECK(is_done_);
149 return error_.get();
150 }
151
152 const std::vector<blink::mojom::IDBRecordPtr>& GetResults() const {
153 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
154 CHECK(is_done_);
155 return records_;
156 }
157
158 void BindReceiver(
159 mojo::PendingAssociatedReceiver<blink::mojom::IDBDatabaseGetAllResultSink>
160 receiver) {
161 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
162 CHECK(!is_done_);
163 receiver_.Bind(std::move(receiver));
164 }
165
166 void WaitForResults() {
167 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
168 run_loop_.Run();
169 CHECK(is_done_);
170 }
171
172 private:
173 void ReceiveResults(std::vector<blink::mojom::IDBRecordPtr> records,
174 bool done) final {
175 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
176 CHECK(!is_done_);
177
178 if (records_.empty()) {
179 records_ = std::move(records);
180 } else {
181 records_.reserve(records_.size() + records.size());
182 for (auto& record : records) {
183 records_.emplace_back(std::move(record));
184 }
185 }
186
187 if (done) {
188 is_done_ = true;
189 run_loop_.Quit();
190 }
191 }
192
193 void OnError(blink::mojom::IDBErrorPtr error) final {
194 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
195 CHECK(!is_done_);
196
197 error_ = std::move(error);
198 is_done_ = true;
199 run_loop_.Quit();
200 }
201
202 SEQUENCE_CHECKER(sequence_checker_);
203
204 mojo::AssociatedReceiver<blink::mojom::IDBDatabaseGetAllResultSink> receiver_{
205 this};
206
207 // Used to wait until all results have been received.
208 base::RunLoop run_loop_;
209 bool is_done_ = false;
210
211 // Store results and error for later inspection. Must not be accessed until
212 // `is_done_` is true.
213 std::vector<blink::mojom::IDBRecordPtr> records_;
214 blink::mojom::IDBErrorPtr error_;
215};
216
217void ExpectEqualsIndexedDBKey(const IndexedDBKey& expected_primary_key,
218 const IndexedDBKey& actual_primary_key) {
219 ASSERT_EQ(actual_primary_key.IsValid(), expected_primary_key.IsValid());
220
221 if (expected_primary_key.IsValid()) {
222 EXPECT_TRUE(actual_primary_key.Equals(expected_primary_key))
223 << "Expected " << expected_primary_key.DebugString() << " but got "
224 << actual_primary_key.DebugString();
225 }
226}
227
228void ExpectEqualsOptionalIndexedDBKey(
229 const std::optional<IndexedDBKey>& expected_primary_key,
230 const std::optional<IndexedDBKey>& actual_primary_key) {
231 ASSERT_EQ(actual_primary_key.has_value(), expected_primary_key.has_value());
232
233 if (expected_primary_key.has_value()) {
234 ASSERT_NO_FATAL_FAILURE(
235 ExpectEqualsIndexedDBKey(*expected_primary_key, *actual_primary_key));
236 }
237}
238
239void ExpectEqualsIDBReturnValuePtr(
240 const blink::mojom::IDBReturnValuePtr& expected_return_value,
241 const blink::mojom::IDBReturnValuePtr& actual_return_value) {
242 ASSERT_EQ(actual_return_value.is_null(), expected_return_value.is_null());
243
244 if (!expected_return_value.is_null()) {
245 // Verify the value bits.
246 ASSERT_EQ(actual_return_value->value.is_null(),
247 expected_return_value->value.is_null());
248
249 if (!expected_return_value->value.is_null()) {
250 EXPECT_EQ(actual_return_value->value->bits,
251 expected_return_value->value->bits);
252
253 // Verify the external objects.
254 EXPECT_EQ(actual_return_value->value->external_objects.size(),
255 expected_return_value->value->external_objects.size());
256 }
257
258 // Verify the return value primary key and key path.
259 ASSERT_NO_FATAL_FAILURE(ExpectEqualsIndexedDBKey(
260 actual_return_value->primary_key, expected_return_value->primary_key));
261
262 EXPECT_EQ(expected_return_value->key_path, actual_return_value->key_path);
263 }
264}
265
266// Creates a `IDBReturnValuePtr` with the given bits. `primary_key`,
267// `key_path` are optional, required only for object stores that generate keys.
268// `external_objects` is not set and remains empty.
269blink::mojom::IDBReturnValuePtr CreateIDBReturnValuePtr(
270 const std::string& bits,
Evan Stadeca999b12025-05-09 19:09:11271 const IndexedDBKey* primary_key = nullptr,
Steve Becker4848af32024-10-29 22:57:19272 IndexedDBKeyPath key_path = {}) {
273 blink::mojom::IDBReturnValuePtr result = blink::mojom::IDBReturnValue::New();
274 result->value = blink::mojom::IDBValue::New();
275 result->value->bits.assign(bits.begin(), bits.end());
Evan Stadeca999b12025-05-09 19:09:11276 if (primary_key) {
277 result->primary_key = primary_key->Clone();
278 }
Steve Becker4848af32024-10-29 22:57:19279 result->key_path = std::move(key_path);
280 return result;
281}
282
283} // namespace
284
Evan Stadecbb1e002024-09-13 20:06:57285class DatabaseTest : public ::testing::Test {
dmurph497e676f12017-04-25 20:29:57286 public:
Evan Stadecbb1e002024-09-13 20:06:57287 DatabaseTest() = default;
Daniel Murphya6d1c4f92019-01-16 18:41:10288
dmurph497e676f12017-04-25 20:29:57289 void SetUp() override {
Ayu Ishiifa357142022-12-22 02:11:27290 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
Ayu Ishiifa357142022-12-22 02:11:27291 quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>(
292 /*is_incognito=*/false, temp_dir_.GetPath(),
293 base::SingleThreadTaskRunner::GetCurrentDefault(),
294 /*special_storage_policy=*/nullptr);
Evan Stadea35e2722023-09-05 22:53:42295
Evan Stadedfd32862023-09-12 21:51:53296 quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>(
297 quota_manager_.get(),
298 base::SingleThreadTaskRunner::GetCurrentDefault().get());
299
Evan Stadecbb1e002024-09-13 20:06:57300 BucketContext::Delegate delegate;
301 delegate.on_ready_for_destruction =
302 base::BindOnce(&DatabaseTest::OnBucketContextReadyForDestruction,
303 weak_factory_.GetWeakPtr());
Evan Stadea35e2722023-09-05 22:53:42304
Evan Stade822bdb42025-08-07 18:37:41305 mojo::PendingRemote<storage::mojom::FileSystemAccessContext> fsa_context;
306 file_system_access_context_ =
307 std::make_unique<test::MockFileSystemAccessContext>();
308 file_system_access_context_->Clone(
309 fsa_context.InitWithNewPipeAndPassReceiver());
310
Evan Stadecbb1e002024-09-13 20:06:57311 bucket_context_ = std::make_unique<BucketContext>(
Evan Stade22f9c2642024-02-04 00:35:28312 storage::BucketInfo(), temp_dir_.GetPath(), std::move(delegate),
Evan Stade9dc36392024-10-29 13:10:39313 scoped_refptr<base::UpdateableSequencedTaskRunner>(),
Evan Stade21b63db2023-11-03 02:00:20314 quota_manager_proxy_,
Evan Stade6584a492023-09-25 21:02:30315 /*blob_storage_context=*/mojo::NullRemote(),
Evan Stade822bdb42025-08-07 18:37:41316 /*file_system_access_context=*/std::move(fsa_context));
Evan Stadea35e2722023-09-05 22:53:42317
Evan Stade22f9c2642024-02-04 00:35:28318 bucket_context_->InitBackingStoreIfNeeded(true);
Abhishek Shanthkumar88ce4902025-06-26 16:00:00319 db_ = bucket_context_->CreateAndAddDatabase(u"db");
Daniel Murphy4c0f9c12019-05-23 01:14:35320 }
321
Evan Stade0c0e6d652023-11-09 23:28:03322 void TearDown() override { db_ = nullptr; }
dmurph497e676f12017-04-25 20:29:57323
Evan Stade0c0e6d652023-11-09 23:28:03324 void OnBucketContextReadyForDestruction() { bucket_context_.reset(); }
325
326 void RunPostedTasks() {
327 base::RunLoop run_loop;
328 base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
329 FROM_HERE, run_loop.QuitClosure());
330 run_loop.Run();
331 }
Daniel Murphy7c750432019-08-20 01:39:47332
dmurph497e676f12017-04-25 20:29:57333 protected:
Evan Stade0c0e6d652023-11-09 23:28:03334 base::test::TaskEnvironment task_environment_;
335
Ayu Ishiifa357142022-12-22 02:11:27336 base::ScopedTempDir temp_dir_;
Evan Stadecbb1e002024-09-13 20:06:57337 std::unique_ptr<BucketContext> bucket_context_;
Evan Stade822bdb42025-08-07 18:37:41338 std::unique_ptr<test::MockFileSystemAccessContext>
339 file_system_access_context_;
Ayu Ishiifa357142022-12-22 02:11:27340 scoped_refptr<storage::MockQuotaManager> quota_manager_;
Evan Stadedfd32862023-09-12 21:51:53341 scoped_refptr<storage::MockQuotaManagerProxy> quota_manager_proxy_;
dmurph497e676f12017-04-25 20:29:57342
Evan Stade59872192024-02-08 16:57:48343 // As this is owned by `bucket_context_`, tests that cause the database to
Evan Stade0c0e6d652023-11-09 23:28:03344 // be destroyed must manually reset this to null to avoid triggering dangling
345 // pointer warnings.
Evan Stadecbb1e002024-09-13 20:06:57346 raw_ptr<Database> db_ = nullptr;
Evan Stade0c0e6d652023-11-09 23:28:03347
Evan Stadecbb1e002024-09-13 20:06:57348 base::WeakPtrFactory<DatabaseTest> weak_factory_{this};
reillyg627e7f72016-10-20 05:12:43349};
350
Evan Stadecbb1e002024-09-13 20:06:57351TEST_F(DatabaseTest, ConnectionLifecycle) {
352 MockMojoDatabaseCallbacks database_callbacks;
353 MockFactoryClient request1;
avib7348942015-12-25 20:57:10354 const int64_t transaction_id1 = 1;
Evan Stadecbb1e002024-09-13 20:06:57355 auto connection1 = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34356 std::make_unique<ThunkFactoryClient>(request1),
Evan Stadecbb1e002024-09-13 20:06:57357 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34358 database_callbacks.BindNewEndpointAndPassDedicatedRemote()),
Evan Stadef5433b82023-07-25 18:03:06359 transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION,
Guido Urdaneta16511382023-10-25 17:40:04360 mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35361 db_->ScheduleOpenConnection(std::move(connection1));
Daniel Murphy7c750432019-08-20 01:39:47362 RunPostedTasks();
[email protected]26811ea2013-06-04 07:33:30363
Evan Stadecbb1e002024-09-13 20:06:57364 MockMojoDatabaseCallbacks database_callbacks2;
365 MockFactoryClient request2;
avib7348942015-12-25 20:57:10366 const int64_t transaction_id2 = 2;
Evan Stadecbb1e002024-09-13 20:06:57367 auto connection2 = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34368 std::make_unique<ThunkFactoryClient>(request2),
Evan Stadecbb1e002024-09-13 20:06:57369 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34370 database_callbacks2.BindNewEndpointAndPassDedicatedRemote()),
Evan Stadef5433b82023-07-25 18:03:06371 transaction_id2, IndexedDBDatabaseMetadata::DEFAULT_VERSION,
Guido Urdaneta16511382023-10-25 17:40:04372 mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35373 db_->ScheduleOpenConnection(std::move(connection2));
Daniel Murphy7c750432019-08-20 01:39:47374 RunPostedTasks();
Evan Stade0c0e6d652023-11-09 23:28:03375 db_ = nullptr;
[email protected]26811ea2013-06-04 07:33:30376
Evan Stade833343922023-07-05 21:09:51377 EXPECT_TRUE(request1.connection());
Mingyu Lei87210bc2025-04-17 09:35:50378 request1.connection()->CloseAndReportForceClose(kTestForceCloseMessage);
Evan Stade833343922023-07-05 21:09:51379 EXPECT_FALSE(request1.connection()->IsConnected());
[email protected]26811ea2013-06-04 07:33:30380
Evan Stade833343922023-07-05 21:09:51381 EXPECT_TRUE(request2.connection());
Mingyu Lei87210bc2025-04-17 09:35:50382 request2.connection()->CloseAndReportForceClose(kTestForceCloseMessage);
Evan Stade833343922023-07-05 21:09:51383 EXPECT_FALSE(request2.connection()->IsConnected());
[email protected]1c0f12272013-10-19 22:24:46384
Daniel Murphy7c750432019-08-20 01:39:47385 RunPostedTasks();
386
Evan Stade90332942023-12-18 21:21:41387 EXPECT_TRUE(bucket_context_->GetDatabasesForTesting().empty());
[email protected]26811ea2013-06-04 07:33:30388}
389
Evan Stadecbb1e002024-09-13 20:06:57390TEST_F(DatabaseTest, ForcedClose) {
391 MockMojoDatabaseCallbacks database_callbacks;
392 MockFactoryClient request;
avib7348942015-12-25 20:57:10393 const int64_t upgrade_transaction_id = 3;
Evan Stadecbb1e002024-09-13 20:06:57394 auto connection = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34395 std::make_unique<ThunkFactoryClient>(request),
Evan Stadecbb1e002024-09-13 20:06:57396 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34397 database_callbacks.BindNewEndpointAndPassDedicatedRemote()),
Evan Stade833343922023-07-05 21:09:51398 upgrade_transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION,
Guido Urdaneta16511382023-10-25 17:40:04399 mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35400 db_->ScheduleOpenConnection(std::move(connection));
Daniel Murphy7c750432019-08-20 01:39:47401 RunPostedTasks();
402
Evan Stade0c0e6d652023-11-09 23:28:03403 EXPECT_EQ(db_, request.connection()->database().get());
[email protected]26811ea2013-06-04 07:33:30404
Steve Becker5cbfe652024-03-07 23:43:33405 request.connection()->CreateTransaction(
406 mojo::NullAssociatedReceiver(), /*transaction_id=*/123,
407 /*object_store_ids=*/{}, blink::mojom::IDBTransactionMode::ReadOnly,
408 blink::mojom::IDBTransactionDurability::Relaxed);
Evan Stade0c0e6d652023-11-09 23:28:03409 db_ = nullptr;
[email protected]26811ea2013-06-04 07:33:30410
Evan Stadec24dbfe92023-11-01 20:04:34411 base::RunLoop run_loop;
412 EXPECT_CALL(database_callbacks, ForcedClose)
413 .WillOnce(base::test::RunClosure(run_loop.QuitClosure()));
Mingyu Lei87210bc2025-04-17 09:35:50414 request.connection()->CloseAndReportForceClose(kTestForceCloseMessage);
Evan Stadec24dbfe92023-11-01 20:04:34415 run_loop.Run();
[email protected]26811ea2013-06-04 07:33:30416}
417
Victor Costan158ce94c2021-02-25 19:57:28418namespace {
419
Evan Stadecbb1e002024-09-13 20:06:57420class FakeFactoryClient : public FactoryClient {
[email protected]09bda0f2013-07-11 08:01:21421 public:
Evan Stadecbb1e002024-09-13 20:06:57422 FakeFactoryClient() : FactoryClient(mojo::NullAssociatedRemote()) {}
423 ~FakeFactoryClient() override = default;
[email protected]09bda0f2013-07-11 08:01:21424
Evan Stadecbb1e002024-09-13 20:06:57425 FakeFactoryClient(const FakeFactoryClient&) = delete;
426 FakeFactoryClient& operator=(const FakeFactoryClient&) = delete;
Peter Boström9b036532021-10-28 23:37:28427
avib7348942015-12-25 20:57:10428 void OnBlocked(int64_t existing_version) override { blocked_called_ = true; }
Evan Stadeabae4f62023-07-28 21:08:15429 void OnDeleteSuccess(int64_t old_version) override { success_called_ = true; }
Evan Stadecbb1e002024-09-13 20:06:57430 void OnError(const DatabaseError& error) override { error_called_ = true; }
[email protected]09bda0f2013-07-11 08:01:21431
432 bool blocked_called() const { return blocked_called_; }
[email protected]72273712014-04-30 19:50:11433 bool success_called() const { return success_called_; }
jsbell94384e52016-10-04 17:19:58434 bool error_called() const { return error_called_; }
[email protected]09bda0f2013-07-11 08:01:21435
436 private:
jsbell94384e52016-10-04 17:19:58437 bool blocked_called_ = false;
438 bool success_called_ = false;
439 bool error_called_ = false;
[email protected]09bda0f2013-07-11 08:01:21440};
441
Victor Costan158ce94c2021-02-25 19:57:28442} // namespace
443
Evan Stadecbb1e002024-09-13 20:06:57444TEST_F(DatabaseTest, PendingDelete) {
445 MockFactoryClient request1;
avib7348942015-12-25 20:57:10446 const int64_t transaction_id1 = 1;
Evan Stadecbb1e002024-09-13 20:06:57447 MockMojoDatabaseCallbacks database_callbacks1;
448 auto connection = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34449 std::make_unique<ThunkFactoryClient>(request1),
Evan Stadecbb1e002024-09-13 20:06:57450 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34451 database_callbacks1.BindNewEndpointAndPassDedicatedRemote()),
Evan Stadef5433b82023-07-25 18:03:06452 transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION,
Guido Urdaneta16511382023-10-25 17:40:04453 mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35454 db_->ScheduleOpenConnection(std::move(connection));
Daniel Murphy7c750432019-08-20 01:39:47455 RunPostedTasks();
[email protected]09bda0f2013-07-11 08:01:21456
dmurph497e676f12017-04-25 20:29:57457 EXPECT_EQ(db_->ConnectionCount(), 1UL);
458 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL);
459 EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
[email protected]09bda0f2013-07-11 08:01:21460
Evan Stade22f9c2642024-02-04 00:35:28461 base::RunLoop run_loop;
Evan Stadecbb1e002024-09-13 20:06:57462 FakeFactoryClient request2;
Evan Stade22f9c2642024-02-04 00:35:28463 db_->ScheduleDeleteDatabase(std::make_unique<ThunkFactoryClient>(request2),
464 run_loop.QuitClosure());
Daniel Murphy7c750432019-08-20 01:39:47465 RunPostedTasks();
dmurph497e676f12017-04-25 20:29:57466 EXPECT_EQ(db_->ConnectionCount(), 1UL);
467 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL);
468 EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
[email protected]09bda0f2013-07-11 08:01:21469
Evan Stade833343922023-07-05 21:09:51470 EXPECT_FALSE(request2.blocked_called());
471 request1.connection()->VersionChangeIgnored();
472 EXPECT_TRUE(request2.blocked_called());
dmurph497e676f12017-04-25 20:29:57473 EXPECT_EQ(db_->ConnectionCount(), 1UL);
474 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL);
475 EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
[email protected]75a854a2014-07-07 15:57:36476
Mingyu Lei87210bc2025-04-17 09:35:50477 db_->ForceCloseAndRunTasks(kTestForceCloseMessage);
Evan Stade0c0e6d652023-11-09 23:28:03478 db_ = nullptr;
Daniel Murphy7c750432019-08-20 01:39:47479
Evan Stade22f9c2642024-02-04 00:35:28480 run_loop.Run();
Daniel Murphy4c0f9c12019-05-23 01:14:35481 EXPECT_FALSE(db_);
[email protected]09bda0f2013-07-11 08:01:21482
Evan Stade833343922023-07-05 21:09:51483 EXPECT_TRUE(request2.success_called());
[email protected]09bda0f2013-07-11 08:01:21484}
485
Evan Stadecbb1e002024-09-13 20:06:57486TEST_F(DatabaseTest, OpenDeleteClear) {
dmurph497e676f12017-04-25 20:29:57487 const int64_t kDatabaseVersion = 1;
488
Evan Stadecbb1e002024-09-13 20:06:57489 MockFactoryClient request1(
Victor Costan158ce94c2021-02-25 19:57:28490 /*expect_connection=*/true);
Evan Stadecbb1e002024-09-13 20:06:57491 MockMojoDatabaseCallbacks database_callbacks1;
dmurph497e676f12017-04-25 20:29:57492 const int64_t transaction_id1 = 1;
Evan Stadecbb1e002024-09-13 20:06:57493 auto connection1 = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34494 std::make_unique<ThunkFactoryClient>(request1),
Evan Stadecbb1e002024-09-13 20:06:57495 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34496 database_callbacks1.BindNewEndpointAndPassDedicatedRemote()),
Guido Urdaneta16511382023-10-25 17:40:04497 transaction_id1, kDatabaseVersion, mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35498 db_->ScheduleOpenConnection(std::move(connection1));
Daniel Murphy7c750432019-08-20 01:39:47499 RunPostedTasks();
dmurph497e676f12017-04-25 20:29:57500
501 EXPECT_EQ(db_->ConnectionCount(), 1UL);
502 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL);
503 EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
dmurph497e676f12017-04-25 20:29:57504
Evan Stadecbb1e002024-09-13 20:06:57505 MockFactoryClient request2(
Victor Costan158ce94c2021-02-25 19:57:28506 /*expect_connection=*/false);
Evan Stadecbb1e002024-09-13 20:06:57507 MockMojoDatabaseCallbacks database_callbacks2;
dmurph497e676f12017-04-25 20:29:57508 const int64_t transaction_id2 = 2;
Evan Stadecbb1e002024-09-13 20:06:57509 auto connection2 = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34510 std::make_unique<ThunkFactoryClient>(request2),
Evan Stadecbb1e002024-09-13 20:06:57511 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34512 database_callbacks2.BindNewEndpointAndPassDedicatedRemote()),
Guido Urdaneta16511382023-10-25 17:40:04513 transaction_id2, kDatabaseVersion, mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35514 db_->ScheduleOpenConnection(std::move(connection2));
Daniel Murphy7c750432019-08-20 01:39:47515 RunPostedTasks();
dmurph497e676f12017-04-25 20:29:57516
517 EXPECT_EQ(db_->ConnectionCount(), 1UL);
518 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL);
519 EXPECT_EQ(db_->PendingOpenDeleteCount(), 1UL);
dmurph497e676f12017-04-25 20:29:57520
Evan Stadecbb1e002024-09-13 20:06:57521 MockFactoryClient request3(
Victor Costan158ce94c2021-02-25 19:57:28522 /*expect_connection=*/false);
Evan Stadecbb1e002024-09-13 20:06:57523 MockMojoDatabaseCallbacks database_callbacks3;
dmurph497e676f12017-04-25 20:29:57524 const int64_t transaction_id3 = 3;
Evan Stadecbb1e002024-09-13 20:06:57525 auto connection3 = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34526 std::make_unique<ThunkFactoryClient>(request3),
Evan Stadecbb1e002024-09-13 20:06:57527 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34528 database_callbacks3.BindNewEndpointAndPassDedicatedRemote()),
Guido Urdaneta16511382023-10-25 17:40:04529 transaction_id3, kDatabaseVersion, mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35530 db_->ScheduleOpenConnection(std::move(connection3));
Daniel Murphy7c750432019-08-20 01:39:47531 RunPostedTasks();
dmurph497e676f12017-04-25 20:29:57532
Evan Stade833343922023-07-05 21:09:51533 EXPECT_TRUE(request1.upgrade_called());
dmurph497e676f12017-04-25 20:29:57534
535 EXPECT_EQ(db_->ConnectionCount(), 1UL);
536 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL);
537 EXPECT_EQ(db_->PendingOpenDeleteCount(), 2UL);
dmurph497e676f12017-04-25 20:29:57538
Evan Stadec24dbfe92023-11-01 20:04:34539 EXPECT_CALL(database_callbacks1, ForcedClose);
540 EXPECT_CALL(database_callbacks2, ForcedClose);
541 EXPECT_CALL(database_callbacks3, ForcedClose);
542
Mingyu Lei87210bc2025-04-17 09:35:50543 db_->ForceCloseAndRunTasks(kTestForceCloseMessage);
Evan Stade0c0e6d652023-11-09 23:28:03544 db_ = nullptr;
545 database_callbacks1.FlushForTesting();
dmurph497e676f12017-04-25 20:29:57546
Evan Stade833343922023-07-05 21:09:51547 EXPECT_TRUE(request1.error_called());
Evan Stade833343922023-07-05 21:09:51548 EXPECT_TRUE(request2.error_called());
Evan Stade833343922023-07-05 21:09:51549 EXPECT_TRUE(request3.error_called());
dmurph497e676f12017-04-25 20:29:57550}
551
Evan Stadecbb1e002024-09-13 20:06:57552TEST_F(DatabaseTest, ForceDelete) {
553 MockFactoryClient request1;
554 MockMojoDatabaseCallbacks database_callbacks;
eostroukhov1470b1f2017-01-23 21:13:53555 const int64_t transaction_id1 = 1;
Evan Stadecbb1e002024-09-13 20:06:57556 auto connection = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34557 std::make_unique<ThunkFactoryClient>(request1),
Evan Stadecbb1e002024-09-13 20:06:57558 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34559 database_callbacks.BindNewEndpointAndPassDedicatedRemote()),
Evan Stadef5433b82023-07-25 18:03:06560 transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION,
Guido Urdaneta16511382023-10-25 17:40:04561 mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35562 db_->ScheduleOpenConnection(std::move(connection));
Daniel Murphy7c750432019-08-20 01:39:47563 RunPostedTasks();
eostroukhov1470b1f2017-01-23 21:13:53564
dmurph497e676f12017-04-25 20:29:57565 EXPECT_EQ(db_->ConnectionCount(), 1UL);
566 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL);
567 EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
eostroukhov1470b1f2017-01-23 21:13:53568
Evan Stade22f9c2642024-02-04 00:35:28569 base::RunLoop run_loop;
Evan Stadecbb1e002024-09-13 20:06:57570 FakeFactoryClient request2;
Evan Stade22f9c2642024-02-04 00:35:28571 db_->ScheduleDeleteDatabase(std::make_unique<ThunkFactoryClient>(request2),
572 run_loop.QuitClosure());
Daniel Murphy7c750432019-08-20 01:39:47573 RunPostedTasks();
Evan Stade22f9c2642024-02-04 00:35:28574 EXPECT_FALSE(run_loop.AnyQuitCalled());
Mingyu Lei87210bc2025-04-17 09:35:50575 db_->ForceCloseAndRunTasks(kTestForceCloseMessage);
Evan Stade0c0e6d652023-11-09 23:28:03576 db_ = nullptr;
Evan Stade22f9c2642024-02-04 00:35:28577 run_loop.Run();
Daniel Murphy4c0f9c12019-05-23 01:14:35578 EXPECT_FALSE(db_);
Evan Stade833343922023-07-05 21:09:51579 EXPECT_FALSE(request2.blocked_called());
580 EXPECT_TRUE(request2.success_called());
eostroukhov1470b1f2017-01-23 21:13:53581}
582
Evan Stadecbb1e002024-09-13 20:06:57583TEST_F(DatabaseTest, ForceCloseWhileOpenPending) {
Daniel Murphyeaf2e8bc2019-03-14 03:23:36584 // Verify that pending connection requests are handled correctly during a
585 // ForceClose.
Evan Stadecbb1e002024-09-13 20:06:57586 MockFactoryClient request1;
587 MockMojoDatabaseCallbacks database_callbacks1;
Daniel Murphyeaf2e8bc2019-03-14 03:23:36588 const int64_t transaction_id1 = 1;
Evan Stadecbb1e002024-09-13 20:06:57589 auto connection1 = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34590 std::make_unique<ThunkFactoryClient>(request1),
Evan Stadecbb1e002024-09-13 20:06:57591 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34592 database_callbacks1.BindNewEndpointAndPassDedicatedRemote()),
Evan Stadef5433b82023-07-25 18:03:06593 transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION,
Guido Urdaneta16511382023-10-25 17:40:04594 mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35595 db_->ScheduleOpenConnection(std::move(connection1));
Daniel Murphy7c750432019-08-20 01:39:47596 RunPostedTasks();
Daniel Murphyeaf2e8bc2019-03-14 03:23:36597
598 EXPECT_EQ(db_->ConnectionCount(), 1UL);
599 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL);
600 EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
Daniel Murphyeaf2e8bc2019-03-14 03:23:36601
Evan Stadecbb1e002024-09-13 20:06:57602 MockFactoryClient request2(/*expect_connection=*/false);
603 MockMojoDatabaseCallbacks database_callbacks2;
Evan Stadec24dbfe92023-11-01 20:04:34604
Daniel Murphyeaf2e8bc2019-03-14 03:23:36605 const int64_t transaction_id2 = 2;
Evan Stadecbb1e002024-09-13 20:06:57606 auto connection2 = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34607 std::make_unique<ThunkFactoryClient>(request2),
Evan Stadecbb1e002024-09-13 20:06:57608 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34609 database_callbacks2.BindNewEndpointAndPassDedicatedRemote()),
Guido Urdaneta16511382023-10-25 17:40:04610 transaction_id2, 3, mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35611 db_->ScheduleOpenConnection(std::move(connection2));
Daniel Murphy7c750432019-08-20 01:39:47612 RunPostedTasks();
Daniel Murphyeaf2e8bc2019-03-14 03:23:36613
614 EXPECT_EQ(db_->ConnectionCount(), 1UL);
615 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL);
616 EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
Daniel Murphyeaf2e8bc2019-03-14 03:23:36617
Mingyu Lei87210bc2025-04-17 09:35:50618 db_->ForceCloseAndRunTasks(kTestForceCloseMessage);
Evan Stade0c0e6d652023-11-09 23:28:03619 db_ = nullptr;
Daniel Murphy7c750432019-08-20 01:39:47620 RunPostedTasks();
Daniel Murphy4c0f9c12019-05-23 01:14:35621 EXPECT_FALSE(db_);
Daniel Murphyeaf2e8bc2019-03-14 03:23:36622}
623
Evan Stadecbb1e002024-09-13 20:06:57624TEST_F(DatabaseTest, ForceCloseWhileOpenAndDeletePending) {
Daniel Murphy8ae1a64b2019-05-24 00:56:59625 // Verify that pending connection requests are handled correctly during a
626 // ForceClose.
Evan Stadecbb1e002024-09-13 20:06:57627 MockFactoryClient request1;
628 MockMojoDatabaseCallbacks database_callbacks1;
Daniel Murphy8ae1a64b2019-05-24 00:56:59629 const int64_t transaction_id1 = 1;
Evan Stadecbb1e002024-09-13 20:06:57630 auto connection1 = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34631 std::make_unique<ThunkFactoryClient>(request1),
Evan Stadecbb1e002024-09-13 20:06:57632 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34633 database_callbacks1.BindNewEndpointAndPassDedicatedRemote()),
Evan Stadef5433b82023-07-25 18:03:06634 transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION,
Guido Urdaneta16511382023-10-25 17:40:04635 mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35636 db_->ScheduleOpenConnection(std::move(connection1));
Daniel Murphy7c750432019-08-20 01:39:47637 RunPostedTasks();
Daniel Murphy8ae1a64b2019-05-24 00:56:59638
639 EXPECT_EQ(db_->ConnectionCount(), 1UL);
640 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL);
641 EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL);
642
Evan Stadecbb1e002024-09-13 20:06:57643 MockFactoryClient request2(false);
644 MockMojoDatabaseCallbacks database_callbacks2;
Daniel Murphy8ae1a64b2019-05-24 00:56:59645 const int64_t transaction_id2 = 2;
Evan Stadecbb1e002024-09-13 20:06:57646 auto connection2 = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34647 std::make_unique<ThunkFactoryClient>(request2),
Evan Stadecbb1e002024-09-13 20:06:57648 std::make_unique<DatabaseCallbacks>(
Evan Stadec24dbfe92023-11-01 20:04:34649 database_callbacks2.BindNewEndpointAndPassDedicatedRemote()),
Guido Urdaneta16511382023-10-25 17:40:04650 transaction_id2, 3, mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35651 db_->ScheduleOpenConnection(std::move(connection2));
Daniel Murphy7c750432019-08-20 01:39:47652 RunPostedTasks();
Daniel Murphy8ae1a64b2019-05-24 00:56:59653
Evan Stade22f9c2642024-02-04 00:35:28654 base::RunLoop run_loop;
Evan Stadecbb1e002024-09-13 20:06:57655 auto request3 = std::make_unique<FakeFactoryClient>();
Evan Stade22f9c2642024-02-04 00:35:28656 db_->ScheduleDeleteDatabase(std::move(request3), run_loop.QuitClosure());
Daniel Murphy7c750432019-08-20 01:39:47657 RunPostedTasks();
Evan Stade22f9c2642024-02-04 00:35:28658 EXPECT_FALSE(run_loop.AnyQuitCalled());
Daniel Murphy8ae1a64b2019-05-24 00:56:59659
660 EXPECT_EQ(db_->ConnectionCount(), 1UL);
661 EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL);
662 EXPECT_EQ(db_->PendingOpenDeleteCount(), 1UL);
663
Mingyu Lei87210bc2025-04-17 09:35:50664 db_->ForceCloseAndRunTasks(kTestForceCloseMessage);
Evan Stade0c0e6d652023-11-09 23:28:03665 db_ = nullptr;
Evan Stade22f9c2642024-02-04 00:35:28666 run_loop.Run();
Daniel Murphy8ae1a64b2019-05-24 00:56:59667}
668
Mike Wasserman0d5da522024-09-27 07:47:03669Status DummyOperation(Transaction* transaction) {
670 return Status::OK();
[email protected]12c337722014-05-22 19:42:42671}
672
Evan Stadecbb1e002024-09-13 20:06:57673class DatabaseOperationTest : public DatabaseTest {
[email protected]12c337722014-05-22 19:42:42674 public:
Mike Wasserman0d5da522024-09-27 07:47:03675 DatabaseOperationTest() = default;
Evan Stadecbb1e002024-09-13 20:06:57676 DatabaseOperationTest(const DatabaseOperationTest&) = delete;
677 DatabaseOperationTest& operator=(const DatabaseOperationTest&) = delete;
Peter Boström9b036532021-10-28 23:37:28678
dchengfa85b152014-10-28 01:13:42679 void SetUp() override {
Evan Stadecbb1e002024-09-13 20:06:57680 DatabaseTest::SetUp();
[email protected]12c337722014-05-22 19:42:42681
avib7348942015-12-25 20:57:10682 const int64_t transaction_id = 1;
Evan Stadecbb1e002024-09-13 20:06:57683 auto connection = std::make_unique<PendingConnection>(
Evan Stadec24dbfe92023-11-01 20:04:34684 std::make_unique<ThunkFactoryClient>(request_),
Evan Stadecbb1e002024-09-13 20:06:57685 std::make_unique<DatabaseCallbacks>(mojo::NullAssociatedRemote()),
Evan Stade833343922023-07-05 21:09:51686 transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION,
Guido Urdaneta16511382023-10-25 17:40:04687 mojo::NullAssociatedReceiver());
Evan Stade9f5e401c2024-01-04 23:58:35688 db_->ScheduleOpenConnection(std::move(connection));
Daniel Murphy7c750432019-08-20 01:39:47689 RunPostedTasks();
jsbelle9c26d72016-02-24 21:23:37690 EXPECT_EQ(IndexedDBDatabaseMetadata::NO_VERSION, db_->metadata().version);
[email protected]12c337722014-05-22 19:42:42691
Evan Stade833343922023-07-05 21:09:51692 EXPECT_TRUE(request_.connection());
Guido Urdaneta16511382023-10-25 17:40:04693 transaction_ = request_.connection()->CreateVersionChangeTransaction(
Joshua Bell28132782021-03-15 18:54:22694 transaction_id, /*scope=*/std::set<int64_t>(),
Evan Stadecc645c82025-04-02 17:26:49695 std::make_unique<FakeTransaction>(
Evan Stade2fbd4532025-04-30 10:19:22696 commit_success_,
697 db_->backing_store_db()->CreateTransaction(
698 blink::mojom::IDBTransactionDurability::Relaxed,
699 blink::mojom::IDBTransactionMode::VersionChange)));
Evan Stade87073092024-01-12 03:53:23700
701 std::vector<PartitionedLockManager::PartitionedLockRequest> lock_requests =
Abhishek Shanthkumar88ce4902025-06-26 16:00:00702 db_->BuildLockRequestsForTransaction(
703 blink::mojom::IDBTransactionMode::VersionChange, /*scope=*/{});
Evan Stade22f9c2642024-02-04 00:35:28704 db_->lock_manager().AcquireLocks(
Evan Staded9055a72024-08-22 23:11:27705 std::move(lock_requests), *transaction_->mutable_locks_receiver(),
Evan Stadecbb1e002024-09-13 20:06:57706 base::BindOnce(&Transaction::Start, transaction_->AsWeakPtr()));
[email protected]12c337722014-05-22 19:42:42707
708 // Add a dummy task which takes the place of the VersionChangeOperation
709 // which kicks off the upgrade. This ensures that the transaction has
710 // processed at least one task before the CreateObjectStore call.
jsbellfd99b4a2017-06-20 19:55:13711 transaction_->ScheduleTask(base::BindOnce(&DummyOperation));
Daniel Murphy0240b782019-08-14 21:15:09712 // Run posted tasks to execute the dummy operation and ensure that it is
713 // stored in the connection.
714 RunPostedTasks();
[email protected]12c337722014-05-22 19:42:42715 }
716
Steve Becker4848af32024-10-29 22:57:19717 // Populates an object store and optionally an index with `database_records`.
718 // After setup, calls `Database::GetAllOperation` with `get_all_parameters`.
719 // Verifies that the results match `expected_results`.
720 void TestGetAll(
Evan Stade46c8dab2025-05-07 17:05:14721 TestDatabaseParameters database_parameters,
722 TestGetAllParameters get_all_parameters,
Steve Becker4848af32024-10-29 22:57:19723 base::span<const blink::mojom::IDBRecordPtr> expected_results) {
724 // Create the object store.
725 ASSERT_EQ(0u, db_->metadata().object_stores.size());
726 const auto& object_store_parameters =
727 database_parameters.object_store_parameters;
728 const int64_t store_id = object_store_parameters.object_store_id;
Evan Stade540f03c82025-04-30 16:45:12729 Status status = transaction_->BackingStoreTransaction()->CreateObjectStore(
Steve Becker4848af32024-10-29 22:57:19730 store_id, object_store_parameters.name,
731 object_store_parameters.key_path,
Evan Stade540f03c82025-04-30 16:45:12732 object_store_parameters.auto_increment);
Steve Becker4848af32024-10-29 22:57:19733 EXPECT_TRUE(status.ok()) << status.ToString();
734 EXPECT_EQ(1u, db_->metadata().object_stores.size());
735
736 // Optionally, create an index when the test provides a valid index id.
Evan Stade73a3dfa2025-05-21 21:22:14737 const blink::IndexedDBIndexMetadata index(
738 database_parameters.index_parameters.name,
739 database_parameters.index_parameters.index_id,
740 database_parameters.index_parameters.key_path,
741 database_parameters.index_parameters.unique,
742 database_parameters.index_parameters.multi_entry);
743 const int64_t index_id = index.id;
Steve Becker4848af32024-10-29 22:57:19744 const bool has_index =
Evan Stade73a3dfa2025-05-21 21:22:14745 index_id != blink::IndexedDBIndexMetadata::kInvalidId;
Steve Becker4848af32024-10-29 22:57:19746 if (has_index) {
Evan Stade73a3dfa2025-05-21 21:22:14747 status =
748 transaction_->BackingStoreTransaction()->CreateIndex(store_id, index);
Steve Becker4848af32024-10-29 22:57:19749 }
750 EXPECT_TRUE(status.ok()) << status.ToString();
751
752 // Populate the object store and optionally the index with the provided
753 // records.
Evan Stadeca999b12025-05-09 19:09:11754 for (TestIDBRecord& record : database_parameters.records) {
Steve Becker4848af32024-10-29 22:57:19755 std::vector<IndexedDBIndexKeys> index_keys;
756 ASSERT_EQ(record.index_key.has_value(), has_index);
757 if (has_index) {
Evan Stadeca999b12025-05-09 19:09:11758 IndexedDBIndexKeys index_key{index_id, {}};
759 index_key.keys.emplace_back(std::move(*record.index_key));
Steve Becker4848af32024-10-29 22:57:19760 index_keys.emplace_back(std::move(index_key));
761 }
762
763 testing::NiceMock<
764 base::MockCallback<blink::mojom::IDBTransaction::PutCallback>>
765 callback;
766
767 // Set in-flight memory to a reasonably large number to prevent underflow
768 // in `PutOperation`
Evan Stade3b9078f2025-05-07 16:14:30769 transaction_->in_flight_memory_ += 1000;
Steve Becker4848af32024-10-29 22:57:19770
Evan Stade46c8dab2025-05-07 17:05:14771 status = transaction_->DoPut(
Evan Stadeca999b12025-05-09 19:09:11772 store_id, record.value.Clone(), std::move(record.primary_key),
Evan Stade46c8dab2025-05-07 17:05:14773 blink::mojom::IDBPutMode::AddOnly, std::move(index_keys),
774 callback.Get(), transaction_);
Steve Becker4848af32024-10-29 22:57:19775 EXPECT_TRUE(status.ok()) << status.ToString();
776 }
777
778 // Call `Database::GetAllOperation` with the provided parameters.
779 FakeGetAllResultSink result_sink;
780 blink::mojom::IDBDatabase::GetAllCallback get_all_callback = base::BindOnce(
781 &FakeGetAllResultSink::BindReceiver, base::Unretained(&result_sink));
782
783 std::unique_ptr<Database::GetAllResultSinkWrapper> result_sink_wrapper =
784 std::make_unique<Database::GetAllResultSinkWrapper>(
785 transaction_->AsWeakPtr(), std::move(get_all_callback));
786 result_sink_wrapper->UseDedicatedReceiverForTesting();
787
Evan Stadeca999b12025-05-09 19:09:11788 status = db_->GetAllOperation(
789 store_id, index_id, std::move(get_all_parameters.key_range),
790 get_all_parameters.result_type, get_all_parameters.max_count,
791 get_all_parameters.direction, std::move(result_sink_wrapper),
792 transaction_);
Steve Becker4848af32024-10-29 22:57:19793 EXPECT_TRUE(status.ok()) << status.ToString();
794
795 result_sink.WaitForResults();
796 EXPECT_EQ(result_sink.GetError(), nullptr);
797
798 // Verify that the actual results match the expected results.
799 const std::vector<blink::mojom::IDBRecordPtr>& actual_results =
800 result_sink.GetResults();
801 ASSERT_EQ(actual_results.size(), expected_results.size());
802
803 for (size_t i = 0u; i < expected_results.size(); ++i) {
804 ASSERT_FALSE(actual_results[i].is_null());
805
806 // Verify the primary key.
807 ASSERT_NO_FATAL_FAILURE(ExpectEqualsOptionalIndexedDBKey(
808 expected_results[i]->primary_key, actual_results[i]->primary_key));
809
810 // Verify the record value.
811 ASSERT_NO_FATAL_FAILURE(ExpectEqualsIDBReturnValuePtr(
812 expected_results[i]->return_value, actual_results[i]->return_value));
813
814 // Verify the index key.
815 ASSERT_NO_FATAL_FAILURE(ExpectEqualsOptionalIndexedDBKey(
816 expected_results[i]->index_key, actual_results[i]->index_key));
817 }
818
819 // Perform cleanup.
820 transaction_->SetCommitFlag();
821 transaction_ = nullptr;
822 RunPostedTasks();
823
824 // A transaction error would have resulted in a deleted db.
825 EXPECT_FALSE(bucket_context_->GetDatabasesForTesting().empty());
826 }
827
[email protected]12c337722014-05-22 19:42:42828 protected:
Evan Stadecbb1e002024-09-13 20:06:57829 MockFactoryClient request_;
Tanuj Martolia5f5bd992024-05-31 05:09:25830
Evan Stadecbb1e002024-09-13 20:06:57831 // As this is owned by `Connection`, tests that cause the transaction
Tanuj Martolia5f5bd992024-05-31 05:09:25832 // to be committed must manually reset this to null to avoid triggering
833 // dangling pointer warnings.
Evan Stadecbb1e002024-09-13 20:06:57834 raw_ptr<Transaction> transaction_ = nullptr;
Mike Wasserman0d5da522024-09-27 07:47:03835 Status commit_success_;
[email protected]12c337722014-05-22 19:42:42836};
837
Evan Stadecbb1e002024-09-13 20:06:57838TEST_F(DatabaseOperationTest, CreateObjectStore) {
[email protected]12c337722014-05-22 19:42:42839 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
avib7348942015-12-25 20:57:10840 const int64_t store_id = 1001;
Evan Stade540f03c82025-04-30 16:45:12841 Status s = transaction_->BackingStoreTransaction()->CreateObjectStore(
842 store_id, u"store", IndexedDBKeyPath(),
843 /*auto_increment=*/false);
Daniel Murphy0240b782019-08-14 21:15:09844 EXPECT_TRUE(s.ok());
Daniel Murphy7c750432019-08-20 01:39:47845 transaction_->SetCommitFlag();
Tanuj Martolia5f5bd992024-05-31 05:09:25846 transaction_ = nullptr;
Daniel Murphy7c750432019-08-20 01:39:47847 RunPostedTasks();
Evan Stade59872192024-02-08 16:57:48848 EXPECT_TRUE(bucket_context_);
[email protected]12c337722014-05-22 19:42:42849 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
850}
851
Evan Stadecbb1e002024-09-13 20:06:57852TEST_F(DatabaseOperationTest, CreateIndex) {
[email protected]12c337722014-05-22 19:42:42853 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
avib7348942015-12-25 20:57:10854 const int64_t store_id = 1001;
Evan Stade540f03c82025-04-30 16:45:12855 Status s = transaction_->BackingStoreTransaction()->CreateObjectStore(
856 store_id, u"store", IndexedDBKeyPath(),
857 /*auto_increment=*/false);
Daniel Murphy0240b782019-08-14 21:15:09858 EXPECT_TRUE(s.ok());
[email protected]12c337722014-05-22 19:42:42859 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
avib7348942015-12-25 20:57:10860 const int64_t index_id = 2002;
Evan Stade540f03c82025-04-30 16:45:12861 s = transaction_->BackingStoreTransaction()->CreateIndex(
Evan Stade73a3dfa2025-05-21 21:22:14862 store_id, blink::IndexedDBIndexMetadata(
863 u"index", index_id, IndexedDBKeyPath(), /*unique=*/false,
864 /*multi_entry=*/false));
Daniel Murphy0240b782019-08-14 21:15:09865 EXPECT_TRUE(s.ok());
[email protected]12c337722014-05-22 19:42:42866 EXPECT_EQ(
867 1ULL,
868 db_->metadata().object_stores.find(store_id)->second.indexes.size());
Daniel Murphy7c750432019-08-20 01:39:47869 transaction_->SetCommitFlag();
Tanuj Martolia5f5bd992024-05-31 05:09:25870 transaction_ = nullptr;
Daniel Murphy7c750432019-08-20 01:39:47871 RunPostedTasks();
Evan Stade59872192024-02-08 16:57:48872 EXPECT_TRUE(bucket_context_);
[email protected]12c337722014-05-22 19:42:42873 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
874 EXPECT_EQ(
875 1ULL,
876 db_->metadata().object_stores.find(store_id)->second.indexes.size());
877}
878
Evan Stadecbb1e002024-09-13 20:06:57879class DatabaseOperationAbortTest : public DatabaseOperationTest {
[email protected]12c337722014-05-22 19:42:42880 public:
Evan Stadecbb1e002024-09-13 20:06:57881 DatabaseOperationAbortTest() {
Mike Wasserman0d5da522024-09-27 07:47:03882 commit_success_ = Status::NotFound("Bummer.");
[email protected]67bb75b92014-06-04 00:34:10883 }
[email protected]e8ca0f52014-06-07 08:46:34884
Evan Stadecbb1e002024-09-13 20:06:57885 DatabaseOperationAbortTest(const DatabaseOperationAbortTest&) = delete;
886 DatabaseOperationAbortTest& operator=(const DatabaseOperationAbortTest&) =
887 delete;
[email protected]12c337722014-05-22 19:42:42888};
889
Evan Stadecbb1e002024-09-13 20:06:57890TEST_F(DatabaseOperationAbortTest, CreateObjectStore) {
[email protected]12c337722014-05-22 19:42:42891 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
avib7348942015-12-25 20:57:10892 const int64_t store_id = 1001;
Evan Stade540f03c82025-04-30 16:45:12893 Status s = transaction_->BackingStoreTransaction()->CreateObjectStore(
894 store_id, u"store", IndexedDBKeyPath(),
895 /*auto_increment=*/false);
Daniel Murphy0240b782019-08-14 21:15:09896 EXPECT_TRUE(s.ok());
[email protected]12c337722014-05-22 19:42:42897 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
Evan Stade59872192024-02-08 16:57:48898 db_ = nullptr;
Daniel Murphy7c750432019-08-20 01:39:47899 transaction_->SetCommitFlag();
900 RunPostedTasks();
Evan Stade59872192024-02-08 16:57:48901 // A transaction error results in a deleted db.
902 EXPECT_TRUE(bucket_context_->GetDatabasesForTesting().empty());
[email protected]12c337722014-05-22 19:42:42903}
904
Evan Stadecbb1e002024-09-13 20:06:57905TEST_F(DatabaseOperationAbortTest, CreateIndex) {
[email protected]12c337722014-05-22 19:42:42906 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
avib7348942015-12-25 20:57:10907 const int64_t store_id = 1001;
Evan Stade540f03c82025-04-30 16:45:12908 Status s = transaction_->BackingStoreTransaction()->CreateObjectStore(
909 store_id, u"store", IndexedDBKeyPath(),
910 /*auto_increment=*/false);
Daniel Murphy0240b782019-08-14 21:15:09911 EXPECT_TRUE(s.ok());
[email protected]12c337722014-05-22 19:42:42912 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
avib7348942015-12-25 20:57:10913 const int64_t index_id = 2002;
Evan Stade540f03c82025-04-30 16:45:12914 s = transaction_->BackingStoreTransaction()->CreateIndex(
Evan Stade73a3dfa2025-05-21 21:22:14915 store_id, blink::IndexedDBIndexMetadata(
916 u"index", index_id, IndexedDBKeyPath(), /*unique=*/false,
917 /*multi_entry=*/false));
Daniel Murphy0240b782019-08-14 21:15:09918 EXPECT_TRUE(s.ok());
[email protected]12c337722014-05-22 19:42:42919 EXPECT_EQ(
920 1ULL,
921 db_->metadata().object_stores.find(store_id)->second.indexes.size());
Evan Stade59872192024-02-08 16:57:48922 db_ = nullptr;
Daniel Murphy7c750432019-08-20 01:39:47923 transaction_->SetCommitFlag();
924 RunPostedTasks();
Evan Stade59872192024-02-08 16:57:48925 // A transaction error results in a deleted db.
926 EXPECT_TRUE(bucket_context_->GetDatabasesForTesting().empty());
[email protected]12c337722014-05-22 19:42:42927}
928
Evan Stadecbb1e002024-09-13 20:06:57929TEST_F(DatabaseOperationTest, CreatePutDelete) {
[email protected]12c337722014-05-22 19:42:42930 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
avib7348942015-12-25 20:57:10931 const int64_t store_id = 1001;
[email protected]12c337722014-05-22 19:42:42932
Evan Stade540f03c82025-04-30 16:45:12933 Status s = transaction_->BackingStoreTransaction()->CreateObjectStore(
934 store_id, u"store", IndexedDBKeyPath(),
935 /*auto_increment=*/false);
Daniel Murphy0240b782019-08-14 21:15:09936 EXPECT_TRUE(s.ok());
[email protected]12c337722014-05-22 19:42:42937 EXPECT_EQ(1ULL, db_->metadata().object_stores.size());
938
Chase Phillips5615c262019-07-29 21:42:38939 base::MockCallback<blink::mojom::IDBTransaction::PutCallback> callback;
[email protected]12c337722014-05-22 19:42:42940
Austin Sullivanda226512020-10-01 19:42:48941 // Set in-flight memory to a reasonably large number to prevent underflow in
Ari Chivukulafae9b8082022-04-14 22:27:29942 // `PutOperation`
Evan Stade3b9078f2025-05-07 16:14:30943 transaction_->in_flight_memory_ += 1000;
Austin Sullivanda226512020-10-01 19:42:48944
Evan Stade3b9078f2025-05-07 16:14:30945 s = transaction_->DoPut(
946 store_id, IndexedDBValue("value1", {}), IndexedDBKey("key"),
947 blink::mojom::IDBPutMode::AddOnly, std::vector<IndexedDBIndexKeys>(),
948 callback.Get(), transaction_);
Daniel Murphy0240b782019-08-14 21:15:09949 EXPECT_TRUE(s.ok());
[email protected]12c337722014-05-22 19:42:42950
Evan Stade540f03c82025-04-30 16:45:12951 s = transaction_->BackingStoreTransaction()->DeleteObjectStore(store_id);
Daniel Murphy0240b782019-08-14 21:15:09952 EXPECT_TRUE(s.ok());
953
[email protected]12c337722014-05-22 19:42:42954 EXPECT_EQ(0ULL, db_->metadata().object_stores.size());
[email protected]41db229742014-05-31 22:17:51955
Daniel Murphy7c750432019-08-20 01:39:47956 transaction_->SetCommitFlag();
Tanuj Martolia5f5bd992024-05-31 05:09:25957 transaction_ = nullptr;
Daniel Murphy7c750432019-08-20 01:39:47958 RunPostedTasks();
Evan Stade59872192024-02-08 16:57:48959 // A transaction error would have resulted in a deleted db.
960 EXPECT_FALSE(bucket_context_->GetDatabasesForTesting().empty());
Daniel Murphy0240b782019-08-14 21:15:09961 EXPECT_TRUE(s.ok());
[email protected]12c337722014-05-22 19:42:42962}
963
Steve Becker4848af32024-10-29 22:57:19964TEST_F(DatabaseOperationTest, ObjectStoreGetAllKeysWhenEmpty) {
965 ASSERT_NO_FATAL_FAILURE(TestGetAll(
966 /*database_parameters=*/
967 {
968 /*object_store_parameters=*/
969 {
970 .object_store_id = kTestObjectStoreId,
971 },
972 /*index_parameters=*/{},
973 /*database_records=*/{},
974 },
975 /*get_all_parameters=*/
976 {
977 .result_type = blink::mojom::IDBGetAllResultType::Keys,
978 },
979 /*expected_results=*/{}));
980}
981
982TEST_F(DatabaseOperationTest, IndexGetAllValuesWhenEmpty) {
983 ASSERT_NO_FATAL_FAILURE(TestGetAll(
984 /*database_parameters=*/
985 {
986 /*object_store_parameters=*/
987 {
988 .object_store_id = kTestObjectStoreId,
989 },
990 /*index_parameters=*/
991 {
992 .index_id = kTestIndexId,
993 },
994 /*database_records=*/{},
995 },
996 /*get_all_parameters=*/
997 {
998 .result_type = blink::mojom::IDBGetAllResultType::Values,
999 },
1000 /*expected_results=*/{}));
1001}
1002
1003TEST_F(DatabaseOperationTest, ObjectStoreGetAllKeys) {
1004 const blink::mojom::IDBRecordPtr expected_results[] = {
1005 blink::mojom::IDBRecord::New(IndexedDBKey{"key1"},
1006 /*value=*/nullptr,
1007 /*index_key=*/std::nullopt),
1008 blink::mojom::IDBRecord::New(IndexedDBKey{"key2"},
1009 /*value=*/nullptr,
1010 /*index_key=*/std::nullopt),
1011 blink::mojom::IDBRecord::New(IndexedDBKey{"key3"},
1012 /*value=*/nullptr,
1013 /*index_key=*/std::nullopt),
1014 };
1015
1016 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1017 /*database_parameters=*/
1018 {
1019 /*object_store_parameters=*/
1020 {
1021 .object_store_id = kTestObjectStoreId,
1022 },
1023 /*index_parameters=*/{},
1024 /*database_records=*/
1025 {
1026 {
1027 IndexedDBKey{"key1"},
1028 {"value1", /*external_objects=*/{}},
1029 /*index_key=*/std::nullopt,
1030 },
1031 {
1032 IndexedDBKey{"key2"},
1033 {"value2", /*external_objects=*/{}},
1034 /*index_key=*/std::nullopt,
1035 },
1036 {
1037 IndexedDBKey{"key3"},
1038 {"value3", /*external_objects=*/{}},
1039 /*index_key=*/std::nullopt,
1040 },
1041 },
1042 },
1043 /*get_all_parameters=*/
1044 {
1045 .result_type = blink::mojom::IDBGetAllResultType::Keys,
1046 },
1047 expected_results));
1048}
1049
1050TEST_F(DatabaseOperationTest, ObjectStoreGetAllValues) {
1051 const blink::mojom::IDBRecordPtr expected_results[] = {
1052 blink::mojom::IDBRecord::New(
1053 /*primary_key=*/std::nullopt,
1054 /*value=*/CreateIDBReturnValuePtr("value1"),
1055 /*index_key=*/std::nullopt),
1056 blink::mojom::IDBRecord::New(
1057 /*primary_key=*/std::nullopt,
1058 /*value=*/CreateIDBReturnValuePtr("value2"),
1059 /*index_key=*/std::nullopt),
1060 blink::mojom::IDBRecord::New(
1061 /*primary_key=*/std::nullopt,
1062 /*value=*/CreateIDBReturnValuePtr("value3"),
1063 /*index_key=*/std::nullopt),
1064 };
1065
1066 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1067 /*database_parameters=*/
1068 {
1069 /*object_store_parameters=*/
1070 {
1071 .object_store_id = kTestObjectStoreId,
1072 },
1073 /*index_parameters=*/{},
1074 /*database_records=*/
1075 {
1076 {
1077 IndexedDBKey{"key1"},
1078 {"value1", /*external_objects=*/{}},
1079 /*index_key=*/std::nullopt,
1080 },
1081 {
1082 IndexedDBKey{"key2"},
1083 {"value2", /*external_objects=*/{}},
1084 /*index_key=*/std::nullopt,
1085 },
1086 {
1087 IndexedDBKey{"key3"},
1088 {"value3", /*external_objects=*/{}},
1089 /*index_key=*/std::nullopt,
1090 },
1091 },
1092 },
1093 /*get_all_parameters=*/
1094 {
1095 .result_type = blink::mojom::IDBGetAllResultType::Values,
1096 },
1097 expected_results));
1098}
1099
1100TEST_F(DatabaseOperationTest, ObjectStoreGetAllRecords) {
1101 const blink::mojom::IDBRecordPtr expected_results[] = {
1102 blink::mojom::IDBRecord::New(IndexedDBKey{"key1"},
1103 /*value=*/CreateIDBReturnValuePtr("value1"),
1104 /*index_key=*/std::nullopt),
1105 blink::mojom::IDBRecord::New(IndexedDBKey{"key2"},
1106 /*value=*/CreateIDBReturnValuePtr("value2"),
1107 /*index_key=*/std::nullopt),
1108 blink::mojom::IDBRecord::New(IndexedDBKey{"key3"},
1109 /*value=*/CreateIDBReturnValuePtr("value3"),
1110 /*index_key=*/std::nullopt),
1111 };
1112
1113 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1114 /*database_parameters=*/
1115 {
1116 /*object_store_parameters=*/
1117 {
1118 .object_store_id = kTestObjectStoreId,
1119 },
1120 /*index_parameters=*/{},
1121 /*database_records=*/
1122 {
1123 {
1124 IndexedDBKey{"key1"},
1125 {"value1", /*external_objects=*/{}},
1126 /*index_key=*/std::nullopt,
1127 },
1128 {
1129 IndexedDBKey{"key2"},
1130 {"value2", /*external_objects=*/{}},
1131 /*index_key=*/std::nullopt,
1132 },
1133 {
1134 IndexedDBKey{"key3"},
1135 {"value3", /*external_objects=*/{}},
1136 /*index_key=*/std::nullopt,
1137 },
1138 },
1139 },
1140 /*get_all_parameters=*/
1141 {
1142 .result_type = blink::mojom::IDBGetAllResultType::Records,
1143 },
1144 expected_results));
1145}
1146
1147TEST_F(DatabaseOperationTest, IndexGetAllKeys) {
1148 const blink::mojom::IDBRecordPtr expected_results[] = {
1149 blink::mojom::IDBRecord::New(IndexedDBKey{"key3"},
1150 /*value=*/nullptr,
1151 /*index_key=*/std::nullopt),
1152 blink::mojom::IDBRecord::New(IndexedDBKey{"key2"},
1153 /*value=*/nullptr,
1154 /*index_key=*/std::nullopt),
1155 blink::mojom::IDBRecord::New(IndexedDBKey{"key1"},
1156 /*value=*/nullptr,
1157 /*index_key=*/std::nullopt),
1158 };
1159
1160 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1161 /*database_parameters=*/
1162 {
1163 /*object_store_parameters=*/
1164 {
1165 .object_store_id = kTestObjectStoreId,
1166 },
1167 /*index_parameters=*/
1168 {
1169 .index_id = kTestIndexId,
1170 },
1171 /*database_records=*/
1172 {
1173 {
1174 IndexedDBKey{"key1"},
1175 {"value1", /*external_objects=*/{}},
1176 IndexedDBKey("index_key3"),
1177 },
1178 {
1179 IndexedDBKey{"key2"},
1180 {"value2", /*external_objects=*/{}},
1181 IndexedDBKey("index_key2"),
1182 },
1183 {
1184 IndexedDBKey{"key3"},
1185 {"value3", /*external_objects=*/{}},
1186 IndexedDBKey("index_key1"),
1187 },
1188 },
1189 },
1190 /*get_all_parameters=*/
1191 {
1192 .result_type = blink::mojom::IDBGetAllResultType::Keys,
1193 },
1194 expected_results));
1195}
1196
1197TEST_F(DatabaseOperationTest, IndexGetAllValues) {
1198 const blink::mojom::IDBRecordPtr expected_results[] = {
1199 blink::mojom::IDBRecord::New(
1200 /*primary_key=*/std::nullopt,
1201 /*value=*/CreateIDBReturnValuePtr("value3"),
1202 /*index_key=*/std::nullopt),
1203 blink::mojom::IDBRecord::New(
1204 /*primary_key=*/std::nullopt,
1205 /*value=*/CreateIDBReturnValuePtr("value2"),
1206 /*index_key=*/std::nullopt),
1207 blink::mojom::IDBRecord::New(
1208 /*primary_key=*/std::nullopt,
1209 /*value=*/CreateIDBReturnValuePtr("value1"),
1210 /*index_key=*/std::nullopt),
1211 };
1212
1213 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1214 /*database_parameters=*/
1215 {
1216 /*object_store_parameters=*/
1217 {
1218 .object_store_id = kTestObjectStoreId,
1219 },
1220 /*index_parameters=*/
1221 {
1222 .index_id = kTestIndexId,
1223 },
1224 /*database_records=*/
1225 {
1226 {
1227 IndexedDBKey{"key1"},
1228 {"value1", /*external_objects=*/{}},
1229 IndexedDBKey("index_key3"),
1230 },
1231 {
1232 IndexedDBKey{"key2"},
1233 {"value2", /*external_objects=*/{}},
1234 IndexedDBKey("index_key2"),
1235 },
1236 {
1237 IndexedDBKey{"key3"},
1238 {"value3", /*external_objects=*/{}},
1239 IndexedDBKey("index_key1"),
1240 },
1241 },
1242 },
1243 /*get_all_parameters=*/
1244 {
1245 .result_type = blink::mojom::IDBGetAllResultType::Values,
1246 },
1247 expected_results));
1248}
1249
1250TEST_F(DatabaseOperationTest, IndexGetAllRecords) {
1251 const blink::mojom::IDBRecordPtr expected_results[] = {
1252 blink::mojom::IDBRecord::New(IndexedDBKey{"key3"},
1253 /*value=*/CreateIDBReturnValuePtr("value3"),
1254 IndexedDBKey{"index_key1"}),
1255 blink::mojom::IDBRecord::New(IndexedDBKey{"key2"},
1256 /*value=*/CreateIDBReturnValuePtr("value2"),
1257 IndexedDBKey{"index_key2"}),
1258 blink::mojom::IDBRecord::New(IndexedDBKey{"key1"},
1259 /*value=*/CreateIDBReturnValuePtr("value1"),
1260 IndexedDBKey{"index_key3"}),
1261 };
1262
1263 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1264 /*database_parameters=*/
1265 {
1266 /*object_store_parameters=*/
1267 {
1268 .object_store_id = kTestObjectStoreId,
1269 },
1270 /*index_parameters=*/
1271 {
1272 .index_id = kTestIndexId,
1273 },
1274 /*database_records=*/
1275 {
1276 {
1277 IndexedDBKey{"key1"},
1278 {"value1", /*external_objects=*/{}},
1279 IndexedDBKey("index_key3"),
1280 },
1281 {
1282 IndexedDBKey{"key2"},
1283 {"value2", /*external_objects=*/{}},
1284 IndexedDBKey("index_key2"),
1285 },
1286 {
1287 IndexedDBKey{"key3"},
1288 {"value3", /*external_objects=*/{}},
1289 IndexedDBKey("index_key1"),
1290 },
1291 },
1292 },
1293 /*get_all_parameters=*/
1294 {
1295 .result_type = blink::mojom::IDBGetAllResultType::Records,
1296 },
1297 expected_results));
1298}
1299
1300TEST_F(DatabaseOperationTest, ObjectStoreGetAllKeysWithRange) {
1301 const blink::mojom::IDBRecordPtr expected_results[] = {
1302 blink::mojom::IDBRecord::New(IndexedDBKey{"key2"},
1303 /*value=*/nullptr,
1304 /*index_key=*/std::nullopt),
1305 blink::mojom::IDBRecord::New(IndexedDBKey{"key3"},
1306 /*value=*/nullptr,
1307 /*index_key=*/std::nullopt),
1308 };
1309
1310 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1311 /*database_parameters=*/
1312 {
1313 /*object_store_parameters=*/
1314 {
1315 .object_store_id = kTestObjectStoreId,
1316 },
1317 /*index_parameters=*/{},
1318 /*database_records=*/
1319 {
1320 {
1321 IndexedDBKey{"key1"},
1322 {"value1", /*external_objects=*/{}},
1323 /*index_key=*/std::nullopt,
1324 },
1325 {
1326 IndexedDBKey{"key2"},
1327 {"value2", /*external_objects=*/{}},
1328 /*index_key=*/std::nullopt,
1329 },
1330 {
1331 IndexedDBKey{"key3"},
1332 {"value3", /*external_objects=*/{}},
1333 /*index_key=*/std::nullopt,
1334 },
1335 },
1336 },
1337 /*get_all_parameters=*/
1338 {
1339 .result_type = blink::mojom::IDBGetAllResultType::Keys,
1340 .key_range =
1341 {
1342 IndexedDBKey("key2"),
1343 IndexedDBKey("key9"),
1344 /*lower_open=*/false,
1345 /*upper_open=*/false,
1346 },
1347 },
1348 expected_results));
1349}
1350
1351TEST_F(DatabaseOperationTest, ObjectStoreGetAllKeysWithRangeThatDoesNotExist) {
1352 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1353 /*database_parameters=*/
1354 {
1355 /*object_store_parameters=*/
1356 {
1357 .object_store_id = kTestObjectStoreId,
1358 },
1359 /*index_parameters=*/{},
1360 /*database_records=*/
1361 {
1362 {
1363 IndexedDBKey{"key1"},
1364 {"value1", /*external_objects=*/{}},
1365 /*index_key=*/std::nullopt,
1366 },
1367 {
1368 IndexedDBKey{"key2"},
1369 {"value2", /*external_objects=*/{}},
1370 /*index_key=*/std::nullopt,
1371 },
1372 {
1373 IndexedDBKey{"key3"},
1374 {"value3", /*external_objects=*/{}},
1375 /*index_key=*/std::nullopt,
1376 },
1377 },
1378 },
1379 /*get_all_parameters=*/
1380 {
1381 .result_type = blink::mojom::IDBGetAllResultType::Keys,
1382 .key_range =
1383 {
1384 IndexedDBKey("key7"),
1385 IndexedDBKey("key9"),
1386 /*lower_open=*/false,
1387 /*upper_open=*/false,
1388 },
1389 },
1390 /*expected_results=*/{}));
1391}
1392
1393TEST_F(DatabaseOperationTest, ObjectStoreGetAllKeysWithInvalidRange) {
1394 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1395 /*database_parameters=*/
1396 {
1397 /*object_store_parameters=*/
1398 {
1399 .object_store_id = kTestObjectStoreId,
1400 },
1401 /*index_parameters=*/{},
1402 /*database_records=*/
1403 {
1404 {
1405 IndexedDBKey{"key1"},
1406 {"value1", /*external_objects=*/{}},
1407 /*index_key=*/std::nullopt,
1408 },
1409 {
1410 IndexedDBKey{"key2"},
1411 {"value2", /*external_objects=*/{}},
1412 /*index_key=*/std::nullopt,
1413 },
1414 {
1415 IndexedDBKey{"key3"},
1416 {"value3", /*external_objects=*/{}},
1417 /*index_key=*/std::nullopt,
1418 },
1419 },
1420 },
1421 /*get_all_parameters=*/
1422 {
1423 .result_type = blink::mojom::IDBGetAllResultType::Keys,
1424 .key_range =
1425 {
1426 IndexedDBKey("key9"),
1427 IndexedDBKey("key7"),
1428 /*lower_open=*/false,
1429 /*upper_open=*/false,
1430 },
1431 },
1432 /*expected_results=*/{}));
1433}
1434
1435TEST_F(DatabaseOperationTest, ObjectStoreGetAllKeysWithMaxCount) {
1436 const blink::mojom::IDBRecordPtr expected_results[] = {
1437 blink::mojom::IDBRecord::New(IndexedDBKey{"key1"},
1438 /*value=*/nullptr,
1439 /*index_key=*/std::nullopt),
1440 blink::mojom::IDBRecord::New(IndexedDBKey{"key2"},
1441 /*value=*/nullptr,
1442 /*index_key=*/std::nullopt),
1443 };
1444
1445 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1446 /*database_parameters=*/
1447 {
1448 /*object_store_parameters=*/
1449 {
1450 .object_store_id = kTestObjectStoreId,
1451 },
1452 /*index_parameters=*/{},
1453 /*database_records=*/
1454 {
1455 {
1456 IndexedDBKey{"key1"},
1457 {"value1", /*external_objects=*/{}},
1458 /*index_key=*/std::nullopt,
1459 },
1460 {
1461 IndexedDBKey{"key2"},
1462 {"value2", /*external_objects=*/{}},
1463 /*index_key=*/std::nullopt,
1464 },
1465 {
1466 IndexedDBKey{"key3"},
1467 {"value3", /*external_objects=*/{}},
1468 /*index_key=*/std::nullopt,
1469 },
1470 },
1471 },
1472 /*get_all_parameters=*/
1473 {
1474 .result_type = blink::mojom::IDBGetAllResultType::Keys,
1475 .max_count = 2,
1476 },
1477 expected_results));
1478}
1479
1480TEST_F(DatabaseOperationTest, ObjectStoreGetAllRecordsWithPrevDirection) {
1481 const blink::mojom::IDBRecordPtr expected_results[] = {
1482 blink::mojom::IDBRecord::New(IndexedDBKey{"key3"},
1483 /*value=*/CreateIDBReturnValuePtr("value3"),
1484 /*index_key=*/std::nullopt),
1485 blink::mojom::IDBRecord::New(IndexedDBKey{"key2"},
1486 /*value=*/CreateIDBReturnValuePtr("value2"),
1487 /*index_key=*/std::nullopt),
1488 blink::mojom::IDBRecord::New(IndexedDBKey{"key1"},
1489 /*value=*/CreateIDBReturnValuePtr("value1"),
1490 /*index_key=*/std::nullopt),
1491 };
1492
1493 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1494 /*database_parameters=*/
1495 {
1496 /*object_store_parameters=*/
1497 {
1498 .object_store_id = kTestObjectStoreId,
1499 },
1500 /*index_parameters=*/{},
1501 /*database_records=*/
1502 {
1503 {
1504 IndexedDBKey{"key1"},
1505 {"value1", /*external_objects=*/{}},
1506 /*index_key=*/std::nullopt,
1507 },
1508 {
1509 IndexedDBKey{"key2"},
1510 {"value2", /*external_objects=*/{}},
1511 /*index_key=*/std::nullopt,
1512 },
1513 {
1514 IndexedDBKey{"key3"},
1515 {"value3", /*external_objects=*/{}},
1516 /*index_key=*/std::nullopt,
1517 },
1518 },
1519 },
1520 /*get_all_parameters=*/
1521 {
1522 .result_type = blink::mojom::IDBGetAllResultType::Records,
1523 .direction = blink::mojom::IDBCursorDirection::Prev,
1524 },
1525 expected_results));
1526}
1527
1528TEST_F(DatabaseOperationTest, IndexGetAllRecordsWithNextNoDuplicateDirection) {
1529 const blink::mojom::IDBRecordPtr expected_results[] = {
1530 blink::mojom::IDBRecord::New(IndexedDBKey{"key1"},
1531 /*value=*/CreateIDBReturnValuePtr("value1"),
1532 IndexedDBKey{"index_key1"}),
1533 blink::mojom::IDBRecord::New(IndexedDBKey{"key2"},
1534 /*value=*/CreateIDBReturnValuePtr("value2"),
1535 IndexedDBKey{"index_key2"}),
1536 blink::mojom::IDBRecord::New(IndexedDBKey{"key4"},
1537 /*value=*/CreateIDBReturnValuePtr("value4"),
1538 IndexedDBKey{"index_key3"}),
1539 };
1540
1541 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1542 /*database_parameters=*/
1543 {
1544 /*object_store_parameters=*/
1545 {
1546 .object_store_id = kTestObjectStoreId,
1547 },
1548 /*index_parameters=*/
1549 {
1550 .index_id = kTestIndexId,
1551 },
1552 /*database_records=*/
1553 {
1554 {
1555 IndexedDBKey{"key1"},
1556 {"value1", /*external_objects=*/{}},
1557 IndexedDBKey("index_key1"),
1558 },
1559 {
1560 IndexedDBKey{"key2"},
1561 {"value2", /*external_objects=*/{}},
1562 IndexedDBKey("index_key2"),
1563 },
1564 {
1565 IndexedDBKey{"key3"},
1566 {"value3", /*external_objects=*/{}},
1567 IndexedDBKey("index_key2"),
1568 },
1569 {
1570 IndexedDBKey{"key4"},
1571 {"value4", /*external_objects=*/{}},
1572 IndexedDBKey("index_key3"),
1573 },
1574 {
1575 IndexedDBKey{"key5"},
1576 {"value5", /*external_objects=*/{}},
1577 IndexedDBKey("index_key3"),
1578 },
1579 {
1580 IndexedDBKey{"key6"},
1581 {"value6", /*external_objects=*/{}},
1582 IndexedDBKey("index_key3"),
1583 },
1584 },
1585 },
1586 /*get_all_parameters=*/
1587 {
1588 .result_type = blink::mojom::IDBGetAllResultType::Records,
1589 .direction = blink::mojom::IDBCursorDirection::NextNoDuplicate,
1590 },
1591 expected_results));
1592}
1593
1594TEST_F(DatabaseOperationTest, IndexGetAllRecordsWithPrevNoDuplicateDirection) {
1595 const blink::mojom::IDBRecordPtr expected_results[] = {
1596 blink::mojom::IDBRecord::New(IndexedDBKey{"key4"},
1597 /*value=*/CreateIDBReturnValuePtr("value4"),
1598 IndexedDBKey{"index_key3"}),
1599 blink::mojom::IDBRecord::New(IndexedDBKey{"key2"},
1600 /*value=*/CreateIDBReturnValuePtr("value2"),
1601 IndexedDBKey{"index_key2"}),
1602 blink::mojom::IDBRecord::New(IndexedDBKey{"key1"},
1603 /*value=*/CreateIDBReturnValuePtr("value1"),
1604 IndexedDBKey{"index_key1"}),
1605 };
1606
1607 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1608 /*database_parameters=*/
1609 {
1610 /*object_store_parameters=*/
1611 {
1612 .object_store_id = kTestObjectStoreId,
1613 },
1614 /*index_parameters=*/
1615 {
1616 .index_id = kTestIndexId,
1617 },
1618 /*database_records=*/
1619 {
1620 {
1621 IndexedDBKey{"key1"},
1622 {"value1", /*external_objects=*/{}},
1623 IndexedDBKey("index_key1"),
1624 },
1625 {
1626 IndexedDBKey{"key2"},
1627 {"value2", /*external_objects=*/{}},
1628 IndexedDBKey("index_key2"),
1629 },
1630 {
1631 IndexedDBKey{"key3"},
1632 {"value3", /*external_objects=*/{}},
1633 IndexedDBKey("index_key2"),
1634 },
1635 {
1636 IndexedDBKey{"key4"},
1637 {"value4", /*external_objects=*/{}},
1638 IndexedDBKey("index_key3"),
1639 },
1640 {
1641 IndexedDBKey{"key5"},
1642 {"value5", /*external_objects=*/{}},
1643 IndexedDBKey("index_key3"),
1644 },
1645 {
1646 IndexedDBKey{"key6"},
1647 {"value6", /*external_objects=*/{}},
1648 IndexedDBKey("index_key3"),
1649 },
1650 },
1651 },
1652 /*get_all_parameters=*/
1653 {
1654 .result_type = blink::mojom::IDBGetAllResultType::Records,
1655 .direction = blink::mojom::IDBCursorDirection::PrevNoDuplicate,
1656 },
1657 expected_results));
1658}
1659
1660TEST_F(DatabaseOperationTest, ObjectStoreGetAllKeysWithInvalidObjectStoreId) {
1661 ASSERT_EQ(0u, db_->metadata().object_stores.size());
1662
1663 // Call `Database::GetAllOperation` with an invalid object store id, which
1664 // must fail with an invalid argument status.
1665 FakeGetAllResultSink result_sink;
1666 blink::mojom::IDBDatabase::GetAllCallback get_all_callback = base::BindOnce(
1667 &FakeGetAllResultSink::BindReceiver, base::Unretained(&result_sink));
1668
1669 std::unique_ptr<Database::GetAllResultSinkWrapper> result_sink_wrapper =
1670 std::make_unique<Database::GetAllResultSinkWrapper>(
1671 transaction_->AsWeakPtr(), std::move(get_all_callback));
1672 result_sink_wrapper->UseDedicatedReceiverForTesting();
1673
1674 TestGetAllParameters get_all_parameters;
1675
Steve Becker4848af32024-10-29 22:57:191676 Status status = db_->GetAllOperation(
1677 kTestObjectStoreId,
1678 /*index_id=*/blink::IndexedDBIndexMetadata::kInvalidId,
Evan Stadeca999b12025-05-09 19:09:111679 std::move(get_all_parameters.key_range), get_all_parameters.result_type,
Steve Becker4848af32024-10-29 22:57:191680 get_all_parameters.max_count, get_all_parameters.direction,
1681 std::move(result_sink_wrapper), transaction_);
1682 ASSERT_TRUE(status.IsInvalidArgument()) << status.ToString();
1683
1684 // Verify that the result sink received an error.
1685 result_sink.WaitForResults();
1686 ASSERT_NE(result_sink.GetError(), nullptr);
1687 EXPECT_EQ(result_sink.GetError()->error_code,
1688 blink::mojom::IDBException::kUnknownError);
1689
1690 // Perform cleanup.
1691 transaction_->SetCommitFlag();
1692 transaction_ = nullptr;
1693 RunPostedTasks();
1694}
1695
1696TEST_F(DatabaseOperationTest, IndexGetAllKeysWithInvalidIndexId) {
1697 // Create an object store.
1698 ASSERT_EQ(0u, db_->metadata().object_stores.size());
Evan Stade540f03c82025-04-30 16:45:121699 Status status = transaction_->BackingStoreTransaction()->CreateObjectStore(
Steve Becker4848af32024-10-29 22:57:191700 kTestObjectStoreId, u"store", IndexedDBKeyPath(),
Evan Stade540f03c82025-04-30 16:45:121701 /*auto_increment=*/false);
Steve Becker4848af32024-10-29 22:57:191702 ASSERT_TRUE(status.ok()) << status.ToString();
1703 ASSERT_EQ(1u, db_->metadata().object_stores.size());
1704
1705 // Call `Database::GetAllOperation` with an invalid index id, which must fail
1706 // with an invalid argument status.
1707 FakeGetAllResultSink result_sink;
1708 blink::mojom::IDBDatabase::GetAllCallback get_all_callback = base::BindOnce(
1709 &FakeGetAllResultSink::BindReceiver, base::Unretained(&result_sink));
1710
1711 std::unique_ptr<Database::GetAllResultSinkWrapper> result_sink_wrapper =
1712 std::make_unique<Database::GetAllResultSinkWrapper>(
1713 transaction_->AsWeakPtr(), std::move(get_all_callback));
1714 result_sink_wrapper->UseDedicatedReceiverForTesting();
1715
1716 TestGetAllParameters get_all_parameters;
1717
Steve Becker4848af32024-10-29 22:57:191718 status = db_->GetAllOperation(
Evan Stadeca999b12025-05-09 19:09:111719 kTestObjectStoreId, kTestIndexId, std::move(get_all_parameters.key_range),
Steve Becker4848af32024-10-29 22:57:191720 get_all_parameters.result_type, get_all_parameters.max_count,
1721 get_all_parameters.direction, std::move(result_sink_wrapper),
1722 transaction_);
1723 ASSERT_TRUE(status.IsInvalidArgument()) << status.ToString();
1724
1725 // Verify that the result sink received an error.
1726 result_sink.WaitForResults();
1727 ASSERT_NE(result_sink.GetError(), nullptr);
1728 EXPECT_EQ(result_sink.GetError()->error_code,
1729 blink::mojom::IDBException::kUnknownError);
1730
1731 // Perform cleanup.
1732 transaction_->SetCommitFlag();
1733 transaction_ = nullptr;
1734 RunPostedTasks();
1735}
1736
1737TEST_F(DatabaseOperationTest,
1738 ObjectStoreGetAllRecordsWithMultipleResultChunks) {
1739 // Generate 2.5 chunks of results.
1740 const size_t record_count = (blink::mojom::kIDBGetAllChunkSize * 2) +
1741 (blink::mojom::kIDBGetAllChunkSize / 2);
1742
1743 std::vector<TestIDBRecord> database_records;
1744 std::vector<blink::mojom::IDBRecordPtr> expected_results;
1745
1746 for (size_t i = 0u; i < record_count; ++i) {
1747 const std::string primary_key = base::StringPrintf("key%zu", i);
1748 const std::string value = base::StringPrintf("value%zu", i);
1749
Evan Stade46c8dab2025-05-07 17:05:141750 database_records.emplace_back(IndexedDBKey{primary_key},
1751 IndexedDBValue{value, {}},
1752 /*index_key=*/std::nullopt);
Steve Becker4848af32024-10-29 22:57:191753
1754 expected_results.emplace_back(
1755 blink::mojom::IDBRecord::New(IndexedDBKey{primary_key},
1756 /*value=*/CreateIDBReturnValuePtr(value),
1757 /*index_key=*/std::nullopt));
1758 }
1759
1760 // Sort the expected results by primary key.
1761 std::sort(expected_results.begin(), expected_results.end(),
1762 [](const blink::mojom::IDBRecordPtr& left,
1763 const blink::mojom::IDBRecordPtr& right) {
1764 return left->primary_key->IsLessThan(*right->primary_key);
1765 });
1766
1767 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1768 /*database_parameters=*/
1769 {
1770 /*object_store_parameters=*/
1771 {
1772 .object_store_id = kTestObjectStoreId,
1773 },
1774 /*index_parameters=*/{},
1775 std::move(database_records),
1776 },
1777 /*get_all_parameters=*/
1778 {
1779 .result_type = blink::mojom::IDBGetAllResultType::Records,
1780 },
1781 expected_results));
1782}
1783
1784TEST_F(DatabaseOperationTest, IndexGetAllRecordsWithAutoIncrementingKeys) {
1785 const IndexedDBKeyPath object_store_key_path{u"id"};
1786
Arthur Sonzognid5ce01f72024-12-13 13:35:281787 const auto expected_generated_keys = std::to_array<IndexedDBKey>({
Steve Becker4848af32024-10-29 22:57:191788 IndexedDBKey(1.0, blink::mojom::IDBKeyType::Number),
1789 IndexedDBKey(2.0, blink::mojom::IDBKeyType::Number),
1790 IndexedDBKey(3.0, blink::mojom::IDBKeyType::Number),
Arthur Sonzognid5ce01f72024-12-13 13:35:281791 });
Steve Becker4848af32024-10-29 22:57:191792
1793 const blink::mojom::IDBRecordPtr expected_results[] = {
1794 blink::mojom::IDBRecord::New(
Evan Stadeca999b12025-05-09 19:09:111795 /*primary_key=*/expected_generated_keys[2].Clone(),
Steve Becker4848af32024-10-29 22:57:191796 /*value=*/
Evan Stadeca999b12025-05-09 19:09:111797 CreateIDBReturnValuePtr("value3", &expected_generated_keys[2],
Steve Becker4848af32024-10-29 22:57:191798 object_store_key_path),
1799 /*index_key=*/IndexedDBKey{"index_key1"}),
1800 blink::mojom::IDBRecord::New(
Evan Stadeca999b12025-05-09 19:09:111801 /*primary_key=*/expected_generated_keys[1].Clone(),
Steve Becker4848af32024-10-29 22:57:191802 /*value=*/
Evan Stadeca999b12025-05-09 19:09:111803 CreateIDBReturnValuePtr("value2", &expected_generated_keys[1],
Steve Becker4848af32024-10-29 22:57:191804 object_store_key_path),
1805 /*index_key=*/IndexedDBKey{"index_key2"}),
1806 blink::mojom::IDBRecord::New(
Evan Stadeca999b12025-05-09 19:09:111807 /*primary_key=*/expected_generated_keys[0].Clone(),
Steve Becker4848af32024-10-29 22:57:191808 /*value=*/
Evan Stadeca999b12025-05-09 19:09:111809 CreateIDBReturnValuePtr("value1", &expected_generated_keys[0],
Steve Becker4848af32024-10-29 22:57:191810 object_store_key_path),
1811 /*index_key=*/IndexedDBKey{"index_key3"}),
1812 };
1813
1814 ASSERT_NO_FATAL_FAILURE(TestGetAll(
1815 /*database_parameters=*/
1816 {
1817 /*object_store_parameters=*/
1818 {
1819 .object_store_id = kTestObjectStoreId,
1820 .key_path = object_store_key_path,
1821 .auto_increment = true,
1822 },
1823 /*index_parameters=*/
1824 {
1825 .index_id = kTestIndexId,
1826 },
1827 /*database_records=*/
1828 {
1829 {
1830 /*primary_key (generated)=*/IndexedDBKey(),
1831 {"value1", /*external_objects=*/{}},
1832 IndexedDBKey("index_key3"),
1833 },
1834 {
1835 /*primary_key (generated)=*/IndexedDBKey(),
1836 {"value2", /*external_objects=*/{}},
1837 IndexedDBKey("index_key2"),
1838 },
1839 {
1840 /*primary_key (generated)=*/IndexedDBKey(),
1841 {"value3", /*external_objects=*/{}},
1842 IndexedDBKey("index_key1"),
1843 },
1844 },
1845 },
1846 /*get_all_parameters=*/
1847 {
1848 .result_type = blink::mojom::IDBGetAllResultType::Records,
1849 },
1850 expected_results));
1851}
1852
Evan Stadecbb1e002024-09-13 20:06:571853} // namespace content::indexed_db