go.temporal.io/server@v1.23.0/common/persistence/sql/sqlplugin/tests/queue_v2.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package tests 26 27 import ( 28 "context" 29 "database/sql" 30 "errors" 31 "testing" 32 33 "go.temporal.io/api/serviceerror" 34 35 persistencespb "go.temporal.io/server/api/persistence/v1" 36 "go.temporal.io/server/common/persistence/persistencetest" 37 "go.temporal.io/server/common/persistence/serialization" 38 39 "github.com/stretchr/testify/assert" 40 "github.com/stretchr/testify/require" 41 enumspb "go.temporal.io/api/enums/v1" 42 43 "go.temporal.io/server/common/log" 44 "go.temporal.io/server/common/log/tag" 45 "go.temporal.io/server/common/persistence" 46 persistencesql "go.temporal.io/server/common/persistence/sql" 47 "go.temporal.io/server/common/persistence/sql/sqlplugin" 48 ) 49 50 var ( 51 ErrGetLastMessageIdFailed = errors.New("getLastMessageId error") 52 ErrTxBeginFailed = errors.New("txBegin error") 53 ErrInsertFailed = errors.New("insert error") 54 ErrTxRollbackFailed = errors.New("txRollBack err") 55 ErrTxCommitFailed = errors.New("txCommit err") 56 ErrRangeSelectFailed = errors.New("rangeSelect err") 57 ErrSelectMetadataFailed = errors.New("selectFromMetadata err") 58 ErrInsertMetadataFailed = errors.New("insertMetadataFailed") 59 ErrRangeDeleteFailed = errors.New("rangeDeleteFailed") 60 ErrUpdateMetadataFailed = errors.New("updateMetadataFailed") 61 ErrSelectQueueNames = errors.New("selectQueueNamesFailed") 62 ) 63 64 type ( 65 faultyDB struct { 66 sqlplugin.DB 67 getLastMessageIdErr error 68 txBeginErr error 69 txCommitErr error 70 insertErr error 71 txRollbackErr error 72 rangeSelectError error 73 selectMetadataError error 74 insertMetadataError error 75 rangeDeleteError error 76 updateMetadataError error 77 selectQueueNamesError error 78 commitCalls int 79 } 80 faultyTx struct { 81 db *faultyDB 82 sqlplugin.Tx 83 commitCalls *int 84 } 85 logRecorder struct { 86 log.Logger 87 errMsgs []string 88 } 89 ) 90 91 func (db *faultyDB) BeginTx(ctx context.Context) (sqlplugin.Tx, error) { 92 if db.txBeginErr != nil { 93 return nil, db.txBeginErr 94 } 95 tx, err := db.DB.BeginTx(ctx) 96 if err != nil { 97 return nil, err 98 } 99 return &faultyTx{db: db, commitCalls: &db.commitCalls, Tx: tx}, nil 100 } 101 102 func (tx *faultyTx) InsertIntoQueueV2Messages(ctx context.Context, row []sqlplugin.QueueV2MessageRow) (sql.Result, error) { 103 if tx.db.insertErr != nil { 104 return nil, tx.db.insertErr 105 } 106 return tx.Tx.InsertIntoQueueV2Messages(ctx, row) 107 } 108 109 func (tx *faultyTx) GetLastEnqueuedMessageIDForUpdateV2(ctx context.Context, filter sqlplugin.QueueV2Filter) (int64, error) { 110 if tx.db.getLastMessageIdErr != nil { 111 return 0, tx.db.getLastMessageIdErr 112 } 113 return tx.Tx.GetLastEnqueuedMessageIDForUpdateV2(ctx, filter) 114 } 115 116 func (db *faultyDB) GetLastEnqueuedMessageIDForUpdateV2(ctx context.Context, filter sqlplugin.QueueV2Filter) (int64, error) { 117 if db.getLastMessageIdErr != nil { 118 return 0, db.getLastMessageIdErr 119 } 120 return db.DB.GetLastEnqueuedMessageIDForUpdateV2(ctx, filter) 121 } 122 123 func (db *faultyDB) RangeSelectFromQueueV2Messages(ctx context.Context, filter sqlplugin.QueueV2MessagesFilter) ([]sqlplugin.QueueV2MessageRow, error) { 124 return []sqlplugin.QueueV2MessageRow{}, db.rangeSelectError 125 126 } 127 128 func (db *faultyDB) SelectFromQueueV2Metadata(ctx context.Context, filter sqlplugin.QueueV2MetadataFilter) (*sqlplugin.QueueV2MetadataRow, error) { 129 if db.selectMetadataError != nil { 130 return &sqlplugin.QueueV2MetadataRow{}, db.selectMetadataError 131 } 132 return db.DB.SelectFromQueueV2Metadata(ctx, filter) 133 } 134 135 func (db *faultyDB) SelectNameFromQueueV2Metadata(ctx context.Context, filter sqlplugin.QueueV2MetadataTypeFilter) ([]sqlplugin.QueueV2MetadataRow, error) { 136 if db.selectQueueNamesError != nil { 137 return nil, db.selectQueueNamesError 138 } 139 return db.DB.SelectNameFromQueueV2Metadata(ctx, filter) 140 } 141 142 func (db *faultyDB) SelectFromQueueV2MetadataForUpdate(ctx context.Context, filter sqlplugin.QueueV2MetadataFilter) (*sqlplugin.QueueV2MetadataRow, error) { 143 if db.selectMetadataError != nil { 144 return &sqlplugin.QueueV2MetadataRow{}, db.selectMetadataError 145 } 146 return db.DB.SelectFromQueueV2MetadataForUpdate(ctx, filter) 147 } 148 149 func (tx *faultyTx) SelectFromQueueV2Metadata(ctx context.Context, filter sqlplugin.QueueV2MetadataFilter) (*sqlplugin.QueueV2MetadataRow, error) { 150 if tx.db.selectMetadataError != nil { 151 return &sqlplugin.QueueV2MetadataRow{}, tx.db.selectMetadataError 152 } 153 return tx.Tx.SelectFromQueueV2Metadata(ctx, filter) 154 } 155 156 func (tx *faultyTx) SelectFromQueueV2MetadataForUpdate(ctx context.Context, filter sqlplugin.QueueV2MetadataFilter) (*sqlplugin.QueueV2MetadataRow, error) { 157 if tx.db.selectMetadataError != nil { 158 return &sqlplugin.QueueV2MetadataRow{}, tx.db.selectMetadataError 159 } 160 return tx.Tx.SelectFromQueueV2MetadataForUpdate(ctx, filter) 161 } 162 163 func (db *faultyDB) InsertIntoQueueV2Metadata(ctx context.Context, row *sqlplugin.QueueV2MetadataRow) (sql.Result, error) { 164 if db.insertMetadataError != nil { 165 return nil, db.insertMetadataError 166 } 167 return db.DB.InsertIntoQueueV2Metadata(ctx, row) 168 } 169 170 func (tx *faultyTx) RangeDeleteFromQueueV2Messages(ctx context.Context, filter sqlplugin.QueueV2MessagesFilter) (sql.Result, error) { 171 if tx.db.rangeDeleteError != nil { 172 return nil, tx.db.rangeDeleteError 173 } 174 return tx.Tx.RangeDeleteFromQueueV2Messages(ctx, filter) 175 } 176 177 func (tx *faultyTx) UpdateQueueV2Metadata(ctx context.Context, row *sqlplugin.QueueV2MetadataRow) (sql.Result, error) { 178 if tx.db.updateMetadataError != nil { 179 return nil, tx.db.updateMetadataError 180 } 181 return tx.Tx.UpdateQueueV2Metadata(ctx, row) 182 } 183 184 func (tx *faultyTx) Rollback() error { 185 if err := tx.Tx.Rollback(); err != nil { 186 return err 187 } 188 return tx.db.txRollbackErr 189 } 190 191 func (tx *faultyTx) Commit() error { 192 *tx.commitCalls++ 193 if tx.db.txCommitErr != nil { 194 err := tx.Rollback() 195 if err != nil { 196 return err 197 } 198 return tx.db.txCommitErr 199 } 200 return tx.Tx.Commit() 201 } 202 203 func (l *logRecorder) Error(msg string, _ ...tag.Tag) { 204 l.errMsgs = append(l.errMsgs, msg) 205 } 206 207 func RunSQLQueueV2TestSuite(t *testing.T, baseDB sqlplugin.DB) { 208 ctx := context.Background() 209 t.Run("TestListQueueFailsToGetLastMessageID", func(t *testing.T) { 210 t.Parallel() 211 testListQueueFailsToGetLastMessageID(ctx, t, baseDB) 212 }) 213 t.Run("TestListQueueFailsToExtractQueueMetadata", func(t *testing.T) { 214 t.Parallel() 215 testListQueueFailsToExtractQueueMetadata(ctx, t, baseDB) 216 }) 217 t.Run("GetPartitionFailsForListQueues", func(t *testing.T) { 218 t.Parallel() 219 testListQueuesGetPartitionFails(ctx, t, baseDB) 220 }) 221 t.Run("QueueInsertFails", func(t *testing.T) { 222 t.Parallel() 223 testQueueInsertFails(ctx, t, baseDB) 224 }) 225 t.Run("TxBeginFails", func(t *testing.T) { 226 t.Parallel() 227 testBeginTxFails(ctx, t, baseDB) 228 }) 229 t.Run("TxCommitFails", func(t *testing.T) { 230 t.Parallel() 231 testCommitTxFails(ctx, t, baseDB) 232 }) 233 t.Run("FailedToGetLastMessageIDFromDB", func(t *testing.T) { 234 t.Parallel() 235 testGetLastMessageIDFails(ctx, t, baseDB) 236 }) 237 t.Run("FailedToGetLastMessageIDFromDB", func(t *testing.T) { 238 t.Parallel() 239 testRangeSelectFromQueueV2MessagesFails(ctx, t, baseDB) 240 }) 241 t.Run("InsertIntoQueueV2MetadataFails", func(t *testing.T) { 242 t.Parallel() 243 testInsertIntoQueueV2MetadataFails(ctx, t, baseDB) 244 }) 245 t.Run("GetPartitionFailsForRangeDelete", func(t *testing.T) { 246 t.Parallel() 247 testGetPartitionFailsForRangeDelete(ctx, t, baseDB) 248 }) 249 t.Run("GetLastMessageIDForDeleteFails", func(t *testing.T) { 250 t.Parallel() 251 testGetLastMessageIDForDeleteFails(ctx, t, baseDB) 252 }) 253 t.Run("RangeDeleteMessagesFails", func(t *testing.T) { 254 t.Parallel() 255 testRangeDeleteMessagesFails(ctx, t, baseDB) 256 }) 257 t.Run("RangeDeleteActuallyDeletes", func(t *testing.T) { 258 t.Parallel() 259 testRangeDeleteActuallyDeletes(ctx, t, baseDB) 260 }) 261 t.Run("UpdateMetadataFails", func(t *testing.T) { 262 t.Parallel() 263 testUpdateMetadataFails(ctx, t, baseDB) 264 }) 265 t.Run("InvalidMetadataEncoding", func(t *testing.T) { 266 t.Parallel() 267 testInvalidMetadataEncoding(ctx, t, baseDB) 268 }) 269 t.Run("InvalidMetadataPayload", func(t *testing.T) { 270 t.Parallel() 271 testInvalidMetadataPayload(ctx, t, baseDB) 272 }) 273 t.Run("SelectMetadataFails", func(t *testing.T) { 274 t.Parallel() 275 testSelectMetadataFails(ctx, t, baseDB) 276 }) 277 t.Run("SelectNameFromQueueV2MetadataFails", func(t *testing.T) { 278 t.Parallel() 279 testSelectNameFromQueueV2MetadataFails(ctx, t, baseDB) 280 }) 281 t.Run("SelectNameFromQueueV2NegativeToken", func(t *testing.T) { 282 t.Parallel() 283 testSelectNameFromQueueV2NegativeToken(ctx, t, baseDB) 284 }) 285 } 286 287 func testQueueInsertFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 288 queueType := persistence.QueueTypeHistoryNormal 289 queueName := "test-queue-" + t.Name() 290 db := &faultyDB{ 291 DB: baseDB, 292 insertErr: ErrInsertFailed, 293 txRollbackErr: ErrTxRollbackFailed, 294 } 295 logger := &logRecorder{Logger: log.NewTestLogger()} 296 q := persistencesql.NewQueueV2(db, logger) 297 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 298 QueueType: queueType, 299 QueueName: queueName, 300 }) 301 require.NoError(t, err) 302 _, err = persistencetest.EnqueueMessage(context.Background(), q, queueType, queueName) 303 require.Error(t, err) 304 assert.ErrorContains(t, err, "insert error") 305 require.Len(t, logger.errMsgs, 1) 306 assert.Contains(t, logger.errMsgs[0], "transaction rollback error") 307 assert.Equal(t, db.commitCalls, 0) 308 } 309 310 func testCommitTxFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 311 queueType := persistence.QueueTypeHistoryNormal 312 queueName := "test-queue-" + t.Name() 313 db := &faultyDB{ 314 DB: baseDB, 315 txCommitErr: ErrTxCommitFailed, 316 } 317 logger := &logRecorder{Logger: log.NewTestLogger()} 318 q := persistencesql.NewQueueV2(db, logger) 319 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 320 QueueType: queueType, 321 QueueName: queueName, 322 }) 323 require.NoError(t, err) 324 _, err = persistencetest.EnqueueMessage(context.Background(), q, queueType, queueName) 325 require.Error(t, err) 326 assert.ErrorContains(t, err, "EnqueueMessage failed") 327 assert.Equal(t, db.commitCalls, 1) 328 } 329 330 func testBeginTxFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 331 queueType := persistence.QueueTypeHistoryNormal 332 queueName := "test-queue-" + t.Name() 333 db := &faultyDB{ 334 DB: baseDB, 335 txBeginErr: ErrTxBeginFailed, 336 } 337 logger := &logRecorder{Logger: log.NewTestLogger()} 338 q := persistencesql.NewQueueV2(db, logger) 339 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 340 QueueType: queueType, 341 QueueName: queueName, 342 }) 343 require.NoError(t, err) 344 _, err = persistencetest.EnqueueMessage(context.Background(), q, queueType, queueName) 345 require.Error(t, err) 346 assert.ErrorContains(t, err, "txBegin error") 347 assert.Equal(t, db.commitCalls, 0) 348 } 349 350 func testGetLastMessageIDFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 351 queueType := persistence.QueueTypeHistoryNormal 352 queueName := "test-queue-" + t.Name() 353 db := &faultyDB{ 354 DB: baseDB, 355 getLastMessageIdErr: ErrGetLastMessageIdFailed, 356 txRollbackErr: ErrTxRollbackFailed, 357 } 358 logger := &logRecorder{Logger: log.NewTestLogger()} 359 q := persistencesql.NewQueueV2(db, logger) 360 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 361 QueueType: queueType, 362 QueueName: queueName, 363 }) 364 require.NoError(t, err) 365 _, err = persistencetest.EnqueueMessage(context.Background(), q, queueType, queueName) 366 require.Error(t, err) 367 assert.ErrorContains(t, err, "failed to get next messageId") 368 assert.Equal(t, db.commitCalls, 0) 369 } 370 371 func testRangeSelectFromQueueV2MessagesFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 372 queueType := persistence.QueueTypeHistoryNormal 373 queueName := "test-queue-" + t.Name() 374 db := &faultyDB{ 375 DB: baseDB, 376 rangeSelectError: ErrRangeSelectFailed, 377 } 378 logger := &logRecorder{Logger: log.NewTestLogger()} 379 q := persistencesql.NewQueueV2(db, logger) 380 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 381 QueueType: queueType, 382 QueueName: queueName, 383 }) 384 require.NoError(t, err) 385 _, err = q.ReadMessages(context.Background(), &persistence.InternalReadMessagesRequest{ 386 QueueType: queueType, 387 QueueName: queueName, 388 PageSize: 1, 389 NextPageToken: nil, 390 }) 391 require.Error(t, err) 392 assert.ErrorContains(t, err, "RangeSelectFromQueueV2Messages operation failed") 393 } 394 395 func testInsertIntoQueueV2MetadataFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 396 queueType := persistence.QueueTypeHistoryNormal 397 queueName := "test-queue-" + t.Name() 398 db := &faultyDB{ 399 DB: baseDB, 400 insertMetadataError: ErrInsertMetadataFailed, 401 } 402 logger := &logRecorder{Logger: log.NewTestLogger()} 403 q := persistencesql.NewQueueV2(db, logger) 404 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 405 QueueType: queueType, 406 QueueName: queueName, 407 }) 408 require.Error(t, err) 409 assert.ErrorContains(t, err, "InsertIntoQueueV2Metadata operation failed") 410 } 411 412 func testGetPartitionFailsForRangeDelete(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 413 queueType := persistence.QueueTypeHistoryNormal 414 queueName := "test-queue-" + t.Name() 415 logger := &logRecorder{Logger: log.NewTestLogger()} 416 q := persistencesql.NewQueueV2(baseDB, logger) 417 queuePB := persistencespb.Queue{ 418 Partitions: map[int32]*persistencespb.QueuePartition{ 419 0: {}, 420 1: {}, 421 }, 422 } 423 bytes, _ := queuePB.Marshal() 424 row := sqlplugin.QueueV2MetadataRow{ 425 QueueType: queueType, 426 QueueName: queueName, 427 MetadataPayload: bytes, 428 MetadataEncoding: enumspb.ENCODING_TYPE_PROTO3.String(), 429 } 430 _, err := baseDB.InsertIntoQueueV2Metadata(ctx, &row) 431 require.NoError(t, err) 432 _, err = q.RangeDeleteMessages(context.Background(), &persistence.InternalRangeDeleteMessagesRequest{ 433 QueueType: persistence.QueueTypeHistoryNormal, 434 QueueName: "test-queue-" + t.Name(), 435 InclusiveMaxMessageMetadata: persistence.MessageMetadata{ID: 0}, 436 }) 437 assert.Error(t, err) 438 assert.ErrorContains(t, err, "partitions") 439 } 440 441 func testGetLastMessageIDForDeleteFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 442 queueType := persistence.QueueTypeHistoryNormal 443 queueName := "test-queue-" + t.Name() 444 db := &faultyDB{ 445 DB: baseDB, 446 getLastMessageIdErr: ErrGetLastMessageIdFailed, 447 } 448 logger := &logRecorder{Logger: log.NewTestLogger()} 449 q := persistencesql.NewQueueV2(db, logger) 450 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 451 QueueType: queueType, 452 QueueName: queueName, 453 }) 454 require.NoError(t, err) 455 _, err = q.RangeDeleteMessages(context.Background(), &persistence.InternalRangeDeleteMessagesRequest{ 456 QueueType: persistence.QueueTypeHistoryNormal, 457 QueueName: "test-queue-" + t.Name(), 458 InclusiveMaxMessageMetadata: persistence.MessageMetadata{ID: 0}, 459 }) 460 assert.Error(t, err) 461 assert.ErrorContains(t, err, "getLastMessageId error") 462 } 463 464 func testRangeDeleteMessagesFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 465 queueType := persistence.QueueTypeHistoryNormal 466 queueName := "test-queue-" + t.Name() 467 db := &faultyDB{ 468 DB: baseDB, 469 rangeDeleteError: ErrRangeDeleteFailed, 470 } 471 logger := &logRecorder{Logger: log.NewTestLogger()} 472 q := persistencesql.NewQueueV2(db, logger) 473 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 474 QueueType: queueType, 475 QueueName: queueName, 476 }) 477 require.NoError(t, err) 478 persistencetest.EnqueueMessagesForDelete(t, q, queueName, queueType) 479 _, err = q.RangeDeleteMessages(context.Background(), &persistence.InternalRangeDeleteMessagesRequest{ 480 QueueType: queueType, 481 QueueName: queueName, 482 InclusiveMaxMessageMetadata: persistence.MessageMetadata{ID: 0}, 483 }) 484 assert.Error(t, err) 485 assert.ErrorContains(t, err, "rangeDeleteFailed") 486 } 487 488 func testUpdateMetadataFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 489 queueType := persistence.QueueTypeHistoryNormal 490 queueName := "test-queue-" + t.Name() 491 db := &faultyDB{ 492 DB: baseDB, 493 updateMetadataError: ErrUpdateMetadataFailed, 494 } 495 logger := &logRecorder{Logger: log.NewTestLogger()} 496 q := persistencesql.NewQueueV2(db, logger) 497 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 498 QueueType: queueType, 499 QueueName: queueName, 500 }) 501 require.NoError(t, err) 502 persistencetest.EnqueueMessagesForDelete(t, q, queueName, queueType) 503 _, err = q.RangeDeleteMessages(context.Background(), &persistence.InternalRangeDeleteMessagesRequest{ 504 QueueType: queueType, 505 QueueName: queueName, 506 InclusiveMaxMessageMetadata: persistence.MessageMetadata{ID: 0}, 507 }) 508 assert.Error(t, err) 509 assert.ErrorContains(t, err, "updateMetadataFailed") 510 } 511 512 func testSelectMetadataFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 513 queueType := persistence.QueueTypeHistoryNormal 514 queueName := "test-queue-" + t.Name() 515 db := &faultyDB{ 516 DB: baseDB, 517 selectMetadataError: ErrSelectMetadataFailed, 518 } 519 logger := &logRecorder{Logger: log.NewTestLogger()} 520 q := persistencesql.NewQueueV2(db, logger) 521 _, err := q.ReadMessages(ctx, &persistence.InternalReadMessagesRequest{ 522 QueueType: queueType, 523 QueueName: queueName, 524 PageSize: 10, 525 }) 526 assert.Error(t, err) 527 assert.ErrorContains(t, err, ErrSelectMetadataFailed.Error()) 528 _, err = persistencetest.EnqueueMessage(context.Background(), q, queueType, queueName) 529 assert.Error(t, err) 530 assert.ErrorContains(t, err, ErrSelectMetadataFailed.Error()) 531 _, err = q.RangeDeleteMessages(context.Background(), &persistence.InternalRangeDeleteMessagesRequest{ 532 QueueType: queueType, 533 QueueName: queueName, 534 InclusiveMaxMessageMetadata: persistence.MessageMetadata{ID: 0}, 535 }) 536 assert.Error(t, err) 537 assert.ErrorAs(t, err, new(*serviceerror.Unavailable)) 538 } 539 540 func testInvalidMetadataPayload(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 541 queueType := persistence.QueueTypeHistoryNormal 542 queueName := "test-queue-" + t.Name() 543 logger := &logRecorder{Logger: log.NewTestLogger()} 544 q := persistencesql.NewQueueV2(baseDB, logger) 545 546 row := sqlplugin.QueueV2MetadataRow{ 547 QueueType: queueType, 548 QueueName: queueName, 549 MetadataPayload: []byte("invalid_payload"), 550 MetadataEncoding: enumspb.ENCODING_TYPE_PROTO3.String(), 551 } 552 _, err := baseDB.InsertIntoQueueV2Metadata(ctx, &row) 553 require.NoError(t, err) 554 _, err = q.ReadMessages(context.Background(), &persistence.InternalReadMessagesRequest{ 555 QueueType: queueType, 556 QueueName: queueName, 557 PageSize: 10, 558 }) 559 assert.Error(t, err) 560 assert.ErrorAs(t, err, new(*serialization.DeserializationError)) 561 } 562 563 func testInvalidMetadataEncoding(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 564 queueType := persistence.QueueTypeHistoryNormal 565 queueName := "test-queue-" + t.Name() 566 logger := &logRecorder{Logger: log.NewTestLogger()} 567 q := persistencesql.NewQueueV2(baseDB, logger) 568 569 row := sqlplugin.QueueV2MetadataRow{ 570 QueueType: queueType, 571 QueueName: queueName, 572 MetadataPayload: []byte("test"), 573 MetadataEncoding: "invalid_encoding", 574 } 575 _, err := baseDB.InsertIntoQueueV2Metadata(ctx, &row) 576 require.NoError(t, err) 577 _, err = q.ReadMessages(context.Background(), &persistence.InternalReadMessagesRequest{ 578 QueueType: queueType, 579 QueueName: queueName, 580 PageSize: 10, 581 }) 582 assert.Error(t, err) 583 assert.ErrorAs(t, err, new(*serialization.UnknownEncodingTypeError)) 584 _, err = persistencetest.EnqueueMessage(context.Background(), q, queueType, queueName) 585 assert.Error(t, err) 586 assert.ErrorAs(t, err, new(*serialization.UnknownEncodingTypeError)) 587 _, err = q.RangeDeleteMessages(context.Background(), &persistence.InternalRangeDeleteMessagesRequest{ 588 QueueType: queueType, 589 QueueName: queueName, 590 InclusiveMaxMessageMetadata: persistence.MessageMetadata{ID: 0}, 591 }) 592 assert.Error(t, err) 593 assert.ErrorAs(t, err, new(*serviceerror.Unavailable)) 594 } 595 596 func testRangeDeleteActuallyDeletes(ctx context.Context, t *testing.T, db sqlplugin.DB) { 597 queueKey := persistencetest.GetQueueKey(t) 598 queueType := persistence.QueueTypeHistoryNormal 599 q := persistencesql.NewQueueV2(db, log.NewTestLogger()) 600 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 601 QueueType: queueType, 602 QueueName: queueKey.GetQueueName(), 603 }) 604 require.NoError(t, err) 605 for i := 0; i < 3; i++ { 606 _, err = persistencetest.EnqueueMessage(context.Background(), q, queueType, queueKey.GetQueueName()) 607 require.NoError(t, err) 608 } 609 resp, err := q.RangeDeleteMessages(context.Background(), &persistence.InternalRangeDeleteMessagesRequest{ 610 QueueType: queueType, 611 QueueName: queueKey.GetQueueName(), 612 InclusiveMaxMessageMetadata: persistence.MessageMetadata{ID: persistence.FirstQueueMessageID + 2}, 613 }) 614 require.NoError(t, err) 615 assert.Equal(t, int64(3), resp.MessagesDeleted) 616 result, err := q.ReadMessages(ctx, &persistence.InternalReadMessagesRequest{ 617 QueueType: queueType, 618 QueueName: queueKey.GetQueueName(), 619 PageSize: 10, 620 }) 621 require.NoError(t, err) 622 assert.Empty(t, result.Messages) 623 messages, err := db.RangeSelectFromQueueV2Messages(ctx, sqlplugin.QueueV2MessagesFilter{ 624 QueueType: queueType, 625 QueueName: queueKey.GetQueueName(), 626 MinMessageID: 0, 627 MaxMessageID: 100, 628 PageSize: 10, 629 }) 630 require.NoError(t, err) 631 if assert.Len(t, messages, 1) { 632 assert.Equal(t, int64(persistence.FirstQueueMessageID+2), messages[0].MessageID) 633 } 634 response, err := persistencetest.EnqueueMessage(context.Background(), q, queueType, queueKey.GetQueueName()) 635 require.NoError(t, err) 636 assert.Equal(t, int64(persistence.FirstQueueMessageID+3), response.Metadata.ID) 637 } 638 639 func testSelectNameFromQueueV2MetadataFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 640 queueType := persistence.QueueTypeHistoryDLQ 641 db := &faultyDB{ 642 DB: baseDB, 643 selectQueueNamesError: ErrSelectQueueNames, 644 } 645 logger := &logRecorder{Logger: log.NewTestLogger()} 646 q := persistencesql.NewQueueV2(db, logger) 647 _, err := q.ListQueues(ctx, &persistence.InternalListQueuesRequest{ 648 QueueType: queueType, 649 PageSize: 10, 650 NextPageToken: nil, 651 }) 652 assert.Error(t, err) 653 assert.ErrorContains(t, err, "SelectNameFromQueueV2Metadata operation failed") 654 } 655 656 func testSelectNameFromQueueV2NegativeToken(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 657 queueType := persistence.QueueTypeHistoryDLQ 658 logger := &logRecorder{Logger: log.NewTestLogger()} 659 q := persistencesql.NewQueueV2(baseDB, logger) 660 _, err := q.ListQueues(ctx, &persistence.InternalListQueuesRequest{ 661 QueueType: queueType, 662 PageSize: 1, 663 NextPageToken: persistence.GetNextPageTokenForListQueues(-1), 664 }) 665 require.Error(t, err) 666 require.ErrorIs(t, err, persistence.ErrNegativeListQueuesOffset) 667 } 668 669 func testListQueuesGetPartitionFails(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 670 // Using a different QueueType to prevent this test from failing because of queues created in previous tests. 671 queueType := persistence.QueueV2Type(4) 672 queueName := "test-queue-" + t.Name() 673 logger := &logRecorder{Logger: log.NewTestLogger()} 674 q := persistencesql.NewQueueV2(baseDB, logger) 675 queuePB := persistencespb.Queue{ 676 Partitions: map[int32]*persistencespb.QueuePartition{ 677 0: {}, 678 1: {}, 679 }, 680 } 681 bytes, _ := queuePB.Marshal() 682 row := sqlplugin.QueueV2MetadataRow{ 683 QueueType: queueType, 684 QueueName: queueName, 685 MetadataPayload: bytes, 686 MetadataEncoding: enumspb.ENCODING_TYPE_PROTO3.String(), 687 } 688 _, err := baseDB.InsertIntoQueueV2Metadata(ctx, &row) 689 require.NoError(t, err) 690 _, err = q.ListQueues(context.Background(), &persistence.InternalListQueuesRequest{ 691 QueueType: queueType, 692 PageSize: 100, 693 }) 694 assert.Error(t, err) 695 assert.ErrorContains(t, err, "partitions") 696 } 697 698 func testListQueueFailsToGetLastMessageID(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 699 // Using a different QueueType to prevent this test from failing because of queues created in previous tests. 700 queueType := persistence.QueueV2Type(5) 701 queueName := "test-queue-" + t.Name() 702 db := &faultyDB{ 703 DB: baseDB, 704 getLastMessageIdErr: ErrGetLastMessageIdFailed, 705 } 706 logger := &logRecorder{Logger: log.NewTestLogger()} 707 q := persistencesql.NewQueueV2(db, logger) 708 _, err := q.CreateQueue(ctx, &persistence.InternalCreateQueueRequest{ 709 QueueType: queueType, 710 QueueName: queueName, 711 }) 712 assert.NoError(t, err) 713 _, err = q.ListQueues(ctx, &persistence.InternalListQueuesRequest{ 714 QueueType: queueType, 715 PageSize: 100, 716 }) 717 assert.Error(t, err) 718 assert.ErrorContains(t, err, ErrGetLastMessageIdFailed.Error()) 719 } 720 721 func testListQueueFailsToExtractQueueMetadata(ctx context.Context, t *testing.T, baseDB sqlplugin.DB) { 722 // Using a different QueueType to prevent this test from failing because of queues created in previous tests. 723 queueType := persistence.QueueV2Type(6) 724 queueName := "test-queue-" + t.Name() 725 q := persistencesql.NewQueueV2(baseDB, log.NewTestLogger()) 726 row := sqlplugin.QueueV2MetadataRow{ 727 QueueType: queueType, 728 QueueName: queueName, 729 MetadataPayload: []byte("test"), 730 MetadataEncoding: "invalid_encoding", 731 } 732 _, err := baseDB.InsertIntoQueueV2Metadata(ctx, &row) 733 assert.NoError(t, err) 734 _, err = q.ListQueues(ctx, &persistence.InternalListQueuesRequest{ 735 QueueType: queueType, 736 PageSize: 100, 737 }) 738 assert.Error(t, err) 739 assert.ErrorAs(t, err, new(*serialization.UnknownEncodingTypeError)) 740 }