prysm-pulse/validator/client/beacon-api/beacon_api_helpers_test.go
terencechain d17996f8b0
Update to V4 🚀 (#12134)
* Update V3 from V4

* Fix build v3 -> v4

* Update ssz

* Update beacon_chain.pb.go

* Fix formatter import

* Update update-mockgen.sh comment to v4

* Fix conflicts. Pass build and tests

* Fix test
2023-03-17 18:52:56 +00:00

385 lines
8.5 KiB
Go

package beacon_api
import (
"bytes"
"context"
"encoding/json"
"errors"
"net/url"
"testing"
"github.com/golang/mock/gomock"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/apimiddleware"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/testing/assert"
"github.com/prysmaticlabs/prysm/v4/testing/require"
"github.com/prysmaticlabs/prysm/v4/validator/client/beacon-api/mock"
)
func TestBeaconApiHelpers(t *testing.T) {
tests := []struct {
name string
input string
valid bool
}{
{
name: "correct format",
input: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
valid: true,
},
{
name: "root too small",
input: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f",
valid: false,
},
{
name: "root too big",
input: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f22",
valid: false,
},
{
name: "empty root",
input: "",
valid: false,
},
{
name: "no 0x prefix",
input: "cf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2",
valid: false,
},
{
name: "invalid characters",
input: "0xzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
valid: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.valid, validRoot(tt.input))
})
}
}
func TestBeaconApiHelpers_TestUint64ToString(t *testing.T) {
const expectedResult = "1234"
const val = uint64(1234)
assert.Equal(t, expectedResult, uint64ToString(val))
assert.Equal(t, expectedResult, uint64ToString(primitives.Slot(val)))
assert.Equal(t, expectedResult, uint64ToString(primitives.ValidatorIndex(val)))
assert.Equal(t, expectedResult, uint64ToString(primitives.CommitteeIndex(val)))
assert.Equal(t, expectedResult, uint64ToString(primitives.Epoch(val)))
}
func TestBuildURL_NoParams(t *testing.T) {
wanted := "/aaa/bbb/ccc"
actual := buildURL("/aaa/bbb/ccc")
assert.Equal(t, wanted, actual)
}
func TestBuildURL_WithParams(t *testing.T) {
params := url.Values{}
params.Add("xxxx", "1")
params.Add("yyyy", "2")
params.Add("zzzz", "3")
wanted := "/aaa/bbb/ccc?xxxx=1&yyyy=2&zzzz=3"
actual := buildURL("/aaa/bbb/ccc", params)
assert.Equal(t, wanted, actual)
}
const forkEndpoint = "/eth/v1/beacon/states/head/fork"
func TestGetFork_Nominal(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
stateForkResponseJson := apimiddleware.StateForkResponseJson{}
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
expected := apimiddleware.StateForkResponseJson{
Data: &apimiddleware.ForkJson{
PreviousVersion: "0x1",
CurrentVersion: "0x2",
Epoch: "3",
},
}
ctx := context.Background()
jsonRestHandler.EXPECT().GetRestJsonResponse(
ctx,
forkEndpoint,
&stateForkResponseJson,
).Return(
nil,
nil,
).SetArg(
2,
expected,
).Times(1)
validatorClient := beaconApiValidatorClient{
jsonRestHandler: jsonRestHandler,
}
fork, err := validatorClient.getFork(ctx)
require.NoError(t, err)
assert.DeepEqual(t, &expected, fork)
}
func TestGetFork_Invalid(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
ctx := context.Background()
jsonRestHandler.EXPECT().GetRestJsonResponse(
ctx,
forkEndpoint,
gomock.Any(),
).Return(
nil,
errors.New("custom error"),
).Times(1)
validatorClient := beaconApiValidatorClient{
jsonRestHandler: jsonRestHandler,
}
_, err := validatorClient.getFork(ctx)
require.ErrorContains(t, "failed to get json response from `/eth/v1/beacon/states/head/fork` REST endpoint", err)
}
const headersEndpoint = "/eth/v1/beacon/headers"
func TestGetHeaders_Nominal(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
blockHeadersResponseJson := apimiddleware.BlockHeadersResponseJson{}
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
expected := apimiddleware.BlockHeadersResponseJson{
Data: []*apimiddleware.BlockHeaderContainerJson{
{
Header: &apimiddleware.BeaconBlockHeaderContainerJson{
Message: &apimiddleware.BeaconBlockHeaderJson{
Slot: "42",
},
},
},
},
}
ctx := context.Background()
jsonRestHandler.EXPECT().GetRestJsonResponse(
ctx,
headersEndpoint,
&blockHeadersResponseJson,
).Return(
nil,
nil,
).SetArg(
2,
expected,
).Times(1)
validatorClient := beaconApiValidatorClient{
jsonRestHandler: jsonRestHandler,
}
headers, err := validatorClient.getHeaders(ctx)
require.NoError(t, err)
assert.DeepEqual(t, &expected, headers)
}
func TestGetHeaders_Invalid(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
ctx := context.Background()
jsonRestHandler.EXPECT().GetRestJsonResponse(
ctx,
headersEndpoint,
gomock.Any(),
).Return(
nil,
errors.New("custom error"),
).Times(1)
validatorClient := beaconApiValidatorClient{
jsonRestHandler: jsonRestHandler,
}
_, err := validatorClient.getHeaders(ctx)
require.ErrorContains(t, "failed to get json response from `/eth/v1/beacon/headers` REST endpoint", err)
}
const livenessEndpoint = "/eth/v1/validator/liveness/42"
func TestGetLiveness_Nominal(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
livenessResponseJson := apimiddleware.LivenessResponseJson{}
indexes := []string{"1", "2"}
marshalledIndexes, err := json.Marshal(indexes)
require.NoError(t, err)
expected := apimiddleware.LivenessResponseJson{
Data: []*struct {
Index string `json:"index"`
IsLive bool `json:"is_live"`
}{
{
Index: "1",
IsLive: true,
},
{
Index: "2",
IsLive: false,
},
},
}
ctx := context.Background()
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
jsonRestHandler.EXPECT().PostRestJson(
ctx,
livenessEndpoint,
nil,
bytes.NewBuffer(marshalledIndexes),
&livenessResponseJson,
).SetArg(
4,
expected,
).Return(
nil,
nil,
).Times(1)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
liveness, err := validatorClient.getLiveness(ctx, 42, indexes)
require.NoError(t, err)
assert.DeepEqual(t, &expected, liveness)
}
func TestGetLiveness_Invalid(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.Background()
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
jsonRestHandler.EXPECT().PostRestJson(
ctx,
livenessEndpoint,
nil,
gomock.Any(),
gomock.Any(),
).Return(
nil,
errors.New("custom error"),
).Times(1)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
_, err := validatorClient.getLiveness(ctx, 42, nil)
require.ErrorContains(t, "failed to send POST data to `/eth/v1/validator/liveness/42` REST URL", err)
}
const syncingEnpoint = "/eth/v1/node/syncing"
func TestGetIsSyncing_Nominal(t *testing.T) {
testCases := []struct {
name string
isSyncing bool
}{
{
name: "Syncing",
isSyncing: true,
},
{
name: "Not syncing",
isSyncing: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
syncingResponseJson := apimiddleware.SyncingResponseJson{}
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
expected := apimiddleware.SyncingResponseJson{
Data: &helpers.SyncDetailsJson{
IsSyncing: testCase.isSyncing,
},
}
ctx := context.Background()
jsonRestHandler.EXPECT().GetRestJsonResponse(
ctx,
syncingEnpoint,
&syncingResponseJson,
).Return(
nil,
nil,
).SetArg(
2,
expected,
).Times(1)
validatorClient := beaconApiValidatorClient{
jsonRestHandler: jsonRestHandler,
}
isSyncing, err := validatorClient.isSyncing(ctx)
require.NoError(t, err)
assert.Equal(t, testCase.isSyncing, isSyncing)
})
}
}
func TestGetIsSyncing_Invalid(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
syncingResponseJson := apimiddleware.SyncingResponseJson{}
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
ctx := context.Background()
jsonRestHandler.EXPECT().GetRestJsonResponse(
ctx,
syncingEnpoint,
&syncingResponseJson,
).Return(
nil,
errors.New("custom error"),
).Times(1)
validatorClient := beaconApiValidatorClient{
jsonRestHandler: jsonRestHandler,
}
isSyncing, err := validatorClient.isSyncing(ctx)
assert.Equal(t, true, isSyncing)
assert.ErrorContains(t, "failed to get syncing status", err)
}