package users import ( "errors" "testing" "github.com/stretchr/testify/require" "src.dualinventive.com/go/lib/dilog" "src.dualinventive.com/go/mtinfo-go" "src.dualinventive.com/go/users-service/internal/domain" ) func TestGetUserByID_GivenUnknownID_ReturnsUserNotFoundError(t *testing.T) { //given testEnvironment := NewTestEnvironment(t) testEnvironment.userRepository.returnMe = []*domain.User{nil} testEnvironment.userRepository.returnErr = []error{nil} //when user, err := testEnvironment.userService.GetUserByID("", 123) //then require.Nil(t, user) require.NotNil(t, err) require.EqualError(t, err, "user not found") } func TestGetUserByID_GivenKnownID_ReturnsUser(t *testing.T) { //given testEnvironment := NewTestEnvironment(t) testEnvironment.userRepository.returnMe = []*domain.User{{ ID: 123, UserName: "someUsername", FirstName: "someFirstname", LastName: "someLastname", CompanyID: 1, Company: domain.Company{ Code: "system", ID: 1, Name: "System", }, Reference: "someReference", }} testEnvironment.userRepository.returnErr = []error{nil} //when user, err := testEnvironment.userService.GetUserByID("", 123) //then require.NotNil(t, user) require.Equal(t, user.UserName, "someUsername") require.Equal(t, user.FirstName, "someFirstname") require.Equal(t, user.LastName, "someLastname") require.Equal(t, user.Company.Name, "System") require.Equal(t, user.Reference, "someReference") require.Nil(t, err) } func TestGetUserByID_WhenRepositoryError_ReturnsRepositoryError(t *testing.T) { //given testEnvironment := NewTestEnvironment(t) testEnvironment.userRepository.returnMe = []*domain.User{nil} testEnvironment.userRepository.returnErr = []error{errors.New("some repository error")} //when user, err := testEnvironment.userService.GetUserByID("", 123) //then require.Nil(t, user) require.NotNil(t, err) require.EqualError(t, err, "failed to fetch user: some repository error") } func TestListUsers(t *testing.T) { //given testEnvironment := NewTestEnvironment(t) testEnvironment.userRepository.returnMeMulti = [][]domain.User{{{ ID: 123, UserName: "someUsername", FirstName: "someFirstname", LastName: "someLastname", Company: domain.Company{Code: "somecompany", ID: 1, Name: "someCompanyname"}, Reference: "someReference", }, { ID: 321, UserName: "anotherUsername", FirstName: "anotherFirstname", LastName: "anotherLastname", Company: domain.Company{Code: "anothercompany", ID: 2, Name: "anotherCompanyname"}, Reference: "anotherReference", }}} testEnvironment.userRepository.returnErr = []error{nil} //when users, count, err := testEnvironment.userService.ListUsers("", nil, 1, 1, "") //then require.NotNil(t, users) require.Equal(t, count, uint64(2)) require.Equal(t, users[0].UserName, "someUsername") require.Equal(t, users[0].FirstName, "someFirstname") require.Equal(t, users[0].LastName, "someLastname") require.Equal(t, users[0].Company.Name, "someCompanyname") require.Equal(t, users[0].Reference, "someReference") require.Nil(t, err) } // NewTestEnvironment returns all variables for testing func NewTestEnvironment(t *testing.T) *TestEnvironment { userRepository := NewTestUserRepository(t) testLogger := dilog.NewNilLogger() userService := &UserService{ Logger: testLogger, UserRepository: userRepository, Mtinfo: &mtinfo.Client{ Auth: &testAuthClient{}, }, } return &TestEnvironment{userService: userService, userRepository: userRepository, testLogger: testLogger} } type TestEnvironment struct { userService *UserService userRepository *TestUserRepository testLogger dilog.Logger } //NewTestUserRepository returns a mockable user repository. func NewTestUserRepository(t *testing.T) *TestUserRepository { return &TestUserRepository{t: t, callCount: 0, returnMe: []*domain.User{nil}, returnErr: []error{nil}} } type TestUserRepository struct { t *testing.T callCount int returnMe []*domain.User returnMeMulti [][]domain.User returnErr []error } func (r TestUserRepository) GetUserByID(userID uint64) (*domain.User, error) { returnMe := r.returnMe[r.callCount] returnErr := r.returnErr[r.callCount] r.callCount++ return returnMe, returnErr } func (r TestUserRepository) ListUsers( filter domain.UsersFilter, page uint64, perPage uint64, sort domain.SortCol, ) ([]domain.User, uint64, error) { returnMeMulti := r.returnMeMulti[r.callCount] returnErr := r.returnErr[r.callCount] r.callCount++ return returnMeMulti, uint64(len(returnMeMulti)), returnErr } //testAuthClient contains authentication related operations over GRPC type testAuthClient struct{} //VerifyToken verifies the given token to see if its valid. //When a public key is configured, token is locally verified using JWT. //When no public key is configured, token is remotely verified using GRPC. //Returns false when token signed portion is invalid, or token is expired. func (as *testAuthClient) VerifyToken(token string) (bool, error) { return true, nil } func (as *testAuthClient) VerifyTokenRemotely(token string) (bool, error) { return true, nil } func (as *testAuthClient) Login(username, companyCode, password string) (string, error) { return "", nil } func (as *testAuthClient) Logout(token string) error { return nil } func (as *testAuthClient) Me(token string) (*mtinfo.User, error) { user := mtinfo.User{ ID: 1, Name: "someUser", Company: mtinfo.Company{ ID: 1, Code: "somecompany", Name: "someCompanyname", }, } return &user, nil } func (as *testAuthClient) RequestPasswordReset(username string) error { return nil } func (as *testAuthClient) RedeemPasswordReset(username, resetCode, password, passwordVerify string) error { return nil } func (as *testAuthClient) ListTokens(token string) (mtinfo.OpaqueTokens, error) { return nil, nil } func (as *testAuthClient) DeleteToken(token string, opaqueToken string) error { return nil } func (as *testAuthClient) UserAgent() string { return "" } func (as *testAuthClient) SetUserAgent(string) {}