Skip to content

Commit

Permalink
Merge pull request #19 from imrishuroy/gRPC-test
Browse files Browse the repository at this point in the history
test for rpc create & update user
  • Loading branch information
imrishuroy authored Dec 6, 2023
2 parents 05309a1 + 5fe42df commit d74ef6f
Show file tree
Hide file tree
Showing 6 changed files with 523 additions and 12 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ server:

mock:
mockgen -package mockdb -destination db/mock/store.go github.com/imrishuroy/simple_bank/db/sqlc Store
mockgen -package mockwk -destination worker/mock/distributor.go github.com/imrishuroy/simple_bank/worker TaskDistributor

proto:
protoc --proto_path=proto --go_out=pb --go_opt=paths=source_relative \
Expand Down
41 changes: 41 additions & 0 deletions gapi/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package gapi

import (
"context"
"fmt"
"testing"
"time"

db "github.com/imrishuroy/simplebank/db/sqlc"
"github.com/imrishuroy/simplebank/token"
"github.com/imrishuroy/simplebank/util"
"github.com/imrishuroy/simplebank/worker"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/metadata"
)

func newTestServer(t *testing.T, store db.Store, taskDistributor worker.TaskDistributor) *Server {
config := util.Config{
TokenSymmetricKey: util.RandomString(32),
AccessTokenDuration: time.Minute,
}

server, err := NewServer(config, store, taskDistributor)
require.NoError(t, err)

return server
}

func newContextWithBearerToken(t *testing.T, tokenMaker token.Maker, username string, duration time.Duration) context.Context {
accessToken, _, err := tokenMaker.CreateToken(username, duration)
require.NoError(t, err)

bearerToken := fmt.Sprintf("%s %s", authorizationBearer, accessToken)
md := metadata.MD{
authorizationHeader: []string{
bearerToken,
},
}

return metadata.NewIncomingContext(context.Background(), md)
}
213 changes: 213 additions & 0 deletions gapi/rpc_create_user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package gapi

import (
"context"
"database/sql"
"fmt"
"reflect"
"testing"

"github.com/golang/mock/gomock"
mockdb "github.com/imrishuroy/simplebank/db/mock"
db "github.com/imrishuroy/simplebank/db/sqlc"
"github.com/imrishuroy/simplebank/pb"
"github.com/imrishuroy/simplebank/util"
"github.com/imrishuroy/simplebank/worker"
mockwk "github.com/imrishuroy/simplebank/worker/mock"
"github.com/lib/pq"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type eqCreateUserTxParamsMatcher struct {
arg db.CreateUserTxParams
password string
user db.User
}

func (expected eqCreateUserTxParamsMatcher) Matches(x interface{}) bool {
actualArg, ok := x.(db.CreateUserTxParams)
if !ok {
return false
}

err := util.CheckPassword(expected.password, actualArg.HashedPassword)
if err != nil {
return false
}

expected.arg.HashedPassword = actualArg.HashedPassword
if !reflect.DeepEqual(expected.arg.CreateUserParams, actualArg.CreateUserParams) {
return false
}

err = actualArg.AfterCreate(expected.user)
return err == nil
}

func (e eqCreateUserTxParamsMatcher) String() string {
return fmt.Sprintf("matches arg %v and password %v", e.arg, e.password)
}

func EqCreateUserTxParams(arg db.CreateUserTxParams, password string, user db.User) gomock.Matcher {
return eqCreateUserTxParamsMatcher{arg, password, user}
}

func randomUser(t *testing.T) (user db.User, password string) {
password = util.RandomString(6)
hashedPassword, err := util.HashPassword(password)
require.NoError(t, err)

user = db.User{
Username: util.RandomOwner(),
HashedPassword: hashedPassword,
FullName: util.RandomOwner(),
Email: util.RandomEmail(),
}
return
}

func TestCreateUserAPI(t *testing.T) {
user, password := randomUser(t)

testCases := []struct {
name string
req *pb.CreateUserRequest
buildStubs func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor)
checkResponse func(t *testing.T, res *pb.CreateUserResponse, err error)
}{
{
name: "OK",
req: &pb.CreateUserRequest{
Username: user.Username,
Password: password,
FullName: user.FullName,
Email: user.Email,
},
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
arg := db.CreateUserTxParams{
CreateUserParams: db.CreateUserParams{
Username: user.Username,
FullName: user.FullName,
Email: user.Email,
},
}
store.EXPECT().
CreateUserTx(gomock.Any(), EqCreateUserTxParams(arg, password, user)).
Times(1).
Return(db.CreateUserTxResult{User: user}, nil)

taskPayload := &worker.PayloadSendVerifyEmail{
Username: user.Username,
}
taskDistributor.EXPECT().
DistributeTaskSendVerifyEmail(gomock.Any(), taskPayload, gomock.Any()).
Times(1).
Return(nil)
},
checkResponse: func(t *testing.T, res *pb.CreateUserResponse, err error) {
require.NoError(t, err)
require.NotNil(t, res)
createdUser := res.GetUser()
require.Equal(t, user.Username, createdUser.Username)
require.Equal(t, user.FullName, createdUser.FullName)
require.Equal(t, user.Email, createdUser.Email)
},
},
{
name: "InternalError",
req: &pb.CreateUserRequest{
Username: user.Username,
Password: password,
FullName: user.FullName,
Email: user.Email,
},
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
store.EXPECT().
CreateUserTx(gomock.Any(), gomock.Any()).
Times(1).
Return(db.CreateUserTxResult{}, sql.ErrConnDone)

taskDistributor.EXPECT().
DistributeTaskSendVerifyEmail(gomock.Any(), gomock.Any(), gomock.Any()).
Times(0)
},
checkResponse: func(t *testing.T, res *pb.CreateUserResponse, err error) {
require.Error(t, err)
st, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.Internal, st.Code())
},
},
{
name: "DuplicateUsername",
req: &pb.CreateUserRequest{
Username: user.Username,
Password: password,
FullName: user.FullName,
Email: user.Email,
},
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
store.EXPECT().
CreateUserTx(gomock.Any(), gomock.Any()).
Times(1).
Return(db.CreateUserTxResult{}, &pq.Error{Code: "23505"})

taskDistributor.EXPECT().
DistributeTaskSendVerifyEmail(gomock.Any(), gomock.Any(), gomock.Any()).
Times(0)
},
checkResponse: func(t *testing.T, res *pb.CreateUserResponse, err error) {
require.Error(t, err)
st, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.AlreadyExists, st.Code())
},
},
{
name: "InvalidEmail",
req: &pb.CreateUserRequest{
Username: user.Username,
Password: password,
FullName: user.FullName,
Email: "invalid-email",
},
buildStubs: func(store *mockdb.MockStore, taskDistributor *mockwk.MockTaskDistributor) {
store.EXPECT().
CreateUserTx(gomock.Any(), gomock.Any()).
Times(0)

taskDistributor.EXPECT().
DistributeTaskSendVerifyEmail(gomock.Any(), gomock.Any(), gomock.Any()).
Times(0)
},
checkResponse: func(t *testing.T, res *pb.CreateUserResponse, err error) {
require.Error(t, err)
st, ok := status.FromError(err)
require.True(t, ok)
require.Equal(t, codes.InvalidArgument, st.Code())
},
},
}

for i := range testCases {
tc := testCases[i]

t.Run(tc.name, func(t *testing.T) {
storeCtrl := gomock.NewController(t)
defer storeCtrl.Finish()
store := mockdb.NewMockStore(storeCtrl)

taskCtrl := gomock.NewController(t)
defer taskCtrl.Finish()
taskDistributor := mockwk.NewMockTaskDistributor(taskCtrl)

tc.buildStubs(store, taskDistributor)
server := newTestServer(t, store, taskDistributor)

res, err := server.CreateUser(context.Background(), tc.req)
tc.checkResponse(t, res, err)
})
}
}
Loading

0 comments on commit d74ef6f

Please # to comment.