Skip to content

112 get account balance api #119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Aug 6, 2019
7 changes: 6 additions & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ func startGrpcServer(port int, queryExecutor query.ExecutorInterface, p2pHostSer
actionTypeSwitcher,
query.NewAccountBalanceQuery(),
observer.NewObserver())

serv, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
apiLogger.Fatalf("failed to listen: %v\n", err)
Expand Down Expand Up @@ -75,6 +74,12 @@ func startGrpcServer(port int, queryExecutor query.ExecutorInterface, p2pHostSer
P2pHostService: p2pHostService,
})

// Set GRPC handler for account balance requests
rpc_service.RegisterAccountBalanceServiceServer(grpcServer, &handler.AccountBalanceHandler{Service: service.NewAccountBalanceService(
queryExecutor,
query.NewAccountBalanceQuery(),
)})

// run grpc-gateway handler
go func() {
if err := grpcServer.Serve(serv); err != nil {
Expand Down
32 changes: 32 additions & 0 deletions api/client/GetAccountBalance/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"context"

log "github.com/sirupsen/logrus"
rpc_model "github.com/zoobc/zoobc-core/common/model"
rpc_service "github.com/zoobc/zoobc-core/common/service"
"google.golang.org/grpc"
)

func main() {
conn, err := grpc.Dial(":3001", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %s", err)
}
defer conn.Close()

c := rpc_service.NewAccountBalanceServiceClient(conn)

response, err := c.GetAccountBalance(context.Background(), &rpc_model.GetAccountBalanceRequest{
AccountType: 0,
AccountAddress: "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgtN",
})

if err != nil {
log.Fatalf("error calling rpc_service.GetAccountBalance: %s", err)
}

log.Printf("response from remote rpc_service.GetBlockByID(): %s", response)

}
27 changes: 27 additions & 0 deletions api/handler/accountBalanceHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package handler

import (
"context"

"github.com/zoobc/zoobc-core/api/service"
"github.com/zoobc/zoobc-core/common/model"
)

type AccountBalanceHandler struct {
Service service.AccountBalanceServiceInterface
}

func (abh *AccountBalanceHandler) GetAccountBalance(ctx context.Context,
request *model.GetAccountBalanceRequest) (*model.GetAccountBalanceResponse, error) {
accountBalance, err := abh.Service.GetAccountBalance(request)
if err != nil {
return nil, err
}
return accountBalance, nil
}

func (abh *AccountBalanceHandler) GetAccountBalances(ctx context.Context,
request *model.GetAccountBalancesRequest) (*model.GetAccountBalancesResponse, error) {
// todo: implement this after have filter
return nil, nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be inserted //TODO or remove if it still not work yet

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added todo comment

}
51 changes: 51 additions & 0 deletions api/service/accountBalanceApiService.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package service

import (
"errors"
"github.com/zoobc/zoobc-core/common/model"
"github.com/zoobc/zoobc-core/common/query"
"github.com/zoobc/zoobc-core/common/util"
)

type (
AccountBalanceServiceInterface interface {
GetAccountBalance(request *model.GetAccountBalanceRequest) (*model.GetAccountBalanceResponse, error)
}

AccountBalanceService struct {
AccountBalanceQuery query.AccountBalanceQueryInterface
Executor query.ExecutorInterface
}
)

func NewAccountBalanceService(executor query.ExecutorInterface,
accountBalanceQuery query.AccountBalanceQueryInterface) *AccountBalanceService {
return &AccountBalanceService{
AccountBalanceQuery: accountBalanceQuery,
Executor: executor,
}
}

func (abs *AccountBalanceService) GetAccountBalance(request *model.GetAccountBalanceRequest) (*model.GetAccountBalanceResponse, error) {
var (
err error
accountBalances []*model.AccountBalance
)
accountID := util.CreateAccountIDFromAddress(request.AccountType, request.AccountAddress)
accountBalanceQuery, arg := abs.AccountBalanceQuery.GetAccountBalanceByAccountID(accountID)
rows, err := abs.Executor.ExecuteSelect(accountBalanceQuery, arg)

if err != nil {
return nil, err
}

accountBalances = abs.AccountBalanceQuery.BuildModel(accountBalances, rows)

if len(accountBalances) == 0 {
return nil, errors.New("error: account not found")
}

return &model.GetAccountBalanceResponse{
AccountBalance: accountBalances[0],
}, nil
}
163 changes: 163 additions & 0 deletions api/service/accountBalanceApiService_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package service

import (
"database/sql"
"errors"
"github.com/DATA-DOG/go-sqlmock"
"github.com/zoobc/zoobc-core/common/model"
"github.com/zoobc/zoobc-core/common/query"
"reflect"
"regexp"
"testing"
)

type (
// mock GetAccountBalance
mockExecutorGetAccountBalanceFail struct {
query.Executor
}
mockExecutorGetAccountBalanceNotFound struct {
query.Executor
}
mockExecutorGetAccountBalanceSuccess struct {
query.Executor
}
)

var mockAccountBalanceQuery = query.NewAccountBalanceQuery()

func (*mockExecutorGetAccountBalanceSuccess) ExecuteSelect(qe string, args ...interface{}) (*sql.Rows, error) {
db, mock, _ := sqlmock.New()
defer db.Close()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT`)).WillReturnRows(sqlmock.NewRows([]string{
"AccountId", "BlockHeight", "SpendableBalance", "Balance", "PopRevenue", "Latest"}).AddRow(
[]byte{1}, 1, 10000, 10000, 0, 1))
rows, _ := db.Query(qe)
return rows, nil
}

func (*mockExecutorGetAccountBalanceFail) ExecuteSelect(qe string, args ...interface{}) (*sql.Rows, error) {
return nil, errors.New("mockError:executeSelectFail")
}

func (*mockExecutorGetAccountBalanceNotFound) ExecuteSelect(qe string, args ...interface{}) (*sql.Rows, error) {
db, mock, _ := sqlmock.New()
defer db.Close()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT`)).WillReturnRows(sqlmock.NewRows([]string{
"AccountId", "BlockHeight", "SpendableBalance", "Balance", "PopRevenue", "Latest"}))
rows, _ := db.Query(qe)
return rows, nil
}

func TestAccountBalanceService_GetAccountBalance(t *testing.T) {
type fields struct {
AccountBalanceQuery query.AccountBalanceQueryInterface
Executor query.ExecutorInterface
}
type args struct {
request *model.GetAccountBalanceRequest
}
tests := []struct {
name string
fields fields
args args
want *model.GetAccountBalanceResponse
wantErr bool
}{
{
name: "GetAccountBalance:fail",
fields: fields{
AccountBalanceQuery: mockAccountBalanceQuery,
Executor: &mockExecutorGetAccountBalanceFail{},
},
args: args{request: &model.GetAccountBalanceRequest{
AccountType: 0,
AccountAddress: "BCZ000000000000",
}},
want: nil,
wantErr: true,
},
{
name: "GetAccountBalance:notFound",
fields: fields{
AccountBalanceQuery: mockAccountBalanceQuery,
Executor: &mockExecutorGetAccountBalanceNotFound{},
},
args: args{request: &model.GetAccountBalanceRequest{
AccountType: 0,
AccountAddress: "BCZ000000000000",
}},
want: nil,
wantErr: true,
},
{
name: "GetAccountBalance:success",
fields: fields{
AccountBalanceQuery: mockAccountBalanceQuery,
Executor: &mockExecutorGetAccountBalanceSuccess{},
},
args: args{request: &model.GetAccountBalanceRequest{
AccountType: 0,
AccountAddress: "BCZ000000000000",
}},
want: &model.GetAccountBalanceResponse{
AccountBalance: &model.AccountBalance{
AccountID: []byte{1},
BlockHeight: 1,
SpendableBalance: 10000,
Balance: 10000,
PopRevenue: 0,
Latest: true,
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
abs := &AccountBalanceService{
AccountBalanceQuery: tt.fields.AccountBalanceQuery,
Executor: tt.fields.Executor,
}
got, err := abs.GetAccountBalance(tt.args.request)
if (err != nil) != tt.wantErr {
t.Errorf("GetAccountBalance() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetAccountBalance() got = %v, want %v", got, tt.want)
}
})
}
}

func TestNewAccountBalanceService(t *testing.T) {
type args struct {
executor query.ExecutorInterface
accountBalanceQuery query.AccountBalanceQueryInterface
}
tests := []struct {
name string
args args
want *AccountBalanceService
}{
{
name: "NewAccountBalanceService:success",
args: args{
executor: nil,
accountBalanceQuery: nil,
},
want: &AccountBalanceService{
AccountBalanceQuery: nil,
Executor: nil,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewAccountBalanceService(tt.args.executor, tt.args.accountBalanceQuery); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewAccountBalanceService() = %v, want %v", got, tt.want)
}
})
}
}
Loading