## Description This adds support for registering gRPC query server implementations that were generated using pulsar. It should make integration with the ORM easier. This should be backportable. This does not enable support for pulsar msg servers or tx's. --- ### 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](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] 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.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
175 lines
5.2 KiB
Go
175 lines
5.2 KiB
Go
package baseapp_test
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
dbm "github.com/tendermint/tm-db"
|
|
|
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
|
"github.com/cosmos/cosmos-sdk/codec/types"
|
|
"github.com/cosmos/cosmos-sdk/simapp"
|
|
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
)
|
|
|
|
func TestGRPCQueryRouter(t *testing.T) {
|
|
qr := baseapp.NewGRPCQueryRouter()
|
|
interfaceRegistry := testdata.NewTestInterfaceRegistry()
|
|
qr.SetInterfaceRegistry(interfaceRegistry)
|
|
testdata_pulsar.RegisterQueryServer(qr, testdata_pulsar.QueryImpl{})
|
|
helper := &baseapp.QueryServiceTestHelper{
|
|
GRPCQueryRouter: qr,
|
|
Ctx: sdk.Context{}.WithContext(context.Background()),
|
|
}
|
|
client := testdata.NewQueryClient(helper)
|
|
|
|
res, err := client.Echo(context.Background(), &testdata.EchoRequest{Message: "hello"})
|
|
require.Nil(t, err)
|
|
require.NotNil(t, res)
|
|
require.Equal(t, "hello", res.Message)
|
|
|
|
require.Panics(t, func() {
|
|
_, _ = client.Echo(context.Background(), nil)
|
|
})
|
|
|
|
res2, err := client.SayHello(context.Background(), &testdata.SayHelloRequest{Name: "Foo"})
|
|
require.Nil(t, err)
|
|
require.NotNil(t, res)
|
|
require.Equal(t, "Hello Foo!", res2.Greeting)
|
|
|
|
spot := &testdata.Dog{Name: "Spot", Size_: "big"}
|
|
any, err := types.NewAnyWithValue(spot)
|
|
require.NoError(t, err)
|
|
res3, err := client.TestAny(context.Background(), &testdata.TestAnyRequest{AnyAnimal: any})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, res3)
|
|
require.Equal(t, spot, res3.HasAnimal.Animal.GetCachedValue())
|
|
}
|
|
|
|
func TestRegisterQueryServiceTwice(t *testing.T) {
|
|
// Setup baseapp.
|
|
db := dbm.NewMemDB()
|
|
encCfg := simapp.MakeTestEncodingConfig()
|
|
logger, _ := log.NewDefaultLogger("plain", "info", false)
|
|
app := baseapp.NewBaseApp("test", logger, db)
|
|
app.SetInterfaceRegistry(encCfg.InterfaceRegistry)
|
|
testdata.RegisterInterfaces(encCfg.InterfaceRegistry)
|
|
|
|
// First time registering service shouldn't panic.
|
|
require.NotPanics(t, func() {
|
|
testdata.RegisterQueryServer(
|
|
app.GRPCQueryRouter(),
|
|
testdata.QueryImpl{},
|
|
)
|
|
})
|
|
|
|
// Second time should panic.
|
|
require.Panics(t, func() {
|
|
testdata.RegisterQueryServer(
|
|
app.GRPCQueryRouter(),
|
|
testdata.QueryImpl{},
|
|
)
|
|
})
|
|
}
|
|
|
|
// Tests that we don't have data races per
|
|
// https://github.com/cosmos/cosmos-sdk/issues/10324
|
|
// but with the same client connection being used concurrently.
|
|
func TestQueryDataRaces_sameConnectionToSameHandler(t *testing.T) {
|
|
var mu sync.Mutex
|
|
var helper *baseapp.QueryServiceTestHelper
|
|
makeClientConn := func(qr *baseapp.GRPCQueryRouter) *baseapp.QueryServiceTestHelper {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
if helper == nil {
|
|
helper = &baseapp.QueryServiceTestHelper{
|
|
GRPCQueryRouter: qr,
|
|
Ctx: sdk.Context{}.WithContext(context.Background()),
|
|
}
|
|
}
|
|
return helper
|
|
}
|
|
testQueryDataRacesSameHandler(t, makeClientConn)
|
|
}
|
|
|
|
// Tests that we don't have data races per
|
|
// https://github.com/cosmos/cosmos-sdk/issues/10324
|
|
// but with unique client connections requesting from the same handler concurrently.
|
|
func TestQueryDataRaces_uniqueConnectionsToSameHandler(t *testing.T) {
|
|
// Return a new handler for every single call.
|
|
testQueryDataRacesSameHandler(t, func(qr *baseapp.GRPCQueryRouter) *baseapp.QueryServiceTestHelper {
|
|
return &baseapp.QueryServiceTestHelper{
|
|
GRPCQueryRouter: qr,
|
|
Ctx: sdk.Context{}.WithContext(context.Background()),
|
|
}
|
|
})
|
|
}
|
|
|
|
func testQueryDataRacesSameHandler(t *testing.T, makeClientConn func(*baseapp.GRPCQueryRouter) *baseapp.QueryServiceTestHelper) {
|
|
t.Parallel()
|
|
|
|
qr := baseapp.NewGRPCQueryRouter()
|
|
interfaceRegistry := testdata.NewTestInterfaceRegistry()
|
|
qr.SetInterfaceRegistry(interfaceRegistry)
|
|
testdata.RegisterQueryServer(qr, testdata.QueryImpl{})
|
|
|
|
// The goal is to invoke the router concurrently and check for any data races.
|
|
// 0. Run with: go test -race
|
|
// 1. Synchronize every one of the 1,000 goroutines waiting to all query at the
|
|
// same time.
|
|
// 2. Once the greenlight is given, perform a query through the router.
|
|
var wg sync.WaitGroup
|
|
defer wg.Wait()
|
|
|
|
greenlight := make(chan bool)
|
|
n := 1000
|
|
ready := make(chan bool, n)
|
|
go func() {
|
|
for i := 0; i < n; i++ {
|
|
<-ready
|
|
}
|
|
close(greenlight)
|
|
}()
|
|
|
|
for i := 0; i < n; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
// Wait until we get the green light to start.
|
|
ready <- true
|
|
<-greenlight
|
|
|
|
client := testdata.NewQueryClient(makeClientConn(qr))
|
|
res, err := client.Echo(context.Background(), &testdata.EchoRequest{Message: "hello"})
|
|
require.Nil(t, err)
|
|
require.NotNil(t, res)
|
|
require.Equal(t, "hello", res.Message)
|
|
|
|
require.Panics(t, func() {
|
|
_, _ = client.Echo(context.Background(), nil)
|
|
})
|
|
|
|
res2, err := client.SayHello(context.Background(), &testdata.SayHelloRequest{Name: "Foo"})
|
|
require.Nil(t, err)
|
|
require.NotNil(t, res)
|
|
require.Equal(t, "Hello Foo!", res2.Greeting)
|
|
|
|
spot := &testdata.Dog{Name: "Spot", Size_: "big"}
|
|
any, err := types.NewAnyWithValue(spot)
|
|
require.NoError(t, err)
|
|
res3, err := client.TestAny(context.Background(), &testdata.TestAnyRequest{AnyAnimal: any})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, res3)
|
|
require.Equal(t, spot, res3.HasAnimal.Animal.GetCachedValue())
|
|
}()
|
|
}
|
|
}
|