test(api): cover exact pagination-limit boundaries for sponsored transactions - #199
Open
phalap1 wants to merge 1 commit into
Open
Conversation
…sactions The limit validation in list_sponsored_transactions was implemented but never tested at its exact boundaries (0, 1, 200, 201, negative), nor was the status-filter validation error path. Adds direct coverage for each. Asserts the exact error message the handler returns, not just the status code, so a wording regression fails too. The boundary test inserts three rows so limit=1 has to truncate and emit a cursor, proving the limit is applied rather than merely accepted.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #67
GET /v1/wallets/:id/sponsored-transactions(crates/api/src/routes/sponsor.rs::list_sponsored_transactions) validateslimitagainst> 200and< 1, and constrainsstatustopending|confirmed|failed. None of that was covered:list_sponsored_transactions_paginationonly ever sends in-range values, so the two 400 paths never fired in a test, the exact accept/reject boundary was never pinned, and the status-filter rejection path had no coverage at all.This adds direct coverage for each, in
crates/api/tests/api_tests.rsalongside the existinglist_sponsored_transactions_*tests, reusing the existingget_authhelper.What's covered
sponsored_tx_limit_zero_and_negative_are_rejectedlimit=0,limit=-1limit must be at least 1sponsored_tx_limit_201_is_rejectedlimit=201limit must not exceed 200sponsored_tx_limit_boundaries_1_and_200_succeedlimit=1,limit=200sponsored_tx_invalid_status_filter_is_rejectedstatus=bogusstatus must be one of: pending, confirmed, failedNotes on the approach
Exact message assertions, not containment. Per the issue's guideline, each rejection asserts the precise string the handler returns, so a wording change fails the test rather than silently passing a substring check. This matches the existing convention in this file.
Ownership is validated before the query string.
list_sponsored_transactionscallsrequire_login, loads the wallet, and checkswallet.user_idbefore it looks atlimitorstatus. Every case therefore creates a real wallet owned by the caller — without one, a 404 would mask the 400 actually under test and the tests would pass for the wrong reason.limitisOption<i64>, so-1is a real test. A negative value deserializes cleanly and reaches the handler's own< 1branch, rather than being rejected earlier by the query extractor as malformed. That is what makeslimit=-1distinct fromlimit=0and worth covering separately.The boundary test proves the limit is applied, not just accepted. It inserts three sponsored transactions, so
limit=1must return exactly one row and emit anext_cursor, whilelimit=200must return all three with a null cursor. Asserting only the status code would let a handler that ignoreslimitentirely still pass.Empty
statusis pinned as valid. The handler doesq.status.filter(|s| !s.is_empty()), so?status=means "unfiltered", not "invalid". The invalid-status test asserts that?status=still returns 200, which keeps that.filter()from being dropped as dead code later.Verification
Run against a local Postgres:
The off-by-one check was confirmed to be meaningful rather than vacuous: temporarily changing the handler's guard from
limit > 200tolimit > 199failssponsored_tx_limit_boundaries_1_and_200_succeedwithleft: 400, right: 200, and it passes again once the guard is restored.No production code is changed — this PR is additive test coverage only.