-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tests(integration): port x/bank tests to server/v2 app #21912
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Outside diff range and nitpick comments (5)
tests/integration/v2/bank/determinisitic_test.go (2)
86-87
: Initialize context within the fixture for consistencyCurrently, the context
f.ctx
is initialized outside ofinitDeterministicFixture
. For better encapsulation and to maintain consistency across tests, consider initializing the context within theinitDeterministicFixture
function.Update the
initDeterministicFixture
function to include context initialization:func initDeterministicFixture(t *testing.T) *deterministicFixture { t.Helper() // ... existing setup code ... require.NoError(t, err) require.NotNil(t, app) + ctx := app.StateLatestContext(t) + return &deterministicFixture{ app: app, bankKeeper: bankKeeper, + ctx: ctx, T: t, } }And remove the context initialization from
TestGRPCQueryBalance
:func TestGRPCQueryBalance(t *testing.T) { f := initDeterministicFixture(t) - f.ctx = f.app.StateLatestContext(t) rapid.Check(t, func(rt *rapid.T) { // ... test code ... }) }
93-94
: Optimize address encoding by reusing codec optionsIn the test, a new
CodecOptions{}
instance is created each time to get the address codec. To optimize performance and reduce unnecessary allocations, consider defining the codec options once and reusing them.Define the codec options at the beginning of your test or within the fixture:
+addrCodec := codectestutil.CodecOptions{}.GetAddressCodec() func TestGRPCQueryBalance(t *testing.T) { f := initDeterministicFixture(t) rapid.Check(t, func(rt *rapid.T) { addr := testdata.AddressGenerator(rt).Draw(rt, "address") coin := getCoin(rt) fundAccount(f, addr, coin) - addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr) + addrStr, err := addrCodec.BytesToString(addr) require.NoError(t, err) // ... remaining test code ... }) }Alternatively, incorporate the codec into the fixture for reuse across multiple tests.
testutil/testdata/grpc_query.go (1)
99-99
: Add a GoDoc comment for 'DeterministicIterationsV2'Exported functions should have a GoDoc comment explaining their purpose and usage, starting with the function name, as per Go conventions and the Uber Go Style Guide.
Please add a comment for
DeterministicIterationsV2
to improve code documentation and readability.Apply this diff to add the comment:
+// DeterministicIterationsV2 handles deterministic query requests for server/v2 and tests: +// 1. That the response is always the same when calling the +// grpcFn query iterCount times (defaults to 1000). +// 2. That the gas consumption of the query is consistent. When +// gasOverwrite is set to true, it also checks that this consumed +// gas value is equal to the hardcoded gasConsumed. func DeterministicIterationsV2[request, response proto.Message](tests/integration/v2/app.go (2)
288-288
: Fix grammatical error inStateLatestContext
commentThe comment for the
StateLatestContext
method contains a grammatical error. It currently reads: "StateLatestContext creates returns a new context...". This should be corrected for clarity.Apply this diff to fix the comment:
-// StateLatestContext creates returns a new context from context.Background() with the latest state. +// StateLatestContext returns a new context derived from context.Background() with the latest state.
358-359
: Address the TODO comment regarding duplicate fetchesThere is a TODO comment questioning why the transaction is fetched twice. It's important to resolve TODOs to maintain code clarity and prevent potential issues.
Do you need assistance investigating the reason for fetching the transaction twice? I can help analyze the code to determine if this duplication is necessary or if it can be optimized. Let me know if you would like me to open a new GitHub issue for this.
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
📒 Files selected for processing (4)
- tests/integration/v2/app.go (1 hunks)
- tests/integration/v2/bank/app_test.go (1 hunks)
- tests/integration/v2/bank/determinisitic_test.go (1 hunks)
- testutil/testdata/grpc_query.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/integration/v2/bank/app_test.go
🧰 Additional context used
📓 Path-based instructions (3)
tests/integration/v2/app.go (2)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Pattern
tests/**/*
: "Assess the integration and e2e test code assessing sufficient code coverage for the changes associated in the pull request"tests/integration/v2/bank/determinisitic_test.go (3)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Pattern
tests/**/*
: "Assess the integration and e2e test code assessing sufficient code coverage for the changes associated in the pull request"
Pattern
**/*_test.go
: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"testutil/testdata/grpc_query.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
rapid.Check(t, func(rt *rapid.T) { | ||
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | ||
coin := getCoin(rt) | ||
fundAccount(f, addr, coin) | ||
|
||
addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr) | ||
require.NoError(t, err) | ||
|
||
req := banktypes.NewQueryBalanceRequest(addrStr, coin.GetDenom()) | ||
|
||
testdata.DeterministicIterationsV2(t, f.ctx, nil, req, f.QueryBalance, 0, true) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance test coverage for bank module functionalities
While the TestGRPCQueryBalance
function tests the balance query, to ensure comprehensive integration test coverage, consider porting additional tests from the x/bank module. This could include tests for:
- Transferring funds between accounts.
- Querying total supply of tokens.
- Handling edge cases like insufficient balances or invalid denominations.
Would you like assistance in identifying key tests to port or in writing additional tests to enhance coverage?
res, err := f.app.Query(ctx, 0, req) | ||
return res.(*banktypes.QueryBalanceResponse), err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent potential panic due to unchecked type assertion
In the QueryBalance
method, the type assertion res.(*banktypes.QueryBalanceResponse)
could cause a panic if res
is not of the expected type. To enhance robustness, consider using a type assertion with an ok
check to handle unexpected types gracefully.
Apply this diff to safely perform the type assertion:
func (f *deterministicFixture) QueryBalance(
ctx context.Context, req *banktypes.QueryBalanceRequest,
) (*banktypes.QueryBalanceResponse, error) {
res, err := f.app.Query(ctx, 0, req)
- return res.(*banktypes.QueryBalanceResponse), err
+ if err != nil {
+ return nil, err
+ }
+ balanceRes, ok := res.(*banktypes.QueryBalanceResponse)
+ if !ok {
+ return nil, fmt.Errorf("unexpected response type: %T", res)
+ }
+ return balanceRes, nil
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
res, err := f.app.Query(ctx, 0, req) | |
return res.(*banktypes.QueryBalanceResponse), err | |
func (f *deterministicFixture) QueryBalance( | |
ctx context.Context, req *banktypes.QueryBalanceRequest, | |
) (*banktypes.QueryBalanceResponse, error) { | |
res, err := f.app.Query(ctx, 0, req) | |
if err != nil { | |
return nil, err | |
} | |
balanceRes, ok := res.(*banktypes.QueryBalanceResponse) | |
if !ok { | |
return nil, fmt.Errorf("unexpected response type: %T", res) | |
} | |
return balanceRes, nil | |
} |
@@ -94,3 +95,32 @@ func DeterministicIterations[request, response proto.Message]( | |||
assert.DeepEqual(t, res, prevRes) | |||
} | |||
} | |||
|
|||
func DeterministicIterationsV2[request, response proto.Message]( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider renaming 'DeterministicIterationsV2' to a more descriptive name
The function name DeterministicIterationsV2
does not clearly convey the purpose or the difference from the original DeterministicIterations
. Using version suffixes like V2
is discouraged in function names as per the Uber Go Style Guide.
Consider renaming the function to reflect its specific functionality or distinctions from the previous version, possibly highlighting that it's tailored for the server/v2 architecture.
Abci: DefaultConsensusParams.Abci, | ||
Synchrony: DefaultConsensusParams.Synchrony, | ||
Feature: DefaultConsensusParams.Feature, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove non-existent fields from DefaultConsensusParams
usage
The DefaultConsensusParams
struct does not have fields named Abci
, Synchrony
, or Feature
. Attempting to access these fields will result in a compilation error.
Apply this diff to remove the invalid field references:
Authority: "consensus",
Block: DefaultConsensusParams.Block,
Evidence: DefaultConsensusParams.Evidence,
Validator: DefaultConsensusParams.Validator,
- Abci: DefaultConsensusParams.Abci,
- Synchrony: DefaultConsensusParams.Synchrony,
- Feature: DefaultConsensusParams.Feature,
},
If these fields are necessary, ensure that DefaultConsensusParams
is correctly defined with these fields or obtain them from the appropriate source.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
Abci: DefaultConsensusParams.Abci, | |
Synchrony: DefaultConsensusParams.Synchrony, | |
Feature: DefaultConsensusParams.Feature, | |
}, | |
Authority: "consensus", | |
Block: DefaultConsensusParams.Block, | |
Evidence: DefaultConsensusParams.Evidence, | |
Validator: DefaultConsensusParams.Validator, | |
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Outside diff range and nitpick comments (1)
server/v2/appmanager/appmanager.go (1)
138-150
: Improved readability and error handling. Consider using a switch statement.The refactoring of the
Query
method has improved both readability and error handling. The new structure is more concise and logical.Consider using a switch statement for better clarity:
var queryState corestore.ReaderMap var err error switch { case version != 0: queryState, err = a.db.StateAt(version) default: _, queryState, err = a.db.StateLatest() } if err != nil { return nil, err }This structure makes the logic even more explicit and is idiomatic Go.
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
📒 Files selected for processing (7)
- server/v2/appmanager/appmanager.go (2 hunks)
- server/v2/cometbft/abci.go (4 hunks)
- server/v2/cometbft/handlers/defaults.go (6 hunks)
- tests/integration/v2/app.go (1 hunks)
- tests/integration/v2/bank/determinisitic_test.go (1 hunks)
- tests/integration/v2/services.go (1 hunks)
- testutil/testdata/grpc_query.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/integration/v2/app.go
- tests/integration/v2/services.go
🧰 Additional context used
📓 Path-based instructions (5)
server/v2/appmanager/appmanager.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.server/v2/cometbft/abci.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.server/v2/cometbft/handlers/defaults.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.tests/integration/v2/bank/determinisitic_test.go (3)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Pattern
tests/**/*
: "Assess the integration and e2e test code assessing sufficient code coverage for the changes associated in the pull request"
Pattern
**/*_test.go
: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"testutil/testdata/grpc_query.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
🔇 Additional comments (11)
testutil/testdata/grpc_query.go (3)
9-17
: LGTM: New imports are correctly added and organized.The new imports are necessary for the
DeterministicIterationsV2
function and follow the Uber Go Style Guide for grouping and ordering.
101-101
: Consider renaming 'DeterministicIterationsV2' to a more descriptive nameThe function name
DeterministicIterationsV2
still includes a version suffix, which is discouraged as per the Uber Go Style Guide. Consider renaming the function to reflect its specific functionality or distinctions from the previous version, possibly highlighting that it's tailored for the server/v2 architecture.
101-127
: LGTM: Function logic is well-implementedThe
DeterministicIterationsV2
function is well-structured and implements the required functionality correctly. It usesrequire
for better error handling and avoids the variable shadowing issue mentioned in a previous review. The use of generics and function parameters makes it flexible and reusable.server/v2/appmanager/appmanager.go (1)
160-162
: Improved readability of method signature.The reformatting of the
QueryWithState
method signature enhances code readability without changing its functionality. This change is in line with good coding practices.server/v2/cometbft/abci.go (3)
192-194
: Function signature formatting improved.The Query function signature has been reformatted to improve readability by splitting it across multiple lines. This change enhances code clarity without altering the function's behavior.
243-245
: Function signature formatting improved.The InitChain function signature has been reformatted to improve readability by splitting it across multiple lines. This change enhances code clarity without altering the function's behavior.
561-563
: Function signature formatting improved.The ExtendVote function signature has been reformatted to improve readability by splitting it across multiple lines. This change enhances code clarity without altering the function's behavior.
tests/integration/v2/bank/determinisitic_test.go (2)
1-48
: LGTM: Imports and global variables are well-definedThe import statements cover all necessary packages for testing the bank module, and the global variables are appropriately defined for use in the test cases.
1-627
: Overall assessment: Well-structured tests with room for enhancementThe integration tests for the bank module are comprehensive and well-structured, covering various scenarios using both property-based testing with rapid and specific test cases. The tests demonstrate a good understanding of the bank module's functionalities and aim to ensure its correctness.
However, there are several areas where the tests can be improved:
- Error handling in query methods of the
deterministicFixture
struct.- Additional assertions in various test functions to verify the correctness of returned data.
- More robust checks in property-based tests to cover edge cases.
Implementing the suggested improvements will significantly enhance the quality and reliability of these tests, providing stronger guarantees about the correctness of the bank module's implementation.
server/v2/cometbft/handlers/defaults.go (2)
43-43
: Confirm that ignoring thegas
return value fromapp.Query
is appropriateIn multiple locations (lines 43, 116, and 184-186), the
gas
value returned fromapp.Query
is ignored using_
. Please ensure that disregarding this value does not have unintended consequences and that it is acceptable in these contexts.Also applies to: 116-116, 184-186
20-22
: Update all implementations ofAppManager[T].Query
to match the new method signatureThe method signature of
AppManager[T].Query
has been updated to include an additionalgas gas.Gas
return value. Ensure that all implementations of this interface are updated accordingly to prevent compilation errors.Run the following script to find implementations of
AppManager[T].Query
that may need updating:
func TestQueryBalance(t *testing.T) { | ||
t.Parallel() | ||
f := initDeterministicFixture(t) | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory := integration.GasMeterFactory(f.ctx) | ||
assertBalance := func(coin sdk.Coin) func(t *testing.T, res *banktypes.QueryBalanceResponse) { | ||
return func(t *testing.T, res *banktypes.QueryBalanceResponse) { | ||
require.Equal(t, coin.Denom, res.Balance.Denom) | ||
require.Truef(t, coin.Amount.Equal(res.Balance.Amount), | ||
"expected %s, got %s", coin.Amount, res.Balance.Amount) | ||
} | ||
} | ||
|
||
rapid.Check(t, func(rt *rapid.T) { | ||
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | ||
coin := getCoin(rt) | ||
fundAccount(f, addr, coin) | ||
|
||
addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr) | ||
require.NoError(t, err) | ||
|
||
req := banktypes.NewQueryBalanceRequest(addrStr, coin.GetDenom()) | ||
|
||
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | ||
f.QueryBalance, assertNonZeroGas, assertBalance(coin)) | ||
}) | ||
|
||
fundAccount(f, addr1, coin1) | ||
addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) | ||
require.NoError(t, err) | ||
req := banktypes.NewQueryBalanceRequest(addr1Str, coin1.GetDenom()) | ||
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | ||
f.QueryBalance, assertNonZeroGas, assertBalance(coin1)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance assertion in TestQueryBalance rapid check
The TestQueryBalance
function is well-implemented, but the assertion in the rapid check could be more robust.
Consider adding an assertion to check if the balance is greater than zero:
assertBalance := func(coin sdk.Coin) func(t *testing.T, res *banktypes.QueryBalanceResponse) {
return func(t *testing.T, res *banktypes.QueryBalanceResponse) {
require.Equal(t, coin.Denom, res.Balance.Denom)
require.Truef(t, coin.Amount.Equal(res.Balance.Amount),
"expected %s, got %s", coin.Amount, res.Balance.Amount)
+ require.True(t, res.Balance.Amount.IsPositive(), "balance should be positive")
}
}
This additional check ensures that the balance is always positive, which is an expected invariant for account balances.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func TestQueryBalance(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
assertBalance := func(coin sdk.Coin) func(t *testing.T, res *banktypes.QueryBalanceResponse) { | |
return func(t *testing.T, res *banktypes.QueryBalanceResponse) { | |
require.Equal(t, coin.Denom, res.Balance.Denom) | |
require.Truef(t, coin.Amount.Equal(res.Balance.Amount), | |
"expected %s, got %s", coin.Amount, res.Balance.Amount) | |
} | |
} | |
rapid.Check(t, func(rt *rapid.T) { | |
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | |
coin := getCoin(rt) | |
fundAccount(f, addr, coin) | |
addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr) | |
require.NoError(t, err) | |
req := banktypes.NewQueryBalanceRequest(addrStr, coin.GetDenom()) | |
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | |
f.QueryBalance, assertNonZeroGas, assertBalance(coin)) | |
}) | |
fundAccount(f, addr1, coin1) | |
addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) | |
require.NoError(t, err) | |
req := banktypes.NewQueryBalanceRequest(addr1Str, coin1.GetDenom()) | |
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | |
f.QueryBalance, assertNonZeroGas, assertBalance(coin1)) | |
} | |
func TestQueryBalance(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
assertBalance := func(coin sdk.Coin) func(t *testing.T, res *banktypes.QueryBalanceResponse) { | |
return func(t *testing.T, res *banktypes.QueryBalanceResponse) { | |
require.Equal(t, coin.Denom, res.Balance.Denom) | |
require.Truef(t, coin.Amount.Equal(res.Balance.Amount), | |
"expected %s, got %s", coin.Amount, res.Balance.Amount) | |
require.True(t, res.Balance.Amount.IsPositive(), "balance should be positive") | |
} | |
} | |
rapid.Check(t, func(rt *rapid.T) { | |
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | |
coin := getCoin(rt) | |
fundAccount(f, addr, coin) | |
addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr) | |
require.NoError(t, err) | |
req := banktypes.NewQueryBalanceRequest(addrStr, coin.GetDenom()) | |
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | |
f.QueryBalance, assertNonZeroGas, assertBalance(coin)) | |
}) | |
fundAccount(f, addr1, coin1) | |
addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) | |
require.NoError(t, err) | |
req := banktypes.NewQueryBalanceRequest(addr1Str, coin1.GetDenom()) | |
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | |
f.QueryBalance, assertNonZeroGas, assertBalance(coin1)) | |
} |
func TestQueryParams(t *testing.T) { | ||
t.Parallel() | ||
f := initDeterministicFixture(t) | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory := integration.GasMeterFactory(f.ctx) | ||
|
||
rapid.Check(t, func(rt *rapid.T) { | ||
enabledStatus := banktypes.SendEnabled{ | ||
Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), | ||
Enabled: rapid.Bool().Draw(rt, "status"), | ||
} | ||
|
||
params := banktypes.Params{ | ||
SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, | ||
DefaultSendEnabled: rapid.Bool().Draw(rt, "send"), | ||
} | ||
|
||
err := f.bankKeeper.SetParams(f.ctx, params) | ||
require.NoError(t, err) | ||
|
||
req := &banktypes.QueryParamsRequest{} | ||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, nil) | ||
}) | ||
|
||
enabledStatus := banktypes.SendEnabled{ | ||
Denom: "denom", | ||
Enabled: true, | ||
} | ||
|
||
params := banktypes.Params{ | ||
SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, | ||
DefaultSendEnabled: false, | ||
} | ||
|
||
err := f.bankKeeper.SetParams(f.ctx, params) | ||
require.NoError(t, err) | ||
req := &banktypes.QueryParamsRequest{} | ||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, nil) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add assertions to TestQueryParams
The TestQueryParams
function is well-structured, but it lacks specific assertions on the returned parameters.
Consider adding assertions to verify the correctness of the returned parameters:
testdata.DeterministicIterationsV2(
- t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, nil)
+ t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryParamsResponse) {
+ require.Equal(t, params.DefaultSendEnabled, res.Params.DefaultSendEnabled, "DefaultSendEnabled should match")
+ require.Equal(t, len(params.SendEnabled), len(res.Params.SendEnabled), "SendEnabled length should match")
+ for i, sendEnabled := range params.SendEnabled {
+ require.Equal(t, sendEnabled.Denom, res.Params.SendEnabled[i].Denom, "SendEnabled denom should match")
+ require.Equal(t, sendEnabled.Enabled, res.Params.SendEnabled[i].Enabled, "SendEnabled status should match")
+ }
+ })
These assertions will ensure that the parameters returned by the query match the expected values set in the test.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func TestQueryParams(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
enabledStatus := banktypes.SendEnabled{ | |
Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), | |
Enabled: rapid.Bool().Draw(rt, "status"), | |
} | |
params := banktypes.Params{ | |
SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, | |
DefaultSendEnabled: rapid.Bool().Draw(rt, "send"), | |
} | |
err := f.bankKeeper.SetParams(f.ctx, params) | |
require.NoError(t, err) | |
req := &banktypes.QueryParamsRequest{} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, nil) | |
}) | |
enabledStatus := banktypes.SendEnabled{ | |
Denom: "denom", | |
Enabled: true, | |
} | |
params := banktypes.Params{ | |
SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, | |
DefaultSendEnabled: false, | |
} | |
err := f.bankKeeper.SetParams(f.ctx, params) | |
require.NoError(t, err) | |
req := &banktypes.QueryParamsRequest{} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, nil) | |
} | |
func TestQueryParams(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
enabledStatus := banktypes.SendEnabled{ | |
Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), | |
Enabled: rapid.Bool().Draw(rt, "status"), | |
} | |
params := banktypes.Params{ | |
SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, | |
DefaultSendEnabled: rapid.Bool().Draw(rt, "send"), | |
} | |
err := f.bankKeeper.SetParams(f.ctx, params) | |
require.NoError(t, err) | |
req := &banktypes.QueryParamsRequest{} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryParamsResponse) { | |
require.Equal(t, params.DefaultSendEnabled, res.Params.DefaultSendEnabled, "DefaultSendEnabled should match") | |
require.Equal(t, len(params.SendEnabled), len(res.Params.SendEnabled), "SendEnabled length should match") | |
for i, sendEnabled := range params.SendEnabled { | |
require.Equal(t, sendEnabled.Denom, res.Params.SendEnabled[i].Denom, "SendEnabled denom should match") | |
require.Equal(t, sendEnabled.Enabled, res.Params.SendEnabled[i].Enabled, "SendEnabled status should match") | |
} | |
}) | |
}) | |
enabledStatus := banktypes.SendEnabled{ | |
Denom: "denom", | |
Enabled: true, | |
} | |
params := banktypes.Params{ | |
SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, | |
DefaultSendEnabled: false, | |
} | |
err := f.bankKeeper.SetParams(f.ctx, params) | |
require.NoError(t, err) | |
req := &banktypes.QueryParamsRequest{} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryParams, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryParamsResponse) { | |
require.Equal(t, params.DefaultSendEnabled, res.Params.DefaultSendEnabled, "DefaultSendEnabled should match") | |
require.Equal(t, len(params.SendEnabled), len(res.Params.SendEnabled), "SendEnabled length should match") | |
for i, sendEnabled := range params.SendEnabled { | |
require.Equal(t, sendEnabled.Denom, res.Params.SendEnabled[i].Denom, "SendEnabled denom should match") | |
require.Equal(t, sendEnabled.Enabled, res.Params.SendEnabled[i].Enabled, "SendEnabled status should match") | |
} | |
}) | |
} |
func TestQueryAllBalances(t *testing.T) { | ||
t.Parallel() | ||
f := initDeterministicFixture(t) | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory := integration.GasMeterFactory(f.ctx) | ||
addressCodec := codectestutil.CodecOptions{}.GetAddressCodec() | ||
|
||
rapid.Check(t, func(rt *rapid.T) { | ||
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | ||
numCoins := rapid.IntRange(1, 10).Draw(rt, "num-count") | ||
coins := make(sdk.Coins, 0, numCoins) | ||
|
||
addrStr, err := addressCodec.BytesToString(addr) | ||
require.NoError(t, err) | ||
|
||
for i := 0; i < numCoins; i++ { | ||
coin := getCoin(rt) | ||
if exists, _ := coins.Find(coin.Denom); exists { | ||
t.Skip("duplicate denom") | ||
} | ||
// NewCoins sorts the denoms | ||
coins = sdk.NewCoins(append(coins, coin)...) | ||
} | ||
|
||
fundAccount(f, addr, coins...) | ||
|
||
req := banktypes.NewQueryAllBalancesRequest( | ||
addrStr, testdata.PaginationGenerator(rt, uint64(numCoins)).Draw(rt, "pagination"), false) | ||
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | ||
f.QueryAllBalances, assertNonZeroGas, nil) | ||
}) | ||
|
||
coins := sdk.NewCoins( | ||
sdk.NewCoin("stake", math.NewInt(10)), | ||
sdk.NewCoin("denom", math.NewInt(100)), | ||
) | ||
|
||
fundAccount(f, addr1, coins...) | ||
addr1Str, err := addressCodec.BytesToString(addr1) | ||
require.NoError(t, err) | ||
|
||
req := banktypes.NewQueryAllBalancesRequest(addr1Str, nil, false) | ||
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | ||
f.QueryAllBalances, assertNonZeroGas, nil) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance assertions in TestQueryAllBalances
The TestQueryAllBalances
function is well-implemented, but it could benefit from additional assertions to ensure the correctness of the returned balances.
Consider adding the following assertions within the rapid check:
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory,
- f.QueryAllBalances, assertNonZeroGas, nil)
+ f.QueryAllBalances, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryAllBalancesResponse) {
+ require.Equal(t, len(coins), len(res.Balances), "number of returned balances should match")
+ for _, coin := range coins {
+ found := false
+ for _, balance := range res.Balances {
+ if balance.Denom == coin.Denom {
+ require.True(t, coin.Amount.Equal(balance.Amount), "amounts should match for denom %s", coin.Denom)
+ found = true
+ break
+ }
+ }
+ require.True(t, found, "coin %s should be present in the response", coin.Denom)
+ }
+ })
These additional assertions will ensure that all funded coins are present in the response and that their amounts match the expected values.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func TestQueryAllBalances(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
addressCodec := codectestutil.CodecOptions{}.GetAddressCodec() | |
rapid.Check(t, func(rt *rapid.T) { | |
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | |
numCoins := rapid.IntRange(1, 10).Draw(rt, "num-count") | |
coins := make(sdk.Coins, 0, numCoins) | |
addrStr, err := addressCodec.BytesToString(addr) | |
require.NoError(t, err) | |
for i := 0; i < numCoins; i++ { | |
coin := getCoin(rt) | |
if exists, _ := coins.Find(coin.Denom); exists { | |
t.Skip("duplicate denom") | |
} | |
// NewCoins sorts the denoms | |
coins = sdk.NewCoins(append(coins, coin)...) | |
} | |
fundAccount(f, addr, coins...) | |
req := banktypes.NewQueryAllBalancesRequest( | |
addrStr, testdata.PaginationGenerator(rt, uint64(numCoins)).Draw(rt, "pagination"), false) | |
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | |
f.QueryAllBalances, assertNonZeroGas, nil) | |
}) | |
coins := sdk.NewCoins( | |
sdk.NewCoin("stake", math.NewInt(10)), | |
sdk.NewCoin("denom", math.NewInt(100)), | |
) | |
fundAccount(f, addr1, coins...) | |
addr1Str, err := addressCodec.BytesToString(addr1) | |
require.NoError(t, err) | |
req := banktypes.NewQueryAllBalancesRequest(addr1Str, nil, false) | |
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | |
f.QueryAllBalances, assertNonZeroGas, nil) | |
} | |
func TestQueryAllBalances(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
addressCodec := codectestutil.CodecOptions{}.GetAddressCodec() | |
rapid.Check(t, func(rt *rapid.T) { | |
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | |
numCoins := rapid.IntRange(1, 10).Draw(rt, "num-count") | |
coins := make(sdk.Coins, 0, numCoins) | |
addrStr, err := addressCodec.BytesToString(addr) | |
require.NoError(t, err) | |
for i := 0; i < numCoins; i++ { | |
coin := getCoin(rt) | |
if exists, _ := coins.Find(coin.Denom); exists { | |
t.Skip("duplicate denom") | |
} | |
// NewCoins sorts the denoms | |
coins = sdk.NewCoins(append(coins, coin)...) | |
} | |
fundAccount(f, addr, coins...) | |
req := banktypes.NewQueryAllBalancesRequest( | |
addrStr, testdata.PaginationGenerator(rt, uint64(numCoins)).Draw(rt, "pagination"), false) | |
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | |
f.QueryAllBalances, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryAllBalancesResponse) { | |
require.Equal(t, len(coins), len(res.Balances), "number of returned balances should match") | |
for _, coin := range coins { | |
found := false | |
for _, balance := range res.Balances { | |
if balance.Denom == coin.Denom { | |
require.True(t, coin.Amount.Equal(balance.Amount), "amounts should match for denom %s", coin.Denom) | |
found = true | |
break | |
} | |
} | |
require.True(t, found, "coin %s should be present in the response", coin.Denom) | |
} | |
}) | |
}) | |
coins := sdk.NewCoins( | |
sdk.NewCoin("stake", math.NewInt(10)), | |
sdk.NewCoin("denom", math.NewInt(100)), | |
) | |
fundAccount(f, addr1, coins...) | |
addr1Str, err := addressCodec.BytesToString(addr1) | |
require.NoError(t, err) | |
req := banktypes.NewQueryAllBalancesRequest(addr1Str, nil, false) | |
testdata.DeterministicIterationsV2(t, f.ctx, req, gasMeterFactory, | |
f.QueryAllBalances, assertNonZeroGas, nil) | |
} |
func createAndReturnMetadatas(t *rapid.T, count int) []banktypes.Metadata { | ||
denomsMetadata := make([]banktypes.Metadata, 0, count) | ||
for i := 0; i < count; i++ { | ||
|
||
denom := rapid.StringMatching(denomRegex).Draw(t, "denom") | ||
|
||
aliases := rapid.SliceOf(rapid.String()).Draw(t, "aliases") | ||
// In the GRPC server code, empty arrays are returned as nil | ||
if len(aliases) == 0 { | ||
aliases = nil | ||
} | ||
|
||
metadata := banktypes.Metadata{ | ||
Description: rapid.StringN(1, 100, 100).Draw(t, "desc"), | ||
DenomUnits: []*banktypes.DenomUnit{ | ||
{ | ||
Denom: denom, | ||
Exponent: rapid.Uint32().Draw(t, "exponent"), | ||
Aliases: aliases, | ||
}, | ||
}, | ||
Base: denom, | ||
Display: denom, | ||
Name: rapid.String().Draw(t, "name"), | ||
Symbol: rapid.String().Draw(t, "symbol"), | ||
URI: rapid.String().Draw(t, "uri"), | ||
URIHash: rapid.String().Draw(t, "uri-hash"), | ||
} | ||
|
||
denomsMetadata = append(denomsMetadata, metadata) | ||
} | ||
|
||
return denomsMetadata | ||
} | ||
|
||
func TestDenomsMetadata(t *testing.T) { | ||
t.Parallel() | ||
f := initDeterministicFixture(t) | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory := integration.GasMeterFactory(f.ctx) | ||
|
||
rapid.Check(t, func(rt *rapid.T) { | ||
count := rapid.IntRange(1, 3).Draw(rt, "count") | ||
denomsMetadata := createAndReturnMetadatas(rt, count) | ||
require.True(t, len(denomsMetadata) == count) | ||
|
||
for i := 0; i < count; i++ { | ||
f.bankKeeper.SetDenomMetaData(f.ctx, denomsMetadata[i]) | ||
} | ||
|
||
req := &banktypes.QueryDenomsMetadataRequest{ | ||
Pagination: testdata.PaginationGenerator(rt, uint64(count)).Draw(rt, "pagination"), | ||
} | ||
|
||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil) | ||
}) | ||
|
||
f = initDeterministicFixture(t) // reset | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory = integration.GasMeterFactory(f.ctx) | ||
|
||
f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) | ||
|
||
req := &banktypes.QueryDenomsMetadataRequest{} | ||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil) | ||
} | ||
|
||
func TestDenomMetadata(t *testing.T) { | ||
t.Parallel() | ||
f := initDeterministicFixture(t) | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory := integration.GasMeterFactory(f.ctx) | ||
|
||
rapid.Check(t, func(rt *rapid.T) { | ||
denomMetadata := createAndReturnMetadatas(rt, 1) | ||
require.True(t, len(denomMetadata) == 1) | ||
f.bankKeeper.SetDenomMetaData(f.ctx, denomMetadata[0]) | ||
|
||
req := &banktypes.QueryDenomMetadataRequest{ | ||
Denom: denomMetadata[0].Base, | ||
} | ||
|
||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil) | ||
}) | ||
|
||
f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) | ||
|
||
req := &banktypes.QueryDenomMetadataRequest{ | ||
Denom: metadataAtom.Base, | ||
} | ||
|
||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance metadata-related test assertions
The TestDenomsMetadata
and TestDenomMetadata
functions are well-implemented, but they could benefit from more specific assertions to ensure the correctness of the returned metadata.
For TestDenomsMetadata
, consider adding the following assertion:
testdata.DeterministicIterationsV2(
- t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil)
+ t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryDenomsMetadataResponse) {
+ require.Equal(t, len(denomsMetadata), len(res.Metadatas), "number of metadata entries should match")
+ for _, expected := range denomsMetadata {
+ found := false
+ for _, actual := range res.Metadatas {
+ if expected.Base == actual.Base {
+ require.Equal(t, expected, actual, "metadata for denom %s should match", expected.Base)
+ found = true
+ break
+ }
+ }
+ require.True(t, found, "metadata for denom %s should be present in the response", expected.Base)
+ }
+ })
For TestDenomMetadata
, add this assertion:
testdata.DeterministicIterationsV2(
- t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil)
+ t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryDenomMetadataResponse) {
+ require.Equal(t, denomMetadata[0], res.Metadata, "returned metadata should match the set metadata")
+ })
These additions will ensure that the returned metadata values match the expected metadata set in the tests.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func createAndReturnMetadatas(t *rapid.T, count int) []banktypes.Metadata { | |
denomsMetadata := make([]banktypes.Metadata, 0, count) | |
for i := 0; i < count; i++ { | |
denom := rapid.StringMatching(denomRegex).Draw(t, "denom") | |
aliases := rapid.SliceOf(rapid.String()).Draw(t, "aliases") | |
// In the GRPC server code, empty arrays are returned as nil | |
if len(aliases) == 0 { | |
aliases = nil | |
} | |
metadata := banktypes.Metadata{ | |
Description: rapid.StringN(1, 100, 100).Draw(t, "desc"), | |
DenomUnits: []*banktypes.DenomUnit{ | |
{ | |
Denom: denom, | |
Exponent: rapid.Uint32().Draw(t, "exponent"), | |
Aliases: aliases, | |
}, | |
}, | |
Base: denom, | |
Display: denom, | |
Name: rapid.String().Draw(t, "name"), | |
Symbol: rapid.String().Draw(t, "symbol"), | |
URI: rapid.String().Draw(t, "uri"), | |
URIHash: rapid.String().Draw(t, "uri-hash"), | |
} | |
denomsMetadata = append(denomsMetadata, metadata) | |
} | |
return denomsMetadata | |
} | |
func TestDenomsMetadata(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
count := rapid.IntRange(1, 3).Draw(rt, "count") | |
denomsMetadata := createAndReturnMetadatas(rt, count) | |
require.True(t, len(denomsMetadata) == count) | |
for i := 0; i < count; i++ { | |
f.bankKeeper.SetDenomMetaData(f.ctx, denomsMetadata[i]) | |
} | |
req := &banktypes.QueryDenomsMetadataRequest{ | |
Pagination: testdata.PaginationGenerator(rt, uint64(count)).Draw(rt, "pagination"), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil) | |
}) | |
f = initDeterministicFixture(t) // reset | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory = integration.GasMeterFactory(f.ctx) | |
f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) | |
req := &banktypes.QueryDenomsMetadataRequest{} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil) | |
} | |
func TestDenomMetadata(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
denomMetadata := createAndReturnMetadatas(rt, 1) | |
require.True(t, len(denomMetadata) == 1) | |
f.bankKeeper.SetDenomMetaData(f.ctx, denomMetadata[0]) | |
req := &banktypes.QueryDenomMetadataRequest{ | |
Denom: denomMetadata[0].Base, | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil) | |
}) | |
f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) | |
req := &banktypes.QueryDenomMetadataRequest{ | |
Denom: metadataAtom.Base, | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil) | |
} | |
func TestDenomsMetadata(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
count := rapid.IntRange(1, 3).Draw(rt, "count") | |
denomsMetadata := createAndReturnMetadatas(rt, count) | |
require.True(t, len(denomsMetadata) == count) | |
for i := 0; i < count; i++ { | |
f.bankKeeper.SetDenomMetaData(f.ctx, denomsMetadata[i]) | |
} | |
req := &banktypes.QueryDenomsMetadataRequest{ | |
Pagination: testdata.PaginationGenerator(rt, uint64(count)).Draw(rt, "pagination"), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryDenomsMetadataResponse) { | |
require.Equal(t, len(denomsMetadata), len(res.Metadatas), "number of metadata entries should match") | |
for _, expected := range denomsMetadata { | |
found := false | |
for _, actual := range res.Metadatas { | |
if expected.Base == actual.Base { | |
require.Equal(t, expected, actual, "metadata for denom %s should match", expected.Base) | |
found = true | |
break | |
} | |
} | |
require.True(t, found, "metadata for denom %s should be present in the response", expected.Base) | |
} | |
}) | |
}) | |
f = initDeterministicFixture(t) // reset | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory = integration.GasMeterFactory(f.ctx) | |
f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) | |
req := &banktypes.QueryDenomsMetadataRequest{} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomsMetadata, assertNonZeroGas, nil) | |
} | |
func TestDenomMetadata(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
denomMetadata := createAndReturnMetadatas(rt, 1) | |
require.True(t, len(denomMetadata) == 1) | |
f.bankKeeper.SetDenomMetaData(f.ctx, denomMetadata[0]) | |
req := &banktypes.QueryDenomMetadataRequest{ | |
Denom: denomMetadata[0].Base, | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryDenomMetadataResponse) { | |
require.Equal(t, denomMetadata[0], res.Metadata, "returned metadata should match the set metadata") | |
}) | |
}) | |
f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom) | |
req := &banktypes.QueryDenomMetadataRequest{ | |
Denom: metadataAtom.Base, | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomMetadata, assertNonZeroGas, nil) | |
} |
func TestQueryTotalSupply(t *testing.T) { | ||
t.Parallel() | ||
f := initDeterministicFixture(t) | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory := integration.GasMeterFactory(f.ctx) | ||
|
||
res, err := f.QueryTotalSupply(f.ctx, &banktypes.QueryTotalSupplyRequest{}) | ||
require.NoError(t, err) | ||
initialSupply := res.GetSupply() | ||
|
||
rapid.Check(t, func(rt *rapid.T) { | ||
numCoins := rapid.IntRange(1, 3).Draw(rt, "num-count") | ||
coins := make(sdk.Coins, 0, numCoins) | ||
|
||
for i := 0; i < numCoins; i++ { | ||
coin := sdk.NewCoin( | ||
rapid.StringMatching(denomRegex).Draw(rt, "denom"), | ||
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), | ||
) | ||
|
||
coins = coins.Add(coin) | ||
} | ||
|
||
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) | ||
|
||
initialSupply = initialSupply.Add(coins...) | ||
|
||
req := &banktypes.QueryTotalSupplyRequest{ | ||
Pagination: testdata.PaginationGenerator(rt, uint64(len(initialSupply))).Draw(rt, "pagination"), | ||
} | ||
|
||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, nil) | ||
}) | ||
|
||
f = initDeterministicFixture(t) // reset | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory = integration.GasMeterFactory(f.ctx) | ||
|
||
coins := sdk.NewCoins( | ||
sdk.NewCoin("foo", math.NewInt(10)), | ||
sdk.NewCoin("bar", math.NewInt(100)), | ||
) | ||
|
||
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) | ||
|
||
req := &banktypes.QueryTotalSupplyRequest{} | ||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, nil) | ||
} | ||
|
||
func TestQueryTotalSupplyOf(t *testing.T) { | ||
t.Parallel() | ||
f := initDeterministicFixture(t) | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory := integration.GasMeterFactory(f.ctx) | ||
|
||
rapid.Check(t, func(rt *rapid.T) { | ||
coin := sdk.NewCoin( | ||
rapid.StringMatching(denomRegex).Draw(rt, "denom"), | ||
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), | ||
) | ||
|
||
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) | ||
|
||
req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} | ||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, nil) | ||
}) | ||
|
||
coin := sdk.NewCoin("bar", math.NewInt(100)) | ||
|
||
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) | ||
req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} | ||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, nil) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance assertions in supply-related tests
The TestQueryTotalSupply
and TestQueryTotalSupplyOf
functions are well-implemented, but they could benefit from more specific assertions to ensure the correctness of the returned supply.
For TestQueryTotalSupply
, consider adding the following assertion:
testdata.DeterministicIterationsV2(
- t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, nil)
+ t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryTotalSupplyResponse) {
+ require.Equal(t, initialSupply.String(), res.Supply.String(), "total supply should match the expected value")
+ })
For TestQueryTotalSupplyOf
, add this assertion:
testdata.DeterministicIterationsV2(
- t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, nil)
+ t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, func(t *testing.T, res *banktypes.QuerySupplyOfResponse) {
+ require.Equal(t, coin.Amount, res.Amount.Amount, "supply of %s should match the minted amount", coin.Denom)
+ })
These additions will ensure that the returned supply values match the expected amounts based on the minted coins.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func TestQueryTotalSupply(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
res, err := f.QueryTotalSupply(f.ctx, &banktypes.QueryTotalSupplyRequest{}) | |
require.NoError(t, err) | |
initialSupply := res.GetSupply() | |
rapid.Check(t, func(rt *rapid.T) { | |
numCoins := rapid.IntRange(1, 3).Draw(rt, "num-count") | |
coins := make(sdk.Coins, 0, numCoins) | |
for i := 0; i < numCoins; i++ { | |
coin := sdk.NewCoin( | |
rapid.StringMatching(denomRegex).Draw(rt, "denom"), | |
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), | |
) | |
coins = coins.Add(coin) | |
} | |
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) | |
initialSupply = initialSupply.Add(coins...) | |
req := &banktypes.QueryTotalSupplyRequest{ | |
Pagination: testdata.PaginationGenerator(rt, uint64(len(initialSupply))).Draw(rt, "pagination"), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, nil) | |
}) | |
f = initDeterministicFixture(t) // reset | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory = integration.GasMeterFactory(f.ctx) | |
coins := sdk.NewCoins( | |
sdk.NewCoin("foo", math.NewInt(10)), | |
sdk.NewCoin("bar", math.NewInt(100)), | |
) | |
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) | |
req := &banktypes.QueryTotalSupplyRequest{} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, nil) | |
} | |
func TestQueryTotalSupplyOf(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
coin := sdk.NewCoin( | |
rapid.StringMatching(denomRegex).Draw(rt, "denom"), | |
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), | |
) | |
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) | |
req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, nil) | |
}) | |
coin := sdk.NewCoin("bar", math.NewInt(100)) | |
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) | |
req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, nil) | |
} | |
func TestQueryTotalSupply(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
res, err := f.QueryTotalSupply(f.ctx, &banktypes.QueryTotalSupplyRequest{}) | |
require.NoError(t, err) | |
initialSupply := res.GetSupply() | |
rapid.Check(t, func(rt *rapid.T) { | |
numCoins := rapid.IntRange(1, 3).Draw(rt, "num-count") | |
coins := make(sdk.Coins, 0, numCoins) | |
for i := 0; i < numCoins; i++ { | |
coin := sdk.NewCoin( | |
rapid.StringMatching(denomRegex).Draw(rt, "denom"), | |
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), | |
) | |
coins = coins.Add(coin) | |
} | |
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) | |
initialSupply = initialSupply.Add(coins...) | |
req := &banktypes.QueryTotalSupplyRequest{ | |
Pagination: testdata.PaginationGenerator(rt, uint64(len(initialSupply))).Draw(rt, "pagination"), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryTotalSupplyResponse) { | |
require.Equal(t, initialSupply.String(), res.Supply.String(), "total supply should match the expected value") | |
}) | |
}) | |
f = initDeterministicFixture(t) // reset | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory = integration.GasMeterFactory(f.ctx) | |
coins := sdk.NewCoins( | |
sdk.NewCoin("foo", math.NewInt(10)), | |
sdk.NewCoin("bar", math.NewInt(100)), | |
) | |
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins)) | |
req := &banktypes.QueryTotalSupplyRequest{} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryTotalSupply, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryTotalSupplyResponse) { | |
require.Equal(t, initialSupply.String(), res.Supply.String(), "total supply should match the expected value") | |
}) | |
} | |
func TestQueryTotalSupplyOf(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
coin := sdk.NewCoin( | |
rapid.StringMatching(denomRegex).Draw(rt, "denom"), | |
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), | |
) | |
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) | |
req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, func(t *testing.T, res *banktypes.QuerySupplyOfResponse) { | |
require.Equal(t, coin.Amount, res.Amount.Amount, "supply of %s should match the minted amount", coin.Denom) | |
}) | |
}) | |
coin := sdk.NewCoin("bar", math.NewInt(100)) | |
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin))) | |
req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QuerySupplyOf, assertNonZeroGas, func(t *testing.T, res *banktypes.QuerySupplyOfResponse) { | |
require.Equal(t, coin.Amount, res.Amount.Amount, "supply of %s should match the minted amount", coin.Denom) | |
}) | |
} |
|
||
rapid.Check(t, func(rt *rapid.T) { | ||
count := rapid.IntRange(0, 10).Draw(rt, "count") | ||
denoms := make([]string, 0, count) | ||
|
||
for i := 0; i < count; i++ { | ||
coin := banktypes.SendEnabled{ | ||
Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), | ||
Enabled: rapid.Bool().Draw(rt, "enabled-status"), | ||
} | ||
|
||
f.bankKeeper.SetSendEnabled(f.ctx, coin.Denom, coin.Enabled) | ||
denoms = append(denoms, coin.Denom) | ||
} | ||
|
||
allDenoms = append(allDenoms, denoms...) | ||
|
||
req := &banktypes.QuerySendEnabledRequest{ | ||
Denoms: denoms, | ||
// Pagination is only taken into account when `denoms` is an empty array | ||
Pagination: testdata.PaginationGenerator(rt, uint64(len(allDenoms))).Draw(rt, "pagination"), | ||
} | ||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, nil) | ||
}) | ||
|
||
coin1 := banktypes.SendEnabled{ | ||
Denom: "falsecoin", | ||
Enabled: false, | ||
} | ||
coin2 := banktypes.SendEnabled{ | ||
Denom: "truecoin", | ||
Enabled: true, | ||
} | ||
|
||
f.bankKeeper.SetSendEnabled(f.ctx, coin1.Denom, false) | ||
f.bankKeeper.SetSendEnabled(f.ctx, coin2.Denom, true) | ||
|
||
req := &banktypes.QuerySendEnabledRequest{ | ||
Denoms: []string{coin1.GetDenom(), coin2.GetDenom()}, | ||
} | ||
|
||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, nil) | ||
} | ||
|
||
func TestDenomOwners(t *testing.T) { | ||
t.Parallel() | ||
f := initDeterministicFixture(t) | ||
f.ctx = f.app.StateLatestContext(t) | ||
gasMeterFactory := integration.GasMeterFactory(f.ctx) | ||
|
||
rapid.Check(t, func(rt *rapid.T) { | ||
denom := rapid.StringMatching(denomRegex).Draw(rt, "denom") | ||
numAddr := rapid.IntRange(1, 10).Draw(rt, "number-address") | ||
for i := 0; i < numAddr; i++ { | ||
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | ||
|
||
coin := sdk.NewCoin( | ||
denom, | ||
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), | ||
) | ||
|
||
err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin)) | ||
require.NoError(t, err) | ||
} | ||
|
||
req := &banktypes.QueryDenomOwnersRequest{ | ||
Denom: denom, | ||
Pagination: testdata.PaginationGenerator(rt, uint64(numAddr)).Draw(rt, "pagination"), | ||
} | ||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil) | ||
}) | ||
|
||
denomOwners := []*banktypes.DenomOwner{ | ||
{ | ||
Address: "cosmos1qg65a9q6k2sqq7l3ycp428sqqpmqcucgzze299", | ||
Balance: coin1, | ||
}, | ||
{ | ||
Address: "cosmos1qglnsqgpq48l7qqzgs8qdshr6fh3gqq9ej3qut", | ||
Balance: coin1, | ||
}, | ||
} | ||
|
||
for i := 0; i < len(denomOwners); i++ { | ||
addr, err := sdk.AccAddressFromBech32(denomOwners[i].Address) | ||
require.NoError(t, err) | ||
|
||
err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin1)) | ||
require.NoError(t, err) | ||
} | ||
|
||
req := &banktypes.QueryDenomOwnersRequest{ | ||
Denom: coin1.GetDenom(), | ||
} | ||
testdata.DeterministicIterationsV2( | ||
t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance assertions in SendEnabled and DenomOwners tests
The TestSendEnabled
and TestDenomOwners
functions are well-implemented, but they could benefit from more specific assertions to ensure the correctness of the returned data.
For TestSendEnabled
, consider adding the following assertion:
testdata.DeterministicIterationsV2(
- t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, nil)
+ t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, func(t *testing.T, res *banktypes.QuerySendEnabledResponse) {
+ require.Equal(t, len(req.Denoms), len(res.SendEnabled), "number of SendEnabled entries should match")
+ for _, denom := range req.Denoms {
+ found := false
+ for _, sendEnabled := range res.SendEnabled {
+ if sendEnabled.Denom == denom {
+ enabled, _ := f.bankKeeper.IsSendEnabledDenom(f.ctx, denom)
+ require.Equal(t, enabled, sendEnabled.Enabled, "SendEnabled status for denom %s should match", denom)
+ found = true
+ break
+ }
+ }
+ require.True(t, found, "SendEnabled entry for denom %s should be present in the response", denom)
+ }
+ })
For TestDenomOwners
, add this assertion:
testdata.DeterministicIterationsV2(
- t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil)
+ t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryDenomOwnersResponse) {
+ require.Equal(t, len(denomOwners), len(res.DenomOwners), "number of DenomOwners should match")
+ for _, expected := range denomOwners {
+ found := false
+ for _, actual := range res.DenomOwners {
+ if expected.Address == actual.Address {
+ require.Equal(t, expected.Balance.Denom, actual.Balance.Denom, "denom should match for address %s", expected.Address)
+ require.True(t, expected.Balance.Amount.Equal(actual.Balance.Amount), "amount should match for address %s", expected.Address)
+ found = true
+ break
+ }
+ }
+ require.True(t, found, "DenomOwner for address %s should be present in the response", expected.Address)
+ }
+ })
These additions will ensure that the returned SendEnabled statuses and DenomOwners data match the expected values set in the tests.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
func TestSendEnabled(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
allDenoms := []string{} | |
rapid.Check(t, func(rt *rapid.T) { | |
count := rapid.IntRange(0, 10).Draw(rt, "count") | |
denoms := make([]string, 0, count) | |
for i := 0; i < count; i++ { | |
coin := banktypes.SendEnabled{ | |
Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), | |
Enabled: rapid.Bool().Draw(rt, "enabled-status"), | |
} | |
f.bankKeeper.SetSendEnabled(f.ctx, coin.Denom, coin.Enabled) | |
denoms = append(denoms, coin.Denom) | |
} | |
allDenoms = append(allDenoms, denoms...) | |
req := &banktypes.QuerySendEnabledRequest{ | |
Denoms: denoms, | |
// Pagination is only taken into account when `denoms` is an empty array | |
Pagination: testdata.PaginationGenerator(rt, uint64(len(allDenoms))).Draw(rt, "pagination"), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, nil) | |
}) | |
coin1 := banktypes.SendEnabled{ | |
Denom: "falsecoin", | |
Enabled: false, | |
} | |
coin2 := banktypes.SendEnabled{ | |
Denom: "truecoin", | |
Enabled: true, | |
} | |
f.bankKeeper.SetSendEnabled(f.ctx, coin1.Denom, false) | |
f.bankKeeper.SetSendEnabled(f.ctx, coin2.Denom, true) | |
req := &banktypes.QuerySendEnabledRequest{ | |
Denoms: []string{coin1.GetDenom(), coin2.GetDenom()}, | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, nil) | |
} | |
func TestDenomOwners(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
denom := rapid.StringMatching(denomRegex).Draw(rt, "denom") | |
numAddr := rapid.IntRange(1, 10).Draw(rt, "number-address") | |
for i := 0; i < numAddr; i++ { | |
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | |
coin := sdk.NewCoin( | |
denom, | |
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), | |
) | |
err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin)) | |
require.NoError(t, err) | |
} | |
req := &banktypes.QueryDenomOwnersRequest{ | |
Denom: denom, | |
Pagination: testdata.PaginationGenerator(rt, uint64(numAddr)).Draw(rt, "pagination"), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil) | |
}) | |
denomOwners := []*banktypes.DenomOwner{ | |
{ | |
Address: "cosmos1qg65a9q6k2sqq7l3ycp428sqqpmqcucgzze299", | |
Balance: coin1, | |
}, | |
{ | |
Address: "cosmos1qglnsqgpq48l7qqzgs8qdshr6fh3gqq9ej3qut", | |
Balance: coin1, | |
}, | |
} | |
for i := 0; i < len(denomOwners); i++ { | |
addr, err := sdk.AccAddressFromBech32(denomOwners[i].Address) | |
require.NoError(t, err) | |
err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin1)) | |
require.NoError(t, err) | |
} | |
req := &banktypes.QueryDenomOwnersRequest{ | |
Denom: coin1.GetDenom(), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil) | |
} | |
func TestSendEnabled(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
allDenoms := []string{} | |
rapid.Check(t, func(rt *rapid.T) { | |
count := rapid.IntRange(0, 10).Draw(rt, "count") | |
denoms := make([]string, 0, count) | |
for i := 0; i < count; i++ { | |
coin := banktypes.SendEnabled{ | |
Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"), | |
Enabled: rapid.Bool().Draw(rt, "enabled-status"), | |
} | |
f.bankKeeper.SetSendEnabled(f.ctx, coin.Denom, coin.Enabled) | |
denoms = append(denoms, coin.Denom) | |
} | |
allDenoms = append(allDenoms, denoms...) | |
req := &banktypes.QuerySendEnabledRequest{ | |
Denoms: denoms, | |
// Pagination is only taken into account when `denoms` is an empty array | |
Pagination: testdata.PaginationGenerator(rt, uint64(len(allDenoms))).Draw(rt, "pagination"), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, func(t *testing.T, res *banktypes.QuerySendEnabledResponse) { | |
require.Equal(t, len(req.Denoms), len(res.SendEnabled), "number of SendEnabled entries should match") | |
for _, denom := range req.Denoms { | |
found := false | |
for _, sendEnabled := range res.SendEnabled { | |
if sendEnabled.Denom == denom { | |
enabled, _ := f.bankKeeper.IsSendEnabledDenom(f.ctx, denom) | |
require.Equal(t, enabled, sendEnabled.Enabled, "SendEnabled status for denom %s should match", denom) | |
found = true | |
break | |
} | |
} | |
require.True(t, found, "SendEnabled entry for denom %s should be present in the response", denom) | |
} | |
}) | |
}) | |
coin1 := banktypes.SendEnabled{ | |
Denom: "falsecoin", | |
Enabled: false, | |
} | |
coin2 := banktypes.SendEnabled{ | |
Denom: "truecoin", | |
Enabled: true, | |
} | |
f.bankKeeper.SetSendEnabled(f.ctx, coin1.Denom, false) | |
f.bankKeeper.SetSendEnabled(f.ctx, coin2.Denom, true) | |
req := &banktypes.QuerySendEnabledRequest{ | |
Denoms: []string{coin1.GetDenom(), coin2.GetDenom()}, | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QuerySendEnabled, assertNonZeroGas, func(t *testing.T, res *banktypes.QuerySendEnabledResponse) { | |
require.Equal(t, len(req.Denoms), len(res.SendEnabled), "number of SendEnabled entries should match") | |
for _, denom := range req.Denoms { | |
found := false | |
for _, sendEnabled := range res.SendEnabled { | |
if sendEnabled.Denom == denom { | |
enabled, _ := f.bankKeeper.IsSendEnabledDenom(f.ctx, denom) | |
require.Equal(t, enabled, sendEnabled.Enabled, "SendEnabled status for denom %s should match", denom) | |
found = true | |
break | |
} | |
} | |
require.True(t, found, "SendEnabled entry for denom %s should be present in the response", denom) | |
} | |
}) | |
} | |
func TestDenomOwners(t *testing.T) { | |
t.Parallel() | |
f := initDeterministicFixture(t) | |
f.ctx = f.app.StateLatestContext(t) | |
gasMeterFactory := integration.GasMeterFactory(f.ctx) | |
rapid.Check(t, func(rt *rapid.T) { | |
denom := rapid.StringMatching(denomRegex).Draw(rt, "denom") | |
numAddr := rapid.IntRange(1, 10).Draw(rt, "number-address") | |
for i := 0; i < numAddr; i++ { | |
addr := testdata.AddressGenerator(rt).Draw(rt, "address") | |
coin := sdk.NewCoin( | |
denom, | |
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")), | |
) | |
err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin)) | |
require.NoError(t, err) | |
} | |
req := &banktypes.QueryDenomOwnersRequest{ | |
Denom: denom, | |
Pagination: testdata.PaginationGenerator(rt, uint64(numAddr)).Draw(rt, "pagination"), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, nil) | |
}) | |
denomOwners := []*banktypes.DenomOwner{ | |
{ | |
Address: "cosmos1qg65a9q6k2sqq7l3ycp428sqqpmqcucgzze299", | |
Balance: coin1, | |
}, | |
{ | |
Address: "cosmos1qglnsqgpq48l7qqzgs8qdshr6fh3gqq9ej3qut", | |
Balance: coin1, | |
}, | |
} | |
for i := 0; i < len(denomOwners); i++ { | |
addr, err := sdk.AccAddressFromBech32(denomOwners[i].Address) | |
require.NoError(t, err) | |
err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin1)) | |
require.NoError(t, err) | |
} | |
req := &banktypes.QueryDenomOwnersRequest{ | |
Denom: coin1.GetDenom(), | |
} | |
testdata.DeterministicIterationsV2( | |
t, f.ctx, req, gasMeterFactory, f.QueryDenomOwners, assertNonZeroGas, func(t *testing.T, res *banktypes.QueryDenomOwnersResponse) { | |
require.Equal(t, len(denomOwners), len(res.DenomOwners), "number of DenomOwners should match") | |
for _, expected := range denomOwners { | |
found := false | |
for _, actual := range res.DenomOwners { | |
if expected.Address == actual.Address { | |
require.Equal(t, expected.Balance.Denom, actual.Balance.Denom, "denom should match for address %s", expected.Address) | |
require.True(t, expected.Balance.Amount.Equal(actual.Balance.Amount), "amount should match for address %s", expected.Address) | |
found = true | |
break | |
} | |
} | |
require.True(t, found, "DenomOwner for address %s should be present in the response", expected.Address) | |
} | |
}) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Outside diff range and nitpick comments (3)
tests/integration/v2/bank/determinisitic_test.go (3)
347-354
: Check for error when setting bank parametersIn
TestQueryParams
, after callingf.bankKeeper.SetParams
, it is good practice to check for errors even if the current implementation does not return one. This ensures robustness against future changes where an error might be returned.Apply this diff to check for errors:
params := banktypes.Params{ SendEnabled: []*banktypes.SendEnabled{&enabledStatus}, DefaultSendEnabled: false, } -err := f.bankKeeper.SetParams(f.ctx, params) +require.NoError(t, f.bankKeeper.SetParams(f.ctx, params))
218-219
: Check for error when funding accountIn
TestQuerySpendableBalances
, after callingbanktestutil.FundAccount
, it's good practice to check for errors even if it's unlikely to occur. This ensures robustness and easier debugging.Ensure that the error is not overwritten and is properly checked:
err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, coins) -require.NoError(t, err) +require.NoError(t, err, "failed to fund account")
360-389
: Limit the length of random strings to avoid excessively large inputsIn the
createAndReturnMetadatas
function, the random strings generated for fields likeDescription
,Name
,Symbol
,URI
, andURIHash
can potentially be very long. This might lead to excessively large inputs that can slow down tests or cause unexpected failures.Consider limiting the length of the random strings generated:
metadata := banktypes.Metadata{ Description: rapid.StringN(1, 100, 100).Draw(t, "desc"), DenomUnits: []*banktypes.DenomUnit{ { Denom: denom, Exponent: rapid.Uint32().Draw(t, "exponent"), Aliases: aliases, }, }, Base: denom, Display: denom, - Name: rapid.String().Draw(t, "name"), - Symbol: rapid.String().Draw(t, "symbol"), - URI: rapid.String().Draw(t, "uri"), - URIHash: rapid.String().Draw(t, "uri-hash"), + Name: rapid.StringN(1, 50, 50).Draw(t, "name"), + Symbol: rapid.StringN(1, 10, 10).Draw(t, "symbol"), + URI: rapid.StringN(1, 100, 100).Draw(t, "uri"), + URIHash: rapid.StringN(1, 64, 64).Draw(t, "uri-hash"), }
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
📒 Files selected for processing (2)
- tests/integration/v2/bank/determinisitic_test.go (1 hunks)
- testutil/testdata/grpc_query.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- testutil/testdata/grpc_query.go
🧰 Additional context used
📓 Path-based instructions (1)
tests/integration/v2/bank/determinisitic_test.go (3)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
Pattern
tests/**/*
: "Assess the integration and e2e test code assessing sufficient code coverage for the changes associated in the pull request"
Pattern
**/*_test.go
: "Assess the unit test code assessing sufficient code coverage for the changes associated in the pull request"
🔇 Additional comments (3)
tests/integration/v2/bank/determinisitic_test.go (3)
185-191
:⚠️ Potential issueUndefined variable
addr1
inTestQueryAllBalances
The variable
addr1
is used but not defined in theTestQueryAllBalances
function. This will lead to a compilation error.Define
addr1
before using it. For example, you can declareaddr1
as:+ addr1 := testdata.AddressGenerator(t).Draw(t, "address") fundAccount(f, addr1, coins...) addr1Str, err := addressCodec.BytesToString(addr1) require.NoError(t, err) req := banktypes.NewQueryAllBalancesRequest(addr1Str, nil, false)
Likely invalid or redundant comment.
141-145
:⚠️ Potential issueUndefined variable
addr1
inTestQueryBalance
The variable
addr1
is used but not defined in theTestQueryBalance
function. This will lead to a compilation error.Define
addr1
before using it. For example, you can declareaddr1
as:+ addr1 := testdata.AddressGenerator(t).Draw(t, "address") fundAccount(f, addr1, coin1) addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) require.NoError(t, err) req := banktypes.NewQueryBalanceRequest(addr1Str, coin1.GetDenom())
Likely invalid or redundant comment.
230-238
:⚠️ Potential issueUndefined variable
addr1
inTestQuerySpendableBalances
The variable
addr1
is used but not defined in theTestQuerySpendableBalances
function. This will lead to a compilation error.Define
addr1
before using it. You can declareaddr1
as:+ addr1 := testdata.AddressGenerator(t).Draw(t, "address") err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr1, coins) require.NoError(t, err) addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1) require.NoError(t, err) req := banktypes.NewQuerySpendableBalancesRequest(addr1Str, nil)
Likely invalid or redundant comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (1)
runtime/v2/types.go (1)
Line range hint
22-69
: Code structure and style approved with a minor suggestionThe overall code structure and style adhere well to the Uber Golang style guide. The function names are descriptive, error handling is present, and comments are informative.
Consider refactoring the error handling in
validateProtoAnnotations
to use a more specific error type instead oferrors.Join
. This could provide more context about the nature of the errors. For example:type ProtoAnnotationError struct { Services []string Err error } func (e *ProtoAnnotationError) Error() string { return fmt.Sprintf("proto annotation validation failed for services %v: %v", e.Services, e.Err) } // In validateProtoAnnotations if len(serviceErrs) > 0 { return &ProtoAnnotationError{ Services: affectedServices, Err: errors.Join(serviceErrs...), } }This change would provide more structured information about which services failed validation, potentially making error handling and debugging easier for consumers of this function.
📜 Review details
Configuration used: .coderabbit.yml
Review profile: CHILL
📒 Files selected for processing (9)
- runtime/v2/module.go (9 hunks)
- runtime/v2/store.go (2 hunks)
- runtime/v2/types.go (1 hunks)
- server/v2/appmanager/appmanager.go (2 hunks)
- simapp/v2/app_di.go (3 hunks)
- tests/integration/v2/app.go (1 hunks)
- tests/integration/v2/bank/app_test.go (1 hunks)
- tests/integration/v2/bank/determinisitic_test.go (1 hunks)
- tests/integration/v2/services.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
- runtime/v2/module.go
- runtime/v2/store.go
- server/v2/appmanager/appmanager.go
- simapp/v2/app_di.go
- tests/integration/v2/app.go
- tests/integration/v2/bank/app_test.go
- tests/integration/v2/bank/determinisitic_test.go
- tests/integration/v2/services.go
🧰 Additional context used
📓 Path-based instructions (1)
runtime/v2/types.go (1)
Pattern
**/*.go
: Review the Golang code for conformity with the Uber Golang style guide, highlighting any deviations.
cosmossdk.io/store => ../store | ||
cosmossdk.io/store/v2 => ../store/v2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
store/v2 changes look no relation to this PR
@@ -237,7 +243,12 @@ replace ( | |||
cosmossdk.io/api => ../api | |||
cosmossdk.io/client/v2 => ../client/v2 | |||
cosmossdk.io/collections => ../collections | |||
cosmossdk.io/core => ../core |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't see any core update in this PR, why not use the pseudo version here?
Description
This PR creates integration tests for x/bank in server/v2 architecture by doing the following:
Author Checklist
All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.
I have...
!
in the type prefix if API or client breaking changeCHANGELOG.md
Reviewers Checklist
All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.
Please see Pull Request Reviewer section in the contributing guide for more information on how to review a pull request.
I have...
Summary by CodeRabbit
New Features
DefaultProviders
for improved dependency injection.StoreBuilder
for enhanced store management.Bug Fixes
Tests