package client import ( "context" "errors" "io/ioutil" "strings" "testing" "time" ptypes "github.com/gogo/protobuf/types" "github.com/golang/mock/gomock" pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/validator/internal" "github.com/sirupsen/logrus" ) func init() { logrus.SetLevel(logrus.DebugLevel) logrus.SetOutput(ioutil.Discard) } var _ = Validator(&validator{}) func TestWaitForChainStart_SetsChainStartGenesisTime(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := internal.NewMockBeaconServiceClient(ctrl) v := validator{ key: validatorKey, beaconClient: client, } genesis := uint64(time.Unix(0, 0).Unix()) clientStream := internal.NewMockBeaconService_WaitForChainStartClient(ctrl) client.EXPECT().WaitForChainStart( gomock.Any(), &ptypes.Empty{}, ).Return(clientStream, nil) clientStream.EXPECT().Recv().Return( &pb.ChainStartResponse{ Started: true, GenesisTime: genesis, }, nil, ) if err := v.WaitForChainStart(context.Background()); err != nil { t.Fatal(err) } if v.genesisTime != genesis { t.Errorf("Expected chain start time to equal %d, received %d", genesis, v.genesisTime) } if v.ticker == nil { t.Error("Expected ticker to be set, received nil") } } func TestWaitForChainStart_ContextCanceled(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := internal.NewMockBeaconServiceClient(ctrl) v := validator{ key: validatorKey, beaconClient: client, } genesis := uint64(time.Unix(0, 0).Unix()) clientStream := internal.NewMockBeaconService_WaitForChainStartClient(ctrl) client.EXPECT().WaitForChainStart( gomock.Any(), &ptypes.Empty{}, ).Return(clientStream, nil) clientStream.EXPECT().Recv().Return( &pb.ChainStartResponse{ Started: true, GenesisTime: genesis, }, nil, ) ctx, cancel := context.WithCancel(context.Background()) cancel() err := v.WaitForChainStart(ctx) want := "context has been canceled" if !strings.Contains(err.Error(), want) { t.Errorf("Expected %v, received %v", want, err) } } func TestWaitForChainStart_StreamSetupFails(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := internal.NewMockBeaconServiceClient(ctrl) v := validator{ key: validatorKey, beaconClient: client, } clientStream := internal.NewMockBeaconService_WaitForChainStartClient(ctrl) client.EXPECT().WaitForChainStart( gomock.Any(), &ptypes.Empty{}, ).Return(clientStream, errors.New("failed stream")) err := v.WaitForChainStart(context.Background()) want := "could not setup beacon chain ChainStart streaming client" if !strings.Contains(err.Error(), want) { t.Errorf("Expected %v, received %v", want, err) } } func TestWaitForChainStart_ReceiveErrorFromStream(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := internal.NewMockBeaconServiceClient(ctrl) v := validator{ key: validatorKey, beaconClient: client, } clientStream := internal.NewMockBeaconService_WaitForChainStartClient(ctrl) client.EXPECT().WaitForChainStart( gomock.Any(), &ptypes.Empty{}, ).Return(clientStream, nil) clientStream.EXPECT().Recv().Return( nil, errors.New("fails"), ) err := v.WaitForChainStart(context.Background()) want := "could not receive ChainStart from stream" if !strings.Contains(err.Error(), want) { t.Errorf("Expected %v, received %v", want, err) } } func TestUpdateAssignments_DoesNothingWhenNotEpochStartAndAlreadyExistingAssignments(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := internal.NewMockValidatorServiceClient(ctrl) slot := uint64(1) v := validator{ key: validatorKey, validatorClient: client, assignment: &pb.Assignment{ PublicKey: []byte{}, AttesterSlot: 10, ProposerSlot: 20, }, } client.EXPECT().ValidatorEpochAssignments( gomock.Any(), gomock.Any(), ).Times(0) if err := v.UpdateAssignments(context.Background(), slot); err != nil { t.Errorf("Could not update assignments: %v", err) } } func TestUpdateAssignments_ReturnsError(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := internal.NewMockValidatorServiceClient(ctrl) v := validator{ key: validatorKey, validatorClient: client, } expected := errors.New("bad") client.EXPECT().ValidatorEpochAssignments( gomock.Any(), gomock.Any(), ).Return(nil, expected) if err := v.UpdateAssignments(context.Background(), params.BeaconConfig().SlotsPerEpoch); err != expected { t.Errorf("Bad error; want=%v got=%v", expected, err) } } func TestUpdateAssignments_OK(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() client := internal.NewMockValidatorServiceClient(ctrl) slot := params.BeaconConfig().SlotsPerEpoch resp := &pb.ValidatorEpochAssignmentsResponse{ Assignment: &pb.Assignment{ ProposerSlot: 67, AttesterSlot: 78, }, } v := validator{ key: validatorKey, validatorClient: client, } client.EXPECT().ValidatorEpochAssignments( gomock.Any(), gomock.Any(), ).Return(resp, nil) if err := v.UpdateAssignments(context.Background(), slot); err != nil { t.Fatalf("Could not update assignments: %v", err) } if v.assignment.ProposerSlot != 67 { t.Errorf("Unexpected validator assignments. want=%v got=%v", 67, v.assignment.ProposerSlot) } if v.assignment.AttesterSlot != 78 { t.Errorf("Unexpected validator assignments. want=%v got=%v", 78, v.assignment.AttesterSlot) } }