Skip to content
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

Open
wants to merge 70 commits into
base: main
Choose a base branch
from

Conversation

kocubinski
Copy link
Member

@kocubinski kocubinski commented Sep 25, 2024

Description

This PR creates integration tests for x/bank in server/v2 architecture by doing the following:

  • Lift store/v2 building up into a depinject Provider (from builder.go) so that an integration test fixture can keep a handle to it
  • Create a server/v2 integration test fixture
  • Port x/bank integration tests to use that fixture

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...

  • included the correct type prefix in the PR title, you can find examples of the prefixes below:
  • confirmed ! in the type prefix if API or client breaking change
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • reviewed "Files changed" and left comments if necessary
  • included the necessary unit and integration tests
  • added a changelog entry to CHANGELOG.md
  • updated the relevant documentation or specification, including comments for documenting Go code
  • confirmed all CI checks have passed

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...

  • confirmed the correct type prefix in the PR title
  • confirmed all author checklist items have been addressed
  • reviewed state machine logic, API design and naming, documentation is accurate, tests and test coverage

Summary by CodeRabbit

  • New Features

    • Introduced a new DefaultProviders for improved dependency injection.
    • Added a StoreBuilder for enhanced store management.
    • Comprehensive testing framework for Cosmos SDK applications established.
    • Integrated event handling and refined service registration processes.
    • Enhanced genesis state management for blockchain initialization.
  • Bug Fixes

    • Corrected parameter naming in service registration methods.
  • Tests

    • Added extensive integration tests for bank module functionalities and application setup.
    • Introduced deterministic testing for balance queries and account management scenarios.
    • Enhanced testing capabilities with new query functions and transaction handling.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 consistency

Currently, the context f.ctx is initialized outside of initDeterministicFixture. For better encapsulation and to maintain consistency across tests, consider initializing the context within the initDeterministicFixture 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 options

In 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 in StateLatestContext comment

The 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 fetches

There 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

📥 Commits

Files that changed from the base of the PR and between de81b74 and 706a591.

📒 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.

Comment on lines 88 to 99
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)
})
Copy link
Contributor

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?

Comment on lines 38 to 39
res, err := f.app.Query(ctx, 0, req)
return res.(*banktypes.QueryBalanceResponse), err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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](
Copy link
Contributor

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.

testutil/testdata/grpc_query.go Outdated Show resolved Hide resolved
Comment on lines +226 to +229
Abci: DefaultConsensusParams.Abci,
Synchrony: DefaultConsensusParams.Synchrony,
Feature: DefaultConsensusParams.Feature,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
Abci: DefaultConsensusParams.Abci,
Synchrony: DefaultConsensusParams.Synchrony,
Feature: DefaultConsensusParams.Feature,
},
Authority: "consensus",
Block: DefaultConsensusParams.Block,
Evidence: DefaultConsensusParams.Evidence,
Validator: DefaultConsensusParams.Validator,
},

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📥 Commits

Files that changed from the base of the PR and between 706a591 and 869a492.

📒 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 name

The 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-implemented

The DeterministicIterationsV2 function is well-structured and implements the required functionality correctly. It uses require 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-defined

The 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 enhancement

The 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:

  1. Error handling in query methods of the deterministicFixture struct.
  2. Additional assertions in various test functions to verify the correctness of returned data.
  3. 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 the gas return value from app.Query is appropriate

In multiple locations (lines 43, 116, and 184-186), the gas value returned from app.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 of AppManager[T].Query to match the new method signature

The method signature of AppManager[T].Query has been updated to include an additional gas 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:

tests/integration/v2/bank/determinisitic_test.go Outdated Show resolved Hide resolved
Comment on lines 174 to 207
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))
}
Copy link
Contributor

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.

Suggested change
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))
}

Comment on lines 381 to 421
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)
}
Copy link
Contributor

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.

Suggested change
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")
}
})
}

Comment on lines 209 to 253
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)
}
Copy link
Contributor

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.

Suggested change
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)
}

tests/integration/v2/bank/determinisitic_test.go Outdated Show resolved Hide resolved
Comment on lines 423 to 519
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)
}
Copy link
Contributor

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.

Suggested change
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)
}

Comment on lines 303 to 379
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)
}
Copy link
Contributor

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.

Suggested change
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)
})
}

Comment on lines 521 to 627

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)
}
Copy link
Contributor

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.

Suggested change
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)
}
})
}

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 parameters

In TestQueryParams, after calling f.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 account

In TestQuerySpendableBalances, after calling banktestutil.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 inputs

In the createAndReturnMetadatas function, the random strings generated for fields like Description, Name, Symbol, URI, and URIHash 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

📥 Commits

Files that changed from the base of the PR and between 869a492 and 6a9e803.

📒 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 issue

Undefined variable addr1 in TestQueryAllBalances

The variable addr1 is used but not defined in the TestQueryAllBalances function. This will lead to a compilation error.

Define addr1 before using it. For example, you can declare addr1 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 issue

Undefined variable addr1 in TestQueryBalance

The variable addr1 is used but not defined in the TestQueryBalance function. This will lead to a compilation error.

Define addr1 before using it. For example, you can declare addr1 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 issue

Undefined variable addr1 in TestQuerySpendableBalances

The variable addr1 is used but not defined in the TestQuerySpendableBalances function. This will lead to a compilation error.

Define addr1 before using it. You can declare addr1 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 suggestion

The 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 of errors.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

📥 Commits

Files that changed from the base of the PR and between 6a9e803 and 8d34c75.

📒 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.

runtime/v2/types.go Show resolved Hide resolved
cosmossdk.io/store => ../store
cosmossdk.io/store/v2 => ../store/v2
Copy link
Contributor

@cool-develope cool-develope Oct 1, 2024

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
Copy link
Contributor

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants