Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 5 | #include "content/browser/indexed_db/instance/database.h" |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 6 | |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 7 | #include <stdint.h> |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 8 | |
Arthur Sonzogni | d5ce01f7 | 2024-12-13 13:35:28 | [diff] [blame] | 9 | #include <array> |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 10 | #include <optional> |
[email protected] | 4cfd02d | 2014-06-11 18:08:40 | [diff] [blame] | 11 | #include <set> |
Jan Wilken Dörrie | ad587c3 | 2021-03-11 14:09:27 | [diff] [blame] | 12 | #include <string> |
dcheng | 36b6aec9 | 2015-12-26 06:16:36 | [diff] [blame] | 13 | #include <utility> |
[email protected] | 4cfd02d | 2014-06-11 18:08:40 | [diff] [blame] | 14 | |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 15 | #include "base/auto_reset.h" |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 16 | #include "base/containers/span.h" |
Ayu Ishii | fa35714 | 2022-12-22 02:11:27 | [diff] [blame] | 17 | #include "base/files/scoped_temp_dir.h" |
Avi Drissman | adac2199 | 2023-01-11 23:46:39 | [diff] [blame] | 18 | #include "base/functional/bind.h" |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 19 | #include "base/memory/raw_ptr.h" |
Victor Costan | 158ce94c | 2021-02-25 19:57:28 | [diff] [blame] | 20 | #include "base/memory/scoped_refptr.h" |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 21 | #include "base/run_loop.h" |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 22 | #include "base/sequence_checker.h" |
| 23 | #include "base/strings/stringprintf.h" |
Sean Maher | 52fa5a7 | 2022-11-14 15:53:25 | [diff] [blame] | 24 | #include "base/task/sequenced_task_runner.h" |
Sean Maher | 5b9af51f | 2022-11-21 15:32:47 | [diff] [blame] | 25 | #include "base/task/single_thread_task_runner.h" |
Evan Stade | 9dc3639 | 2024-10-29 13:10:39 | [diff] [blame] | 26 | #include "base/task/updateable_sequenced_task_runner.h" |
Guido Urdaneta | ef4e9194 | 2020-11-09 15:06:24 | [diff] [blame] | 27 | #include "base/test/bind.h" |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 28 | #include "base/test/gmock_callback_support.h" |
Chase Phillips | 5615c26 | 2019-07-29 21:42:38 | [diff] [blame] | 29 | #include "base/test/mock_callback.h" |
Adrienne Walker | 9439068 | 2020-02-26 01:08:30 | [diff] [blame] | 30 | #include "base/test/task_environment.h" |
Nathan Memmott | ca05bf75 | 2022-10-20 18:01:34 | [diff] [blame] | 31 | #include "components/services/storage/indexed_db/locks/partitioned_lock_manager.h" |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 32 | #include "components/services/storage/privileged/mojom/indexed_db_client_state_checker.mojom.h" |
Ari Chivukula | a62fcaeb | 2022-04-26 18:33:54 | [diff] [blame] | 33 | #include "components/services/storage/public/cpp/buckets/bucket_locator.h" |
Daniel Murphy | a6d1c4f9 | 2019-01-16 18:41:10 | [diff] [blame] | 34 | #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 35 | #include "content/browser/indexed_db/indexed_db_value.h" |
Evan Stade | 2ab4ae7 | 2025-04-18 17:58:44 | [diff] [blame] | 36 | #include "content/browser/indexed_db/instance/backing_store.h" |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 37 | #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 Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 44 | #include "content/browser/indexed_db/instance/mock_file_system_access_context.h" |
Evan Stade | 1a8d9d4 | 2024-09-10 19:37:19 | [diff] [blame] | 45 | #include "content/browser/indexed_db/instance/transaction.h" |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 46 | #include "content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h" |
Mingyu Lei | 0fe8df7 | 2022-12-16 06:44:48 | [diff] [blame] | 47 | #include "mojo/public/cpp/bindings/associated_remote.h" |
Ayu Ishii | fa35714 | 2022-12-22 02:11:27 | [diff] [blame] | 48 | #include "storage/browser/test/mock_quota_manager.h" |
Evan Stade | dfd3286 | 2023-09-12 21:51:53 | [diff] [blame] | 49 | #include "storage/browser/test/mock_quota_manager_proxy.h" |
[email protected] | d5516bfe | 2013-07-10 01:31:56 | [diff] [blame] | 50 | #include "testing/gtest/include/gtest/gtest.h" |
Ari Chivukula | 61873b7f | 2021-06-09 19:29:23 | [diff] [blame] | 51 | #include "third_party/blink/public/common/storage_key/storage_key.h" |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 52 | |
Chase Phillips | 33d161d6 | 2018-08-28 19:44:12 | [diff] [blame] | 53 | using blink::IndexedDBDatabaseMetadata; |
Chase Phillips | 68ecf551 | 2018-08-16 01:59:13 | [diff] [blame] | 54 | using blink::IndexedDBIndexKeys; |
| 55 | using blink::IndexedDBKey; |
Chase Phillips | 850b96f7 | 2018-08-24 19:44:16 | [diff] [blame] | 56 | using blink::IndexedDBKeyPath; |
[email protected] | 3295612 | 2013-12-25 07:29:24 | [diff] [blame] | 57 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 58 | namespace content::indexed_db { |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 59 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 60 | namespace { |
| 61 | constexpr int64_t kTestObjectStoreId = 1001; |
| 62 | constexpr int64_t kTestIndexId = 2002; |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 63 | constexpr char kTestForceCloseMessage[] = |
| 64 | "The database's connection is force-closed."; |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 65 | |
| 66 | // Contains a record's keys and value that tests use to populate the database. |
| 67 | struct TestIDBRecord { |
Evan Stade | 46c8dab | 2025-05-07 17:05:14 | [diff] [blame] | 68 | TestIDBRecord(IndexedDBKey primary_key, |
| 69 | const IndexedDBValue& value, |
| 70 | std::optional<IndexedDBKey> index_key) |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 71 | : primary_key(std::move(primary_key)), |
| 72 | value(value.Clone()), |
| 73 | index_key(std::move(index_key)) {} |
Evan Stade | 46c8dab | 2025-05-07 17:05:14 | [diff] [blame] | 74 | |
| 75 | TestIDBRecord(const TestIDBRecord& other) { |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 76 | primary_key = other.primary_key.Clone(); |
Evan Stade | 46c8dab | 2025-05-07 17:05:14 | [diff] [blame] | 77 | value = other.value.Clone(); |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 78 | if (other.index_key) { |
| 79 | index_key = other.index_key->Clone(); |
| 80 | } |
Evan Stade | 46c8dab | 2025-05-07 17:05:14 | [diff] [blame] | 81 | } |
| 82 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 83 | 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. |
| 91 | struct 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. |
| 101 | struct 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. |
| 112 | struct 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. |
| 120 | struct 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. |
| 134 | class 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 | |
| 217 | void 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 | |
| 228 | void 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 | |
| 239 | void 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. |
| 269 | blink::mojom::IDBReturnValuePtr CreateIDBReturnValuePtr( |
| 270 | const std::string& bits, |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 271 | const IndexedDBKey* primary_key = nullptr, |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 272 | 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 Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 276 | if (primary_key) { |
| 277 | result->primary_key = primary_key->Clone(); |
| 278 | } |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 279 | result->key_path = std::move(key_path); |
| 280 | return result; |
| 281 | } |
| 282 | |
| 283 | } // namespace |
| 284 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 285 | class DatabaseTest : public ::testing::Test { |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 286 | public: |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 287 | DatabaseTest() = default; |
Daniel Murphy | a6d1c4f9 | 2019-01-16 18:41:10 | [diff] [blame] | 288 | |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 289 | void SetUp() override { |
Ayu Ishii | fa35714 | 2022-12-22 02:11:27 | [diff] [blame] | 290 | ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
Ayu Ishii | fa35714 | 2022-12-22 02:11:27 | [diff] [blame] | 291 | quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>( |
| 292 | /*is_incognito=*/false, temp_dir_.GetPath(), |
| 293 | base::SingleThreadTaskRunner::GetCurrentDefault(), |
| 294 | /*special_storage_policy=*/nullptr); |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 295 | |
Evan Stade | dfd3286 | 2023-09-12 21:51:53 | [diff] [blame] | 296 | quota_manager_proxy_ = base::MakeRefCounted<storage::MockQuotaManagerProxy>( |
| 297 | quota_manager_.get(), |
| 298 | base::SingleThreadTaskRunner::GetCurrentDefault().get()); |
| 299 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 300 | BucketContext::Delegate delegate; |
| 301 | delegate.on_ready_for_destruction = |
| 302 | base::BindOnce(&DatabaseTest::OnBucketContextReadyForDestruction, |
| 303 | weak_factory_.GetWeakPtr()); |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 304 | |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 305 | 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 Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 311 | bucket_context_ = std::make_unique<BucketContext>( |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 312 | storage::BucketInfo(), temp_dir_.GetPath(), std::move(delegate), |
Evan Stade | 9dc3639 | 2024-10-29 13:10:39 | [diff] [blame] | 313 | scoped_refptr<base::UpdateableSequencedTaskRunner>(), |
Evan Stade | 21b63db | 2023-11-03 02:00:20 | [diff] [blame] | 314 | quota_manager_proxy_, |
Evan Stade | 6584a49 | 2023-09-25 21:02:30 | [diff] [blame] | 315 | /*blob_storage_context=*/mojo::NullRemote(), |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 316 | /*file_system_access_context=*/std::move(fsa_context)); |
Evan Stade | a35e272 | 2023-09-05 22:53:42 | [diff] [blame] | 317 | |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 318 | bucket_context_->InitBackingStoreIfNeeded(true); |
Abhishek Shanthkumar | 88ce490 | 2025-06-26 16:00:00 | [diff] [blame] | 319 | db_ = bucket_context_->CreateAndAddDatabase(u"db"); |
Daniel Murphy | 4c0f9c1 | 2019-05-23 01:14:35 | [diff] [blame] | 320 | } |
| 321 | |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 322 | void TearDown() override { db_ = nullptr; } |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 323 | |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 324 | 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 Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 332 | |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 333 | protected: |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 334 | base::test::TaskEnvironment task_environment_; |
| 335 | |
Ayu Ishii | fa35714 | 2022-12-22 02:11:27 | [diff] [blame] | 336 | base::ScopedTempDir temp_dir_; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 337 | std::unique_ptr<BucketContext> bucket_context_; |
Evan Stade | 822bdb4 | 2025-08-07 18:37:41 | [diff] [blame] | 338 | std::unique_ptr<test::MockFileSystemAccessContext> |
| 339 | file_system_access_context_; |
Ayu Ishii | fa35714 | 2022-12-22 02:11:27 | [diff] [blame] | 340 | scoped_refptr<storage::MockQuotaManager> quota_manager_; |
Evan Stade | dfd3286 | 2023-09-12 21:51:53 | [diff] [blame] | 341 | scoped_refptr<storage::MockQuotaManagerProxy> quota_manager_proxy_; |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 342 | |
Evan Stade | 5987219 | 2024-02-08 16:57:48 | [diff] [blame] | 343 | // As this is owned by `bucket_context_`, tests that cause the database to |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 344 | // be destroyed must manually reset this to null to avoid triggering dangling |
| 345 | // pointer warnings. |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 346 | raw_ptr<Database> db_ = nullptr; |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 347 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 348 | base::WeakPtrFactory<DatabaseTest> weak_factory_{this}; |
reillyg | 627e7f7 | 2016-10-20 05:12:43 | [diff] [blame] | 349 | }; |
| 350 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 351 | TEST_F(DatabaseTest, ConnectionLifecycle) { |
| 352 | MockMojoDatabaseCallbacks database_callbacks; |
| 353 | MockFactoryClient request1; |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 354 | const int64_t transaction_id1 = 1; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 355 | auto connection1 = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 356 | std::make_unique<ThunkFactoryClient>(request1), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 357 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 358 | database_callbacks.BindNewEndpointAndPassDedicatedRemote()), |
Evan Stade | f5433b8 | 2023-07-25 18:03:06 | [diff] [blame] | 359 | transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION, |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 360 | mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 361 | db_->ScheduleOpenConnection(std::move(connection1)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 362 | RunPostedTasks(); |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 363 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 364 | MockMojoDatabaseCallbacks database_callbacks2; |
| 365 | MockFactoryClient request2; |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 366 | const int64_t transaction_id2 = 2; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 367 | auto connection2 = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 368 | std::make_unique<ThunkFactoryClient>(request2), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 369 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 370 | database_callbacks2.BindNewEndpointAndPassDedicatedRemote()), |
Evan Stade | f5433b8 | 2023-07-25 18:03:06 | [diff] [blame] | 371 | transaction_id2, IndexedDBDatabaseMetadata::DEFAULT_VERSION, |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 372 | mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 373 | db_->ScheduleOpenConnection(std::move(connection2)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 374 | RunPostedTasks(); |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 375 | db_ = nullptr; |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 376 | |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 377 | EXPECT_TRUE(request1.connection()); |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 378 | request1.connection()->CloseAndReportForceClose(kTestForceCloseMessage); |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 379 | EXPECT_FALSE(request1.connection()->IsConnected()); |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 380 | |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 381 | EXPECT_TRUE(request2.connection()); |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 382 | request2.connection()->CloseAndReportForceClose(kTestForceCloseMessage); |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 383 | EXPECT_FALSE(request2.connection()->IsConnected()); |
[email protected] | 1c0f1227 | 2013-10-19 22:24:46 | [diff] [blame] | 384 | |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 385 | RunPostedTasks(); |
| 386 | |
Evan Stade | 9033294 | 2023-12-18 21:21:41 | [diff] [blame] | 387 | EXPECT_TRUE(bucket_context_->GetDatabasesForTesting().empty()); |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 388 | } |
| 389 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 390 | TEST_F(DatabaseTest, ForcedClose) { |
| 391 | MockMojoDatabaseCallbacks database_callbacks; |
| 392 | MockFactoryClient request; |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 393 | const int64_t upgrade_transaction_id = 3; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 394 | auto connection = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 395 | std::make_unique<ThunkFactoryClient>(request), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 396 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 397 | database_callbacks.BindNewEndpointAndPassDedicatedRemote()), |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 398 | upgrade_transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION, |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 399 | mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 400 | db_->ScheduleOpenConnection(std::move(connection)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 401 | RunPostedTasks(); |
| 402 | |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 403 | EXPECT_EQ(db_, request.connection()->database().get()); |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 404 | |
Steve Becker | 5cbfe65 | 2024-03-07 23:43:33 | [diff] [blame] | 405 | request.connection()->CreateTransaction( |
| 406 | mojo::NullAssociatedReceiver(), /*transaction_id=*/123, |
| 407 | /*object_store_ids=*/{}, blink::mojom::IDBTransactionMode::ReadOnly, |
| 408 | blink::mojom::IDBTransactionDurability::Relaxed); |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 409 | db_ = nullptr; |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 410 | |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 411 | base::RunLoop run_loop; |
| 412 | EXPECT_CALL(database_callbacks, ForcedClose) |
| 413 | .WillOnce(base::test::RunClosure(run_loop.QuitClosure())); |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 414 | request.connection()->CloseAndReportForceClose(kTestForceCloseMessage); |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 415 | run_loop.Run(); |
[email protected] | 26811ea | 2013-06-04 07:33:30 | [diff] [blame] | 416 | } |
| 417 | |
Victor Costan | 158ce94c | 2021-02-25 19:57:28 | [diff] [blame] | 418 | namespace { |
| 419 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 420 | class FakeFactoryClient : public FactoryClient { |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 421 | public: |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 422 | FakeFactoryClient() : FactoryClient(mojo::NullAssociatedRemote()) {} |
| 423 | ~FakeFactoryClient() override = default; |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 424 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 425 | FakeFactoryClient(const FakeFactoryClient&) = delete; |
| 426 | FakeFactoryClient& operator=(const FakeFactoryClient&) = delete; |
Peter Boström | 9b03653 | 2021-10-28 23:37:28 | [diff] [blame] | 427 | |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 428 | void OnBlocked(int64_t existing_version) override { blocked_called_ = true; } |
Evan Stade | abae4f6 | 2023-07-28 21:08:15 | [diff] [blame] | 429 | void OnDeleteSuccess(int64_t old_version) override { success_called_ = true; } |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 430 | void OnError(const DatabaseError& error) override { error_called_ = true; } |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 431 | |
| 432 | bool blocked_called() const { return blocked_called_; } |
[email protected] | 7227371 | 2014-04-30 19:50:11 | [diff] [blame] | 433 | bool success_called() const { return success_called_; } |
jsbell | 94384e5 | 2016-10-04 17:19:58 | [diff] [blame] | 434 | bool error_called() const { return error_called_; } |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 435 | |
| 436 | private: |
jsbell | 94384e5 | 2016-10-04 17:19:58 | [diff] [blame] | 437 | bool blocked_called_ = false; |
| 438 | bool success_called_ = false; |
| 439 | bool error_called_ = false; |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 440 | }; |
| 441 | |
Victor Costan | 158ce94c | 2021-02-25 19:57:28 | [diff] [blame] | 442 | } // namespace |
| 443 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 444 | TEST_F(DatabaseTest, PendingDelete) { |
| 445 | MockFactoryClient request1; |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 446 | const int64_t transaction_id1 = 1; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 447 | MockMojoDatabaseCallbacks database_callbacks1; |
| 448 | auto connection = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 449 | std::make_unique<ThunkFactoryClient>(request1), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 450 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 451 | database_callbacks1.BindNewEndpointAndPassDedicatedRemote()), |
Evan Stade | f5433b8 | 2023-07-25 18:03:06 | [diff] [blame] | 452 | transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION, |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 453 | mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 454 | db_->ScheduleOpenConnection(std::move(connection)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 455 | RunPostedTasks(); |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 456 | |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 457 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 458 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL); |
| 459 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL); |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 460 | |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 461 | base::RunLoop run_loop; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 462 | FakeFactoryClient request2; |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 463 | db_->ScheduleDeleteDatabase(std::make_unique<ThunkFactoryClient>(request2), |
| 464 | run_loop.QuitClosure()); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 465 | RunPostedTasks(); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 466 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 467 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL); |
| 468 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL); |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 469 | |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 470 | EXPECT_FALSE(request2.blocked_called()); |
| 471 | request1.connection()->VersionChangeIgnored(); |
| 472 | EXPECT_TRUE(request2.blocked_called()); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 473 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 474 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL); |
| 475 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL); |
[email protected] | 75a854a | 2014-07-07 15:57:36 | [diff] [blame] | 476 | |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 477 | db_->ForceCloseAndRunTasks(kTestForceCloseMessage); |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 478 | db_ = nullptr; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 479 | |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 480 | run_loop.Run(); |
Daniel Murphy | 4c0f9c1 | 2019-05-23 01:14:35 | [diff] [blame] | 481 | EXPECT_FALSE(db_); |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 482 | |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 483 | EXPECT_TRUE(request2.success_called()); |
[email protected] | 09bda0f | 2013-07-11 08:01:21 | [diff] [blame] | 484 | } |
| 485 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 486 | TEST_F(DatabaseTest, OpenDeleteClear) { |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 487 | const int64_t kDatabaseVersion = 1; |
| 488 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 489 | MockFactoryClient request1( |
Victor Costan | 158ce94c | 2021-02-25 19:57:28 | [diff] [blame] | 490 | /*expect_connection=*/true); |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 491 | MockMojoDatabaseCallbacks database_callbacks1; |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 492 | const int64_t transaction_id1 = 1; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 493 | auto connection1 = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 494 | std::make_unique<ThunkFactoryClient>(request1), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 495 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 496 | database_callbacks1.BindNewEndpointAndPassDedicatedRemote()), |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 497 | transaction_id1, kDatabaseVersion, mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 498 | db_->ScheduleOpenConnection(std::move(connection1)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 499 | RunPostedTasks(); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 500 | |
| 501 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 502 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL); |
| 503 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 504 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 505 | MockFactoryClient request2( |
Victor Costan | 158ce94c | 2021-02-25 19:57:28 | [diff] [blame] | 506 | /*expect_connection=*/false); |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 507 | MockMojoDatabaseCallbacks database_callbacks2; |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 508 | const int64_t transaction_id2 = 2; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 509 | auto connection2 = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 510 | std::make_unique<ThunkFactoryClient>(request2), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 511 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 512 | database_callbacks2.BindNewEndpointAndPassDedicatedRemote()), |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 513 | transaction_id2, kDatabaseVersion, mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 514 | db_->ScheduleOpenConnection(std::move(connection2)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 515 | RunPostedTasks(); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 516 | |
| 517 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 518 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL); |
| 519 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 1UL); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 520 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 521 | MockFactoryClient request3( |
Victor Costan | 158ce94c | 2021-02-25 19:57:28 | [diff] [blame] | 522 | /*expect_connection=*/false); |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 523 | MockMojoDatabaseCallbacks database_callbacks3; |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 524 | const int64_t transaction_id3 = 3; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 525 | auto connection3 = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 526 | std::make_unique<ThunkFactoryClient>(request3), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 527 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 528 | database_callbacks3.BindNewEndpointAndPassDedicatedRemote()), |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 529 | transaction_id3, kDatabaseVersion, mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 530 | db_->ScheduleOpenConnection(std::move(connection3)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 531 | RunPostedTasks(); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 532 | |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 533 | EXPECT_TRUE(request1.upgrade_called()); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 534 | |
| 535 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 536 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL); |
| 537 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 2UL); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 538 | |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 539 | EXPECT_CALL(database_callbacks1, ForcedClose); |
| 540 | EXPECT_CALL(database_callbacks2, ForcedClose); |
| 541 | EXPECT_CALL(database_callbacks3, ForcedClose); |
| 542 | |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 543 | db_->ForceCloseAndRunTasks(kTestForceCloseMessage); |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 544 | db_ = nullptr; |
| 545 | database_callbacks1.FlushForTesting(); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 546 | |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 547 | EXPECT_TRUE(request1.error_called()); |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 548 | EXPECT_TRUE(request2.error_called()); |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 549 | EXPECT_TRUE(request3.error_called()); |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 550 | } |
| 551 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 552 | TEST_F(DatabaseTest, ForceDelete) { |
| 553 | MockFactoryClient request1; |
| 554 | MockMojoDatabaseCallbacks database_callbacks; |
eostroukhov | 1470b1f | 2017-01-23 21:13:53 | [diff] [blame] | 555 | const int64_t transaction_id1 = 1; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 556 | auto connection = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 557 | std::make_unique<ThunkFactoryClient>(request1), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 558 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 559 | database_callbacks.BindNewEndpointAndPassDedicatedRemote()), |
Evan Stade | f5433b8 | 2023-07-25 18:03:06 | [diff] [blame] | 560 | transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION, |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 561 | mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 562 | db_->ScheduleOpenConnection(std::move(connection)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 563 | RunPostedTasks(); |
eostroukhov | 1470b1f | 2017-01-23 21:13:53 | [diff] [blame] | 564 | |
dmurph | 497e676f1 | 2017-04-25 20:29:57 | [diff] [blame] | 565 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 566 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL); |
| 567 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL); |
eostroukhov | 1470b1f | 2017-01-23 21:13:53 | [diff] [blame] | 568 | |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 569 | base::RunLoop run_loop; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 570 | FakeFactoryClient request2; |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 571 | db_->ScheduleDeleteDatabase(std::make_unique<ThunkFactoryClient>(request2), |
| 572 | run_loop.QuitClosure()); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 573 | RunPostedTasks(); |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 574 | EXPECT_FALSE(run_loop.AnyQuitCalled()); |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 575 | db_->ForceCloseAndRunTasks(kTestForceCloseMessage); |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 576 | db_ = nullptr; |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 577 | run_loop.Run(); |
Daniel Murphy | 4c0f9c1 | 2019-05-23 01:14:35 | [diff] [blame] | 578 | EXPECT_FALSE(db_); |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 579 | EXPECT_FALSE(request2.blocked_called()); |
| 580 | EXPECT_TRUE(request2.success_called()); |
eostroukhov | 1470b1f | 2017-01-23 21:13:53 | [diff] [blame] | 581 | } |
| 582 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 583 | TEST_F(DatabaseTest, ForceCloseWhileOpenPending) { |
Daniel Murphy | eaf2e8bc | 2019-03-14 03:23:36 | [diff] [blame] | 584 | // Verify that pending connection requests are handled correctly during a |
| 585 | // ForceClose. |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 586 | MockFactoryClient request1; |
| 587 | MockMojoDatabaseCallbacks database_callbacks1; |
Daniel Murphy | eaf2e8bc | 2019-03-14 03:23:36 | [diff] [blame] | 588 | const int64_t transaction_id1 = 1; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 589 | auto connection1 = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 590 | std::make_unique<ThunkFactoryClient>(request1), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 591 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 592 | database_callbacks1.BindNewEndpointAndPassDedicatedRemote()), |
Evan Stade | f5433b8 | 2023-07-25 18:03:06 | [diff] [blame] | 593 | transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION, |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 594 | mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 595 | db_->ScheduleOpenConnection(std::move(connection1)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 596 | RunPostedTasks(); |
Daniel Murphy | eaf2e8bc | 2019-03-14 03:23:36 | [diff] [blame] | 597 | |
| 598 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 599 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL); |
| 600 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL); |
Daniel Murphy | eaf2e8bc | 2019-03-14 03:23:36 | [diff] [blame] | 601 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 602 | MockFactoryClient request2(/*expect_connection=*/false); |
| 603 | MockMojoDatabaseCallbacks database_callbacks2; |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 604 | |
Daniel Murphy | eaf2e8bc | 2019-03-14 03:23:36 | [diff] [blame] | 605 | const int64_t transaction_id2 = 2; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 606 | auto connection2 = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 607 | std::make_unique<ThunkFactoryClient>(request2), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 608 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 609 | database_callbacks2.BindNewEndpointAndPassDedicatedRemote()), |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 610 | transaction_id2, 3, mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 611 | db_->ScheduleOpenConnection(std::move(connection2)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 612 | RunPostedTasks(); |
Daniel Murphy | eaf2e8bc | 2019-03-14 03:23:36 | [diff] [blame] | 613 | |
| 614 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 615 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL); |
| 616 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL); |
Daniel Murphy | eaf2e8bc | 2019-03-14 03:23:36 | [diff] [blame] | 617 | |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 618 | db_->ForceCloseAndRunTasks(kTestForceCloseMessage); |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 619 | db_ = nullptr; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 620 | RunPostedTasks(); |
Daniel Murphy | 4c0f9c1 | 2019-05-23 01:14:35 | [diff] [blame] | 621 | EXPECT_FALSE(db_); |
Daniel Murphy | eaf2e8bc | 2019-03-14 03:23:36 | [diff] [blame] | 622 | } |
| 623 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 624 | TEST_F(DatabaseTest, ForceCloseWhileOpenAndDeletePending) { |
Daniel Murphy | 8ae1a64b | 2019-05-24 00:56:59 | [diff] [blame] | 625 | // Verify that pending connection requests are handled correctly during a |
| 626 | // ForceClose. |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 627 | MockFactoryClient request1; |
| 628 | MockMojoDatabaseCallbacks database_callbacks1; |
Daniel Murphy | 8ae1a64b | 2019-05-24 00:56:59 | [diff] [blame] | 629 | const int64_t transaction_id1 = 1; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 630 | auto connection1 = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 631 | std::make_unique<ThunkFactoryClient>(request1), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 632 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 633 | database_callbacks1.BindNewEndpointAndPassDedicatedRemote()), |
Evan Stade | f5433b8 | 2023-07-25 18:03:06 | [diff] [blame] | 634 | transaction_id1, IndexedDBDatabaseMetadata::DEFAULT_VERSION, |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 635 | mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 636 | db_->ScheduleOpenConnection(std::move(connection1)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 637 | RunPostedTasks(); |
Daniel Murphy | 8ae1a64b | 2019-05-24 00:56:59 | [diff] [blame] | 638 | |
| 639 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 640 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 0UL); |
| 641 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 0UL); |
| 642 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 643 | MockFactoryClient request2(false); |
| 644 | MockMojoDatabaseCallbacks database_callbacks2; |
Daniel Murphy | 8ae1a64b | 2019-05-24 00:56:59 | [diff] [blame] | 645 | const int64_t transaction_id2 = 2; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 646 | auto connection2 = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 647 | std::make_unique<ThunkFactoryClient>(request2), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 648 | std::make_unique<DatabaseCallbacks>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 649 | database_callbacks2.BindNewEndpointAndPassDedicatedRemote()), |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 650 | transaction_id2, 3, mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 651 | db_->ScheduleOpenConnection(std::move(connection2)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 652 | RunPostedTasks(); |
Daniel Murphy | 8ae1a64b | 2019-05-24 00:56:59 | [diff] [blame] | 653 | |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 654 | base::RunLoop run_loop; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 655 | auto request3 = std::make_unique<FakeFactoryClient>(); |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 656 | db_->ScheduleDeleteDatabase(std::move(request3), run_loop.QuitClosure()); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 657 | RunPostedTasks(); |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 658 | EXPECT_FALSE(run_loop.AnyQuitCalled()); |
Daniel Murphy | 8ae1a64b | 2019-05-24 00:56:59 | [diff] [blame] | 659 | |
| 660 | EXPECT_EQ(db_->ConnectionCount(), 1UL); |
| 661 | EXPECT_EQ(db_->ActiveOpenDeleteCount(), 1UL); |
| 662 | EXPECT_EQ(db_->PendingOpenDeleteCount(), 1UL); |
| 663 | |
Mingyu Lei | 87210bc | 2025-04-17 09:35:50 | [diff] [blame] | 664 | db_->ForceCloseAndRunTasks(kTestForceCloseMessage); |
Evan Stade | 0c0e6d65 | 2023-11-09 23:28:03 | [diff] [blame] | 665 | db_ = nullptr; |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 666 | run_loop.Run(); |
Daniel Murphy | 8ae1a64b | 2019-05-24 00:56:59 | [diff] [blame] | 667 | } |
| 668 | |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 669 | Status DummyOperation(Transaction* transaction) { |
| 670 | return Status::OK(); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 671 | } |
| 672 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 673 | class DatabaseOperationTest : public DatabaseTest { |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 674 | public: |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 675 | DatabaseOperationTest() = default; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 676 | DatabaseOperationTest(const DatabaseOperationTest&) = delete; |
| 677 | DatabaseOperationTest& operator=(const DatabaseOperationTest&) = delete; |
Peter Boström | 9b03653 | 2021-10-28 23:37:28 | [diff] [blame] | 678 | |
dcheng | fa85b15 | 2014-10-28 01:13:42 | [diff] [blame] | 679 | void SetUp() override { |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 680 | DatabaseTest::SetUp(); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 681 | |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 682 | const int64_t transaction_id = 1; |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 683 | auto connection = std::make_unique<PendingConnection>( |
Evan Stade | c24dbfe9 | 2023-11-01 20:04:34 | [diff] [blame] | 684 | std::make_unique<ThunkFactoryClient>(request_), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 685 | std::make_unique<DatabaseCallbacks>(mojo::NullAssociatedRemote()), |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 686 | transaction_id, IndexedDBDatabaseMetadata::DEFAULT_VERSION, |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 687 | mojo::NullAssociatedReceiver()); |
Evan Stade | 9f5e401c | 2024-01-04 23:58:35 | [diff] [blame] | 688 | db_->ScheduleOpenConnection(std::move(connection)); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 689 | RunPostedTasks(); |
jsbell | e9c26d7 | 2016-02-24 21:23:37 | [diff] [blame] | 690 | EXPECT_EQ(IndexedDBDatabaseMetadata::NO_VERSION, db_->metadata().version); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 691 | |
Evan Stade | 83334392 | 2023-07-05 21:09:51 | [diff] [blame] | 692 | EXPECT_TRUE(request_.connection()); |
Guido Urdaneta | 1651138 | 2023-10-25 17:40:04 | [diff] [blame] | 693 | transaction_ = request_.connection()->CreateVersionChangeTransaction( |
Joshua Bell | 2813278 | 2021-03-15 18:54:22 | [diff] [blame] | 694 | transaction_id, /*scope=*/std::set<int64_t>(), |
Evan Stade | cc645c8 | 2025-04-02 17:26:49 | [diff] [blame] | 695 | std::make_unique<FakeTransaction>( |
Evan Stade | 2fbd453 | 2025-04-30 10:19:22 | [diff] [blame] | 696 | commit_success_, |
| 697 | db_->backing_store_db()->CreateTransaction( |
| 698 | blink::mojom::IDBTransactionDurability::Relaxed, |
| 699 | blink::mojom::IDBTransactionMode::VersionChange))); |
Evan Stade | 8707309 | 2024-01-12 03:53:23 | [diff] [blame] | 700 | |
| 701 | std::vector<PartitionedLockManager::PartitionedLockRequest> lock_requests = |
Abhishek Shanthkumar | 88ce490 | 2025-06-26 16:00:00 | [diff] [blame] | 702 | db_->BuildLockRequestsForTransaction( |
| 703 | blink::mojom::IDBTransactionMode::VersionChange, /*scope=*/{}); |
Evan Stade | 22f9c264 | 2024-02-04 00:35:28 | [diff] [blame] | 704 | db_->lock_manager().AcquireLocks( |
Evan Stade | d9055a7 | 2024-08-22 23:11:27 | [diff] [blame] | 705 | std::move(lock_requests), *transaction_->mutable_locks_receiver(), |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 706 | base::BindOnce(&Transaction::Start, transaction_->AsWeakPtr())); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 707 | |
| 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. |
jsbell | fd99b4a | 2017-06-20 19:55:13 | [diff] [blame] | 711 | transaction_->ScheduleTask(base::BindOnce(&DummyOperation)); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 712 | // Run posted tasks to execute the dummy operation and ensure that it is |
| 713 | // stored in the connection. |
| 714 | RunPostedTasks(); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 715 | } |
| 716 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 717 | // 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 Stade | 46c8dab | 2025-05-07 17:05:14 | [diff] [blame] | 721 | TestDatabaseParameters database_parameters, |
| 722 | TestGetAllParameters get_all_parameters, |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 723 | 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 Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 729 | Status status = transaction_->BackingStoreTransaction()->CreateObjectStore( |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 730 | store_id, object_store_parameters.name, |
| 731 | object_store_parameters.key_path, |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 732 | object_store_parameters.auto_increment); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 733 | 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 Stade | 73a3dfa | 2025-05-21 21:22:14 | [diff] [blame] | 737 | 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 Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 744 | const bool has_index = |
Evan Stade | 73a3dfa | 2025-05-21 21:22:14 | [diff] [blame] | 745 | index_id != blink::IndexedDBIndexMetadata::kInvalidId; |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 746 | if (has_index) { |
Evan Stade | 73a3dfa | 2025-05-21 21:22:14 | [diff] [blame] | 747 | status = |
| 748 | transaction_->BackingStoreTransaction()->CreateIndex(store_id, index); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 749 | } |
| 750 | EXPECT_TRUE(status.ok()) << status.ToString(); |
| 751 | |
| 752 | // Populate the object store and optionally the index with the provided |
| 753 | // records. |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 754 | for (TestIDBRecord& record : database_parameters.records) { |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 755 | std::vector<IndexedDBIndexKeys> index_keys; |
| 756 | ASSERT_EQ(record.index_key.has_value(), has_index); |
| 757 | if (has_index) { |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 758 | IndexedDBIndexKeys index_key{index_id, {}}; |
| 759 | index_key.keys.emplace_back(std::move(*record.index_key)); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 760 | 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 Stade | 3b9078f | 2025-05-07 16:14:30 | [diff] [blame] | 769 | transaction_->in_flight_memory_ += 1000; |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 770 | |
Evan Stade | 46c8dab | 2025-05-07 17:05:14 | [diff] [blame] | 771 | status = transaction_->DoPut( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 772 | store_id, record.value.Clone(), std::move(record.primary_key), |
Evan Stade | 46c8dab | 2025-05-07 17:05:14 | [diff] [blame] | 773 | blink::mojom::IDBPutMode::AddOnly, std::move(index_keys), |
| 774 | callback.Get(), transaction_); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 775 | 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 Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 788 | 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 Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 793 | 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] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 828 | protected: |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 829 | MockFactoryClient request_; |
Tanuj Martolia | 5f5bd99 | 2024-05-31 05:09:25 | [diff] [blame] | 830 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 831 | // As this is owned by `Connection`, tests that cause the transaction |
Tanuj Martolia | 5f5bd99 | 2024-05-31 05:09:25 | [diff] [blame] | 832 | // to be committed must manually reset this to null to avoid triggering |
| 833 | // dangling pointer warnings. |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 834 | raw_ptr<Transaction> transaction_ = nullptr; |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 835 | Status commit_success_; |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 836 | }; |
| 837 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 838 | TEST_F(DatabaseOperationTest, CreateObjectStore) { |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 839 | EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 840 | const int64_t store_id = 1001; |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 841 | Status s = transaction_->BackingStoreTransaction()->CreateObjectStore( |
| 842 | store_id, u"store", IndexedDBKeyPath(), |
| 843 | /*auto_increment=*/false); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 844 | EXPECT_TRUE(s.ok()); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 845 | transaction_->SetCommitFlag(); |
Tanuj Martolia | 5f5bd99 | 2024-05-31 05:09:25 | [diff] [blame] | 846 | transaction_ = nullptr; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 847 | RunPostedTasks(); |
Evan Stade | 5987219 | 2024-02-08 16:57:48 | [diff] [blame] | 848 | EXPECT_TRUE(bucket_context_); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 849 | EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); |
| 850 | } |
| 851 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 852 | TEST_F(DatabaseOperationTest, CreateIndex) { |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 853 | EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 854 | const int64_t store_id = 1001; |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 855 | Status s = transaction_->BackingStoreTransaction()->CreateObjectStore( |
| 856 | store_id, u"store", IndexedDBKeyPath(), |
| 857 | /*auto_increment=*/false); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 858 | EXPECT_TRUE(s.ok()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 859 | EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 860 | const int64_t index_id = 2002; |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 861 | s = transaction_->BackingStoreTransaction()->CreateIndex( |
Evan Stade | 73a3dfa | 2025-05-21 21:22:14 | [diff] [blame] | 862 | store_id, blink::IndexedDBIndexMetadata( |
| 863 | u"index", index_id, IndexedDBKeyPath(), /*unique=*/false, |
| 864 | /*multi_entry=*/false)); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 865 | EXPECT_TRUE(s.ok()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 866 | EXPECT_EQ( |
| 867 | 1ULL, |
| 868 | db_->metadata().object_stores.find(store_id)->second.indexes.size()); |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 869 | transaction_->SetCommitFlag(); |
Tanuj Martolia | 5f5bd99 | 2024-05-31 05:09:25 | [diff] [blame] | 870 | transaction_ = nullptr; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 871 | RunPostedTasks(); |
Evan Stade | 5987219 | 2024-02-08 16:57:48 | [diff] [blame] | 872 | EXPECT_TRUE(bucket_context_); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 873 | 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 Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 879 | class DatabaseOperationAbortTest : public DatabaseOperationTest { |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 880 | public: |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 881 | DatabaseOperationAbortTest() { |
Mike Wasserman | 0d5da52 | 2024-09-27 07:47:03 | [diff] [blame] | 882 | commit_success_ = Status::NotFound("Bummer."); |
[email protected] | 67bb75b9 | 2014-06-04 00:34:10 | [diff] [blame] | 883 | } |
[email protected] | e8ca0f5 | 2014-06-07 08:46:34 | [diff] [blame] | 884 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 885 | DatabaseOperationAbortTest(const DatabaseOperationAbortTest&) = delete; |
| 886 | DatabaseOperationAbortTest& operator=(const DatabaseOperationAbortTest&) = |
| 887 | delete; |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 888 | }; |
| 889 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 890 | TEST_F(DatabaseOperationAbortTest, CreateObjectStore) { |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 891 | EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 892 | const int64_t store_id = 1001; |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 893 | Status s = transaction_->BackingStoreTransaction()->CreateObjectStore( |
| 894 | store_id, u"store", IndexedDBKeyPath(), |
| 895 | /*auto_increment=*/false); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 896 | EXPECT_TRUE(s.ok()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 897 | EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); |
Evan Stade | 5987219 | 2024-02-08 16:57:48 | [diff] [blame] | 898 | db_ = nullptr; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 899 | transaction_->SetCommitFlag(); |
| 900 | RunPostedTasks(); |
Evan Stade | 5987219 | 2024-02-08 16:57:48 | [diff] [blame] | 901 | // A transaction error results in a deleted db. |
| 902 | EXPECT_TRUE(bucket_context_->GetDatabasesForTesting().empty()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 903 | } |
| 904 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 905 | TEST_F(DatabaseOperationAbortTest, CreateIndex) { |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 906 | EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 907 | const int64_t store_id = 1001; |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 908 | Status s = transaction_->BackingStoreTransaction()->CreateObjectStore( |
| 909 | store_id, u"store", IndexedDBKeyPath(), |
| 910 | /*auto_increment=*/false); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 911 | EXPECT_TRUE(s.ok()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 912 | EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 913 | const int64_t index_id = 2002; |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 914 | s = transaction_->BackingStoreTransaction()->CreateIndex( |
Evan Stade | 73a3dfa | 2025-05-21 21:22:14 | [diff] [blame] | 915 | store_id, blink::IndexedDBIndexMetadata( |
| 916 | u"index", index_id, IndexedDBKeyPath(), /*unique=*/false, |
| 917 | /*multi_entry=*/false)); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 918 | EXPECT_TRUE(s.ok()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 919 | EXPECT_EQ( |
| 920 | 1ULL, |
| 921 | db_->metadata().object_stores.find(store_id)->second.indexes.size()); |
Evan Stade | 5987219 | 2024-02-08 16:57:48 | [diff] [blame] | 922 | db_ = nullptr; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 923 | transaction_->SetCommitFlag(); |
| 924 | RunPostedTasks(); |
Evan Stade | 5987219 | 2024-02-08 16:57:48 | [diff] [blame] | 925 | // A transaction error results in a deleted db. |
| 926 | EXPECT_TRUE(bucket_context_->GetDatabasesForTesting().empty()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 927 | } |
| 928 | |
Evan Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 929 | TEST_F(DatabaseOperationTest, CreatePutDelete) { |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 930 | EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); |
avi | b734894 | 2015-12-25 20:57:10 | [diff] [blame] | 931 | const int64_t store_id = 1001; |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 932 | |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 933 | Status s = transaction_->BackingStoreTransaction()->CreateObjectStore( |
| 934 | store_id, u"store", IndexedDBKeyPath(), |
| 935 | /*auto_increment=*/false); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 936 | EXPECT_TRUE(s.ok()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 937 | EXPECT_EQ(1ULL, db_->metadata().object_stores.size()); |
| 938 | |
Chase Phillips | 5615c26 | 2019-07-29 21:42:38 | [diff] [blame] | 939 | base::MockCallback<blink::mojom::IDBTransaction::PutCallback> callback; |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 940 | |
Austin Sullivan | da22651 | 2020-10-01 19:42:48 | [diff] [blame] | 941 | // Set in-flight memory to a reasonably large number to prevent underflow in |
Ari Chivukula | fae9b808 | 2022-04-14 22:27:29 | [diff] [blame] | 942 | // `PutOperation` |
Evan Stade | 3b9078f | 2025-05-07 16:14:30 | [diff] [blame] | 943 | transaction_->in_flight_memory_ += 1000; |
Austin Sullivan | da22651 | 2020-10-01 19:42:48 | [diff] [blame] | 944 | |
Evan Stade | 3b9078f | 2025-05-07 16:14:30 | [diff] [blame] | 945 | s = transaction_->DoPut( |
| 946 | store_id, IndexedDBValue("value1", {}), IndexedDBKey("key"), |
| 947 | blink::mojom::IDBPutMode::AddOnly, std::vector<IndexedDBIndexKeys>(), |
| 948 | callback.Get(), transaction_); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 949 | EXPECT_TRUE(s.ok()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 950 | |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 951 | s = transaction_->BackingStoreTransaction()->DeleteObjectStore(store_id); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 952 | EXPECT_TRUE(s.ok()); |
| 953 | |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 954 | EXPECT_EQ(0ULL, db_->metadata().object_stores.size()); |
[email protected] | 41db22974 | 2014-05-31 22:17:51 | [diff] [blame] | 955 | |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 956 | transaction_->SetCommitFlag(); |
Tanuj Martolia | 5f5bd99 | 2024-05-31 05:09:25 | [diff] [blame] | 957 | transaction_ = nullptr; |
Daniel Murphy | 7c75043 | 2019-08-20 01:39:47 | [diff] [blame] | 958 | RunPostedTasks(); |
Evan Stade | 5987219 | 2024-02-08 16:57:48 | [diff] [blame] | 959 | // A transaction error would have resulted in a deleted db. |
| 960 | EXPECT_FALSE(bucket_context_->GetDatabasesForTesting().empty()); |
Daniel Murphy | 0240b78 | 2019-08-14 21:15:09 | [diff] [blame] | 961 | EXPECT_TRUE(s.ok()); |
[email protected] | 12c33772 | 2014-05-22 19:42:42 | [diff] [blame] | 962 | } |
| 963 | |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 964 | TEST_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 | |
| 982 | TEST_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 | |
| 1003 | TEST_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 | |
| 1050 | TEST_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 | |
| 1100 | TEST_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 | |
| 1147 | TEST_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 | |
| 1197 | TEST_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 | |
| 1250 | TEST_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 | |
| 1300 | TEST_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 | |
| 1351 | TEST_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 | |
| 1393 | TEST_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 | |
| 1435 | TEST_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 | |
| 1480 | TEST_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 | |
| 1528 | TEST_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 | |
| 1594 | TEST_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 | |
| 1660 | TEST_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 Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1676 | Status status = db_->GetAllOperation( |
| 1677 | kTestObjectStoreId, |
| 1678 | /*index_id=*/blink::IndexedDBIndexMetadata::kInvalidId, |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 1679 | std::move(get_all_parameters.key_range), get_all_parameters.result_type, |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1680 | 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 | |
| 1696 | TEST_F(DatabaseOperationTest, IndexGetAllKeysWithInvalidIndexId) { |
| 1697 | // Create an object store. |
| 1698 | ASSERT_EQ(0u, db_->metadata().object_stores.size()); |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 1699 | Status status = transaction_->BackingStoreTransaction()->CreateObjectStore( |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1700 | kTestObjectStoreId, u"store", IndexedDBKeyPath(), |
Evan Stade | 540f03c8 | 2025-04-30 16:45:12 | [diff] [blame] | 1701 | /*auto_increment=*/false); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1702 | 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 Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1718 | status = db_->GetAllOperation( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 1719 | kTestObjectStoreId, kTestIndexId, std::move(get_all_parameters.key_range), |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1720 | 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 | |
| 1737 | TEST_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 Stade | 46c8dab | 2025-05-07 17:05:14 | [diff] [blame] | 1750 | database_records.emplace_back(IndexedDBKey{primary_key}, |
| 1751 | IndexedDBValue{value, {}}, |
| 1752 | /*index_key=*/std::nullopt); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1753 | |
| 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 | |
| 1784 | TEST_F(DatabaseOperationTest, IndexGetAllRecordsWithAutoIncrementingKeys) { |
| 1785 | const IndexedDBKeyPath object_store_key_path{u"id"}; |
| 1786 | |
Arthur Sonzogni | d5ce01f7 | 2024-12-13 13:35:28 | [diff] [blame] | 1787 | const auto expected_generated_keys = std::to_array<IndexedDBKey>({ |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1788 | IndexedDBKey(1.0, blink::mojom::IDBKeyType::Number), |
| 1789 | IndexedDBKey(2.0, blink::mojom::IDBKeyType::Number), |
| 1790 | IndexedDBKey(3.0, blink::mojom::IDBKeyType::Number), |
Arthur Sonzogni | d5ce01f7 | 2024-12-13 13:35:28 | [diff] [blame] | 1791 | }); |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1792 | |
| 1793 | const blink::mojom::IDBRecordPtr expected_results[] = { |
| 1794 | blink::mojom::IDBRecord::New( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 1795 | /*primary_key=*/expected_generated_keys[2].Clone(), |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1796 | /*value=*/ |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 1797 | CreateIDBReturnValuePtr("value3", &expected_generated_keys[2], |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1798 | object_store_key_path), |
| 1799 | /*index_key=*/IndexedDBKey{"index_key1"}), |
| 1800 | blink::mojom::IDBRecord::New( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 1801 | /*primary_key=*/expected_generated_keys[1].Clone(), |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1802 | /*value=*/ |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 1803 | CreateIDBReturnValuePtr("value2", &expected_generated_keys[1], |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1804 | object_store_key_path), |
| 1805 | /*index_key=*/IndexedDBKey{"index_key2"}), |
| 1806 | blink::mojom::IDBRecord::New( |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 1807 | /*primary_key=*/expected_generated_keys[0].Clone(), |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1808 | /*value=*/ |
Evan Stade | ca999b1 | 2025-05-09 19:09:11 | [diff] [blame] | 1809 | CreateIDBReturnValuePtr("value1", &expected_generated_keys[0], |
Steve Becker | 4848af3 | 2024-10-29 22:57:19 | [diff] [blame] | 1810 | 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 Stade | cbb1e00 | 2024-09-13 20:06:57 | [diff] [blame] | 1853 | } // namespace content::indexed_db |