Skip to content

Commit

Permalink
[TEST] optimize unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
myth committed May 17, 2024
1 parent 0ef903c commit 69d3892
Show file tree
Hide file tree
Showing 15 changed files with 1,426 additions and 22 deletions.
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ gen-contract:
gen-proto:
docker compose -f ${GEN_COMPOSE} up generate_proto
gen-mock:
docker compose -f ${GEN_COMPOSE} up generate_mock_internal
docker compose -f ${GEN_COMPOSE} up generate_mock_pkg
docker compose -f ${GEN_COMPOSE} up generate_mock
compose:
docker compose -f ${COMPOSE} up -d --build
get-accounts:
Expand Down
10 changes: 2 additions & 8 deletions developments/docker-compose.gen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,9 @@ services:
- "../idl/pb:/proto_out/openmyth/blockchain/idl/pb"
entrypoint: sh /app/gen-proto.sh

generate_mock_internal:
generate_mock:
image: vektra/mockery:latest
working_dir: /code
volumes:
- "../:/code:cached"
command: [ "--all", "--dir", "internal", "--case", "underscore" ]
generate_mock_pkg:
image: vektra/mockery:latest
working_dir: /code
volumes:
- "../:/code:cached"
command: [ "--all", "--dir", "pkg", "--case", "underscore" ]
command: [ "--all", "--dir", "./", "--case", "underscore" ]
23 changes: 23 additions & 0 deletions internal/contract/services/contract_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"context"
"errors"
"log/slog"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down Expand Up @@ -163,6 +165,9 @@ func (s *ContractReaderService) SendTransactionV2(ctx context.Context, req *pb.S
if !ok {
return nil, status.Errorf(codes.Unauthenticated, "unauthenticated")
}
if userCtx.UserID == "" {
return nil, status.Errorf(codes.Unauthenticated, "unauthenticated")
}
resp, err := s.userClient.GetUserPrivateKeyByID(ctx, &userPb.GetUserPrivateKeyByIDRequest{
UserId: userCtx.UserID,
})
Expand All @@ -174,6 +179,24 @@ func (s *ContractReaderService) SendTransactionV2(ctx context.Context, req *pb.S
return nil, status.Errorf(codes.InvalidArgument, "signature is not valid")
}

privateKey, err := crypto.HexToECDSA(resp.GetPrivateKey())
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to get private key: %v", err)
}
fromAddress := crypto.PubkeyToAddress(privateKey.PublicKey)
balance, err := s.myTokenRepo.BalanceOf(fromAddress)
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to get balance: %v", err)
}
var amount big.Int
if _, ok := amount.SetString(req.Amount, 10); !ok {
return nil, status.Errorf(codes.InvalidArgument, "amount is not valid")
}

if balance.Cmp(&amount) < 0 {
return nil, status.Errorf(codes.InvalidArgument, "balance is not enough")
}

b, err := proto.Marshal(&commonPb.Transaction{
PrivKey: resp.GetPrivateKey(),
To: req.GetTo(),
Expand Down
234 changes: 234 additions & 0 deletions internal/contract/services/contract_reader_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package services

import (
"context"
"fmt"
"math/big"
"testing"

"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"

pb "openmyth/blockchain/idl/pb/contract"
userPb "openmyth/blockchain/idl/pb/user"
"openmyth/blockchain/mocks"
mtdt "openmyth/blockchain/pkg/metadata"
"openmyth/blockchain/pkg/xerror"
)

func TestContractReaderService_SendTransactionV2(t *testing.T) {
t.Parallel()

type fields struct {
myTokenRepo *mocks.MyTokenRepository
publisher *mocks.Publisher
userClient *mocks.UserServiceClient
}
type args struct {
ctx context.Context
req *pb.SendTransactionV2Request
}

md := mtdt.ImportUserInfoToCtx(&mtdt.Payload{UserID: "user-id"})
ctx := metadata.NewIncomingContext(context.Background(), md)
var tests = []struct {
name string
args args
fields fields
wantErr error

setup func(fields fields)
}{
{
name: "happy case",
args: args{
ctx: ctx,
req: &pb.SendTransactionV2Request{
Signature: "0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa1b",
To: "0x0d3d7a5d1a8fa8e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e",
Amount: "1",
},
},
fields: fields{
myTokenRepo: mocks.NewMyTokenRepository(t),
publisher: mocks.NewPublisher(t),
userClient: mocks.NewUserServiceClient(t),
},
setup: func(fields fields) {

fields.userClient.On("GetUserPrivateKeyByID", mock.Anything, mock.Anything).Return(&userPb.GetUserPrivateKeyByIDResponse{
PrivateKey: "ae78c8b502571dba876742437f8bc78b689cf8518356c0921393d89caaf284ce",
Nonce: "bou",
}, nil)

fields.myTokenRepo.On("BalanceOf", mock.Anything).Return(big.NewInt(100), nil)

fields.publisher.On("Publish", mock.Anything, mock.Anything, mock.Anything).Return(nil)
},
},
{
name: "error unauthen ticated",
args: args{
ctx: context.Background(),
req: &pb.SendTransactionV2Request{
Signature: "0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa1b",
To: "0x0d3d7a5d1a8fa8e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e",
Amount: "1",
},
},
fields: fields{
myTokenRepo: mocks.NewMyTokenRepository(t),
publisher: mocks.NewPublisher(t),
userClient: mocks.NewUserServiceClient(t),
},
wantErr: status.Errorf(codes.Unauthenticated, "unauthenticated"),
setup: func(fields fields) {
},
},
{
name: "error unable to get user by id",
args: args{
ctx: ctx,
req: &pb.SendTransactionV2Request{
Signature: "0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa1b",
To: "0x0d3d7a5d1a8fa8e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e",
Amount: "1",
},
},
fields: fields{
myTokenRepo: mocks.NewMyTokenRepository(t),
publisher: mocks.NewPublisher(t),
userClient: mocks.NewUserServiceClient(t),
},
wantErr: status.Errorf(codes.Internal, "unable to get user: %v", xerror.ErrNotFound),
setup: func(fields fields) {
fields.userClient.On("GetUserPrivateKeyByID", mock.Anything, mock.Anything).Return(nil, xerror.ErrNotFound)
},
},
{
name: "error wrong signature",
args: args{
ctx: ctx,
req: &pb.SendTransactionV2Request{
Signature: "0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5213123",
To: "0x0d3d7a5d1a8fa8e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e",
Amount: "1",
},
},
fields: fields{
myTokenRepo: mocks.NewMyTokenRepository(t),
publisher: mocks.NewPublisher(t),
userClient: mocks.NewUserServiceClient(t),
},
wantErr: status.Errorf(codes.InvalidArgument, "signature is not valid"),
setup: func(fields fields) {
fields.userClient.On("GetUserPrivateKeyByID", mock.Anything, mock.Anything).Return(&userPb.GetUserPrivateKeyByIDResponse{
PrivateKey: "ae78c8b502571dba876742437f8bc78b689cf8518356c0921393d89caaf284ce",
Nonce: "bou",
}, nil)
},
},
{
name: "error failed to retrieve balance",
args: args{
ctx: ctx,
req: &pb.SendTransactionV2Request{
Signature: "0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa1b",
To: "0x0d3d7a5d1a8fa8e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e",
Amount: "1",
},
},
fields: fields{
myTokenRepo: mocks.NewMyTokenRepository(t),
publisher: mocks.NewPublisher(t),
userClient: mocks.NewUserServiceClient(t),
},
wantErr: status.Errorf(codes.Internal, "unable to get balance: %v", fmt.Errorf("something error")),
setup: func(fields fields) {

fields.userClient.On("GetUserPrivateKeyByID", mock.Anything, mock.Anything).Return(&userPb.GetUserPrivateKeyByIDResponse{
PrivateKey: "ae78c8b502571dba876742437f8bc78b689cf8518356c0921393d89caaf284ce",
Nonce: "bou",
}, nil)

fields.myTokenRepo.On("BalanceOf", mock.Anything).Return(nil, fmt.Errorf("something error"))

},
},
{
name: "error balance not enough",
args: args{
ctx: ctx,
req: &pb.SendTransactionV2Request{
Signature: "0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa1b",
To: "0x0d3d7a5d1a8fa8e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e",
Amount: "1000",
},
},
fields: fields{
myTokenRepo: mocks.NewMyTokenRepository(t),
publisher: mocks.NewPublisher(t),
userClient: mocks.NewUserServiceClient(t),
},
wantErr: status.Errorf(codes.InvalidArgument, "balance is not enough"),
setup: func(fields fields) {

fields.userClient.On("GetUserPrivateKeyByID", mock.Anything, mock.Anything).Return(&userPb.GetUserPrivateKeyByIDResponse{
PrivateKey: "ae78c8b502571dba876742437f8bc78b689cf8518356c0921393d89caaf284ce",
Nonce: "bou",
}, nil)

fields.myTokenRepo.On("BalanceOf", mock.Anything).Return(big.NewInt(100), nil)
},
},
{
name: "error publish failed",
args: args{
ctx: ctx,
req: &pb.SendTransactionV2Request{
Signature: "0xc83d417a3b99535e784a72af0d9772c019c776aa0dfe4313c001a5548f6cf254477f5334c30da59531bb521278edc98f1959009253dda4ee9f63fe5562ead5aa1b",
To: "0x0d3d7a5d1a8fa8e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e7b8a6d1b9c8c7a9d7e",
Amount: "1",
},
},
fields: fields{
myTokenRepo: mocks.NewMyTokenRepository(t),
publisher: mocks.NewPublisher(t),
userClient: mocks.NewUserServiceClient(t),
},
wantErr: status.Errorf(codes.Internal, "unable to send transaction: %v", fmt.Errorf("something error")),
setup: func(fields fields) {

fields.userClient.On("GetUserPrivateKeyByID", mock.Anything, mock.Anything).Return(&userPb.GetUserPrivateKeyByIDResponse{
PrivateKey: "ae78c8b502571dba876742437f8bc78b689cf8518356c0921393d89caaf284ce",
Nonce: "bou",
}, nil)

fields.myTokenRepo.On("BalanceOf", mock.Anything).Return(big.NewInt(100), nil)

fields.publisher.On("Publish", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("something error"))
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &ContractReaderService{
myTokenRepo: tt.fields.myTokenRepo,
publisher: tt.fields.publisher,
userClient: tt.fields.userClient,
}
tt.setup(tt.fields)
_, err := s.SendTransactionV2(tt.args.ctx, tt.args.req)
if tt.wantErr != nil {
require.NotNil(t, err)
require.Equal(t, tt.wantErr.Error(), err.Error())
} else {
require.Nil(t, err)
}
})
}
}
5 changes: 0 additions & 5 deletions internal/user-mgnt/services/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ func Test_authService_Login(t *testing.T) {
t.Parallel()
type fields struct {
userRepo *mocks.UserRepository
wg *sync.WaitGroup
}
type args struct {
ctx context.Context
Expand All @@ -125,7 +124,6 @@ func Test_authService_Login(t *testing.T) {
name: "happy case",
fields: fields{
userRepo: mocks.NewUserRepository(t),
wg: &sync.WaitGroup{},
},
args: args{
ctx: context.Background(),
Expand All @@ -145,7 +143,6 @@ func Test_authService_Login(t *testing.T) {
name: "error user not found",
fields: fields{
userRepo: mocks.NewUserRepository(t),
wg: &sync.WaitGroup{},
},
args: args{
ctx: context.Background(),
Expand All @@ -163,7 +160,6 @@ func Test_authService_Login(t *testing.T) {
name: "error wrong password",
fields: fields{
userRepo: mocks.NewUserRepository(t),
wg: &sync.WaitGroup{},
},
args: args{
ctx: context.Background(),
Expand All @@ -187,7 +183,6 @@ func Test_authService_Login(t *testing.T) {
}
tt.setup(tt.fields)
_, err := s.Login(tt.args.ctx, tt.args.req)
tt.fields.wg.Wait()
if tt.wantErr != nil {
require.NotNil(t, err)
require.Equal(t, tt.wantErr.Error(), err.Error())
Expand Down
Loading

0 comments on commit 69d3892

Please sign in to comment.