laconicd-deprecated/x/registry/keeper/grpc_query_test.go
Thomas E Lackey 880367d5df 122: Fix attribute index key collision (#123)
Fix #122, where the structure of the index key allowed unintended collisions (see below).

This also adds a test cases which _fails_ under the old scheme, but passes now:

**Before:**

```
--- FAIL: TestKeeperTestSuite (0.31s)
    --- FAIL: TestKeeperTestSuite/TestGrpcGetRecordLists (0.09s)
        grpc_query_test.go:143:
                Error Trace:    /home/telackey/cerc/laconicd/x/registry/keeper/grpc_query_test.go:143
                                                        /home/telackey/cerc/laconicd/x/registry/keeper/suite.go:91
                Error:          Not equal:
                                expected: 0
                                actual  : 1
                Test:           TestKeeperTestSuite/TestGrpcGetRecordLists
        --- FAIL: TestKeeperTestSuite/TestGrpcGetRecordLists/Case_Filter_with_typ_(cerc-io/laconicd#122)_ (0.00s)
            testing.go:1490: test executed panic(nil) or runtime.Goexit: subtest may have called FailNow on a parent test
FAIL
FAIL    github.com/cerc-io/laconicd/x/registry/keeper   0.765s
FAIL
make: *** [Makefile:333: run-tests] Error 1

❯ laconic cns record list --all --typ eWebsiteRegistrationRecord
[
  {
    "id": "bafyreies5he2mxyrjso2quewwlmh6cisekkjnf7yijpd2742wrzxgzuazi",
    "names": null,
    "owners": [
      "FC9B9FB065D70DBB10C8F511348421C16669B37D"
    ],
    "bondId": "a9c7161fc154cf44ee61efc699a59c8a27c804bb23ce4c8a7ffa0a39fcc540b1",
    "createTime": "2023-11-28T19:09:03Z",
    "expiryTime": "2024-11-27T19:09:03Z",
    "attributes": {
      "url": "https://hello-urbit.laconic.com",
      "repo_registration_record_cid": "QmTZQ8ZJS6mALjEM2wY71msFno6zzxFftVCiZELj9xREPx",
      "build_artifact_cid": "~lostex-rabdur-labtul-moltev/hello-urbit",
      "tls_cert_cid": "QmR1acEmQt7Tjmhp9cFtymie2eFcrHURQKt9kGto1TQTW1",
      "type": "WebsiteRegistrationRecord",
      "version": "0.2.4"
    }
  }
...

❯ laconic cns record list --all --type WebsiteRegistrationRecord
[
  {
    "id": "bafyreies5he2mxyrjso2quewwlmh6cisekkjnf7yijpd2742wrzxgzuazi",
    "names": null,
    "owners": [
      "FC9B9FB065D70DBB10C8F511348421C16669B37D"
    ],
    "bondId": "a9c7161fc154cf44ee61efc699a59c8a27c804bb23ce4c8a7ffa0a39fcc540b1",
    "createTime": "2023-11-28T19:09:03Z",
    "expiryTime": "2024-11-27T19:09:03Z",
    "attributes": {
      "url": "https://hello-urbit.laconic.com",
      "repo_registration_record_cid": "QmTZQ8ZJS6mALjEM2wY71msFno6zzxFftVCiZELj9xREPx",
      "build_artifact_cid": "~lostex-rabdur-labtul-moltev/hello-urbit",
      "tls_cert_cid": "QmR1acEmQt7Tjmhp9cFtymie2eFcrHURQKt9kGto1TQTW1",
      "type": "WebsiteRegistrationRecord",
      "version": "0.2.4"
    }
  }
...
```

**After:**

```
ok      github.com/cerc-io/laconicd/x/registry/keeper   1.573s

❯ laconic cns record list --all --typ eWebsiteRegistrationRecord
[]

❯ laconic cns record list --all --type WebsiteRegistrationRecord
[
  {
    "id": "bafyreies5he2mxyrjso2quewwlmh6cisekkjnf7yijpd2742wrzxgzuazi",
    "names": null,
    "owners": [
      "FC9B9FB065D70DBB10C8F511348421C16669B37D"
    ],
    "bondId": "a9c7161fc154cf44ee61efc699a59c8a27c804bb23ce4c8a7ffa0a39fcc540b1",
    "createTime": "2023-11-28T19:09:03Z",
    "expiryTime": "2024-11-27T19:09:03Z",
    "attributes": {
      "url": "https://hello-urbit.laconic.com",
      "repo_registration_record_cid": "QmTZQ8ZJS6mALjEM2wY71msFno6zzxFftVCiZELj9xREPx",
      "build_artifact_cid": "~lostex-rabdur-labtul-moltev/hello-urbit",
      "tls_cert_cid": "QmR1acEmQt7Tjmhp9cFtymie2eFcrHURQKt9kGto1TQTW1",
      "type": "WebsiteRegistrationRecord",
      "version": "0.2.4"
    }
  }
...
```

Reviewed-on: cerc-io/laconicd#123
Co-authored-by: Thomas E Lackey <telackey@bozemanpass.com>
Co-committed-by: Thomas E Lackey <telackey@bozemanpass.com>
2023-11-29 00:05:56 +00:00

358 lines
8.7 KiB
Go

package keeper_test
import (
"context"
"fmt"
"os"
"github.com/cerc-io/laconicd/x/registry/client/cli"
"github.com/cerc-io/laconicd/x/registry/helpers"
"github.com/cerc-io/laconicd/x/registry/keeper"
registrytypes "github.com/cerc-io/laconicd/x/registry/types"
)
func (suite *KeeperTestSuite) TestGrpcQueryParams() {
grpcClient := suite.queryClient
testCases := []struct {
msg string
req *registrytypes.QueryParamsRequest
}{
{
"Get Params",
&registrytypes.QueryParamsRequest{},
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
resp, _ := grpcClient.Params(context.Background(), test.req)
defaultParams := registrytypes.DefaultParams()
suite.Require().Equal(defaultParams.String(), resp.GetParams().String())
})
}
}
func (suite *KeeperTestSuite) TestGrpcGetRecordLists() {
grpcClient, ctx := suite.queryClient, suite.ctx
sr := suite.Require()
var recordId string
examples := []string{
"/../helpers/examples/service_provider_example.yml",
"/../helpers/examples/website_registration_example.yml",
}
testCases := []struct {
msg string
req *registrytypes.QueryListRecordsRequest
createRecords bool
expErr bool
noOfRecords int
}{
{
"Empty Records",
&registrytypes.QueryListRecordsRequest{},
false,
false,
0,
},
{
"List Records",
&registrytypes.QueryListRecordsRequest{},
true,
false,
2,
},
{
"Filter with type",
&registrytypes.QueryListRecordsRequest{
Attributes: []*registrytypes.QueryListRecordsRequest_KeyValueInput{
{
Key: "type",
Value: &registrytypes.QueryListRecordsRequest_ValueInput{
Type: "string",
String_: "WebsiteRegistrationRecord",
},
},
},
All: true,
},
true,
false,
1,
},
{
"Filter test for key collision (https://git.vdb.to/cerc-io/laconicd/issues/122)",
&registrytypes.QueryListRecordsRequest{
Attributes: []*registrytypes.QueryListRecordsRequest_KeyValueInput{
{
Key: "typ",
Value: &registrytypes.QueryListRecordsRequest_ValueInput{
Type: "string",
String_: "eWebsiteRegistrationRecord",
},
},
},
All: true,
},
true,
false,
0,
},
{
"Filter with attributes ServiceProviderRegistration",
&registrytypes.QueryListRecordsRequest{
Attributes: []*registrytypes.QueryListRecordsRequest_KeyValueInput{
{
Key: "x500state_name",
Value: &registrytypes.QueryListRecordsRequest_ValueInput{
Type: "string",
String_: "california",
},
},
},
All: true,
},
true,
false,
1,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createRecords {
for _, example := range examples {
dir, err := os.Getwd()
sr.NoError(err)
payloadType, err := cli.GetPayloadFromFile(fmt.Sprint(dir, example))
sr.NoError(err)
payload, err := payloadType.ToPayload()
sr.NoError(err)
record, err := suite.app.RegistryKeeper.ProcessSetRecord(ctx, registrytypes.MsgSetRecord{
BondId: suite.bond.GetId(),
Signer: suite.accounts[0].String(),
Payload: payload,
})
sr.NoError(err)
sr.NotNil(record.ID)
}
}
resp, err := grpcClient.ListRecords(context.Background(), test.req)
if test.expErr {
suite.Error(err)
} else {
sr.NoError(err)
sr.Equal(test.noOfRecords, len(resp.GetRecords()))
if test.createRecords && test.noOfRecords > 0 {
recordId = resp.GetRecords()[0].GetId()
sr.NotZero(resp.GetRecords())
sr.Equal(resp.GetRecords()[0].GetBondId(), suite.bond.GetId())
for _, record := range resp.GetRecords() {
bz, err := registrytypes.GetJSONBytesFromAny(*record.Attributes)
sr.NoError(err)
recAttr := helpers.UnMarshalMapFromJSONBytes(bz)
for _, attr := range test.req.GetAttributes() {
if attr.Key[:4] == "x500" {
sr.Equal(keeper.GetAttributeValue(attr.Value), recAttr["x500"].(map[string]interface{})[attr.Key[4:]])
} else {
sr.Equal(keeper.GetAttributeValue(attr.Value), recAttr[attr.Key])
}
}
}
}
}
})
}
// Get the records by record id
testCases1 := []struct {
msg string
req *registrytypes.QueryRecordByIDRequest
createRecord bool
expErr bool
noOfRecords int
}{
{
"Invalid Request without record id",
&registrytypes.QueryRecordByIDRequest{},
false,
true,
0,
},
{
"With Record ID",
&registrytypes.QueryRecordByIDRequest{
Id: recordId,
},
true,
false,
1,
},
}
for _, test := range testCases1 {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
resp, err := grpcClient.GetRecord(context.Background(), test.req)
if test.expErr {
suite.Error(err)
} else {
sr.NoError(err)
sr.NotNil(resp.GetRecord())
if test.createRecord {
sr.Equal(resp.GetRecord().BondId, suite.bond.GetId())
sr.Equal(resp.GetRecord().Id, recordId)
}
}
})
}
// Get the records by record id
testCasesByBondID := []struct {
msg string
req *registrytypes.QueryRecordByBondIDRequest
createRecord bool
expErr bool
noOfRecords int
}{
{
"Invalid Request without bond id",
&registrytypes.QueryRecordByBondIDRequest{},
false,
true,
0,
},
{
"With Bond ID",
&registrytypes.QueryRecordByBondIDRequest{
Id: suite.bond.GetId(),
},
true,
false,
1,
},
}
for _, test := range testCasesByBondID {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
resp, err := grpcClient.GetRecordByBondID(context.Background(), test.req)
if test.expErr {
sr.Zero(resp.GetRecords())
} else {
sr.NoError(err)
sr.NotNil(resp.GetRecords())
if test.createRecord {
sr.NotZero(resp.GetRecords())
sr.Equal(resp.GetRecords()[0].GetBondId(), suite.bond.GetId())
}
}
})
}
}
func (suite *KeeperTestSuite) TestGrpcQueryRegistryModuleBalance() {
grpcClient, ctx := suite.queryClient, suite.ctx
sr := suite.Require()
examples := []string{
"/../helpers/examples/service_provider_example.yml",
"/../helpers/examples/website_registration_example.yml",
}
testCases := []struct {
msg string
req *registrytypes.GetRegistryModuleBalanceRequest
createRecords bool
expErr bool
noOfRecords int
}{
{
"Get Module Balance",
&registrytypes.GetRegistryModuleBalanceRequest{},
true,
false,
1,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createRecords {
dir, err := os.Getwd()
sr.NoError(err)
for _, example := range examples {
payloadType, err := cli.GetPayloadFromFile(fmt.Sprint(dir, example))
sr.NoError(err)
payload, err := payloadType.ToPayload()
sr.NoError(err)
record, err := suite.app.RegistryKeeper.ProcessSetRecord(ctx, registrytypes.MsgSetRecord{
BondId: suite.bond.GetId(),
Signer: suite.accounts[0].String(),
Payload: payload,
})
sr.NoError(err)
sr.NotNil(record.ID)
}
}
resp, err := grpcClient.GetRegistryModuleBalance(context.Background(), test.req)
if test.expErr {
suite.Error(err)
} else {
sr.NoError(err)
sr.Equal(test.noOfRecords, len(resp.GetBalances()))
if test.createRecords {
balance := resp.GetBalances()[0]
sr.Equal(balance.AccountName, registrytypes.RecordRentModuleAccountName)
}
}
})
}
}
func (suite *KeeperTestSuite) TestGrpcQueryWhoIS() {
grpcClient, ctx := suite.queryClient, suite.ctx
sr := suite.Require()
authorityName := "TestGrpcQueryWhoIS"
testCases := []struct {
msg string
req *registrytypes.QueryWhoisRequest
createName bool
expErr bool
noOfRecords int
}{
{
"Invalid Request without name",
&registrytypes.QueryWhoisRequest{},
false,
true,
1,
},
{
"Success",
&registrytypes.QueryWhoisRequest{},
true,
false,
1,
},
}
for _, test := range testCases {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createName {
err := suite.app.RegistryKeeper.ProcessReserveAuthority(ctx, registrytypes.MsgReserveAuthority{
Name: authorityName,
Signer: suite.accounts[0].String(),
Owner: suite.accounts[0].String(),
})
sr.NoError(err)
test.req = &registrytypes.QueryWhoisRequest{Name: authorityName}
}
resp, err := grpcClient.Whois(context.Background(), test.req)
if test.expErr {
sr.Zero(len(resp.NameAuthority.AuctionId))
} else {
sr.NoError(err)
if test.createName {
nameAuth := resp.NameAuthority
sr.NotNil(nameAuth)
sr.Equal(nameAuth.OwnerAddress, suite.accounts[0].String())
sr.Equal(registrytypes.AuthorityActive, nameAuth.Status)
}
}
})
}
}