package gapi import ( "context" "database/sql" "testing" db "github.com/FernandoJVideira/simple_bank/internal/db/sqlc" "github.com/FernandoJVideira/simple_bank/internal/domain/role" "github.com/FernandoJVideira/simple_bank/internal/security" "github.com/FernandoJVideira/simple_bank/internal/service" mocksvc "github.com/FernandoJVideira/simple_bank/internal/service/mock" "github.com/FernandoJVideira/simple_bank/pb" "github.com/FernandoJVideira/simple_bank/pkg/testutil" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func randomUser(t *testing.T) (user db.User, password string) { password = testutil.RandomString(6) hashedPassword, err := security.HashPassword(password) if err != nil { t.Fatal(err) } user = db.User{ Username: testutil.RandomOwner(), HashedPassword: hashedPassword, Role: role.MemberRole, FullName: testutil.RandomOwner(), Email: testutil.RandomEmail(), } return } func TestCreateUserRPC(t *testing.T) { user, password := randomUser(t) testCases := []struct { name string req *pb.CreateUserRequest buildStubs func(userService *mocksvc.MockUserService) 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(userService *mocksvc.MockUserService) { arg := service.RegisterUserRequest{ Username: user.Username, Password: password, FullName: user.FullName, Email: user.Email, } userService.EXPECT(). CreateUser(gomock.Any(), gomock.Eq(arg)). Times(1). Return(&service.RegisterUserResponse{ User: user, }, nil) }, checkResponse: func(t *testing.T, res *pb.CreateUserResponse, err error) { require.NoError(t, err) require.NotNil(t, res) require.Equal(t, user.Username, res.User.Username) require.Equal(t, user.FullName, res.User.FullName) require.Equal(t, user.Email, res.User.Email) require.NotEmpty(t, res.User.CreatedAt) }, }, { name: "InternalError", req: &pb.CreateUserRequest{ Username: user.Username, Password: password, FullName: user.FullName, Email: user.Email, }, buildStubs: func(userService *mocksvc.MockUserService) { userService.EXPECT(). CreateUser(gomock.Any(), gomock.Any()). Times(1). Return(nil, sql.ErrConnDone) }, 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, st.Code(), codes.Internal) }, }, { name: "DuplicateUsername", req: &pb.CreateUserRequest{ Username: user.Username, Password: password, FullName: user.FullName, Email: user.Email, }, buildStubs: func(userService *mocksvc.MockUserService) { userService.EXPECT(). CreateUser(gomock.Any(), gomock.Any()). Times(1). Return(nil, db.ErrUniqueViolation) }, 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, st.Code(), codes.AlreadyExists) }, }, { name: "InvalidEmail", req: &pb.CreateUserRequest{ Username: user.Username, Password: password, FullName: user.FullName, Email: "invalid-email", }, buildStubs: func(userService *mocksvc.MockUserService) { userService.EXPECT(). CreateUser(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, st.Code(), codes.InvalidArgument) }, }, { name: "PasswordTooShort", req: &pb.CreateUserRequest{ Username: user.Username, Password: "short", FullName: user.FullName, Email: user.Email, }, buildStubs: func(userService *mocksvc.MockUserService) { userService.EXPECT(). CreateUser(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, st.Code(), codes.InvalidArgument) }, }, } for i := range testCases { tc := testCases[i] t.Run(tc.name, func(t *testing.T) { userCtrl := gomock.NewController(t) defer userCtrl.Finish() userService := mocksvc.NewMockUserService(userCtrl) tc.buildStubs(userService) // Start test server and send request s := newTestServer(t, nil, nil, userService, nil) res, err := s.CreateUser(context.Background(), tc.req) tc.checkResponse(t, res, err) }) } }