fix(http): convert user errors

pull/10616/head
Kelvin Wang 2018-12-07 13:12:24 -05:00
parent 6670ef9892
commit 831fc8697b
10 changed files with 346 additions and 197 deletions

View File

@ -23,9 +23,9 @@ func (c *Client) setPassword(ctx context.Context, tx *bolt.Tx, name string, pass
return err
}
u, err := c.findUserByName(ctx, tx, name)
if err != nil {
return err
u, pe := c.findUserByName(ctx, tx, name)
if pe != nil {
return pe
}
encodedID, err := u.ID.Encode()

View File

@ -124,9 +124,9 @@ func (c *Client) CreateSession(ctx context.Context, user string) (*platform.Sess
}
func (c *Client) createSession(ctx context.Context, tx *bolt.Tx, user string) (*platform.Session, error) {
u, err := c.findUserByName(ctx, tx, user)
if err != nil {
return nil, err
u, pe := c.findUserByName(ctx, tx, user)
if pe != nil {
return nil, pe
}
s := &platform.Session{}

View File

@ -6,7 +6,7 @@ import (
"fmt"
"time"
"github.com/coreos/bbolt"
bolt "github.com/coreos/bbolt"
"github.com/influxdata/platform"
platformcontext "github.com/influxdata/platform/context"
)
@ -39,25 +39,30 @@ func (c *Client) FindUserByID(ctx context.Context, id platform.ID) (*platform.Us
var u *platform.User
err := c.db.View(func(tx *bolt.Tx) error {
usr, err := c.findUserByID(ctx, tx, id)
if err != nil {
return err
usr, pe := c.findUserByID(ctx, tx, id)
if pe != nil {
return pe
}
u = usr
return nil
})
if err != nil {
return nil, err
return nil, &platform.Error{
Op: getOp(platform.OpFindUserByID),
Err: err,
}
}
return u, nil
}
func (c *Client) findUserByID(ctx context.Context, tx *bolt.Tx, id platform.ID) (*platform.User, error) {
func (c *Client) findUserByID(ctx context.Context, tx *bolt.Tx, id platform.ID) (*platform.User, *platform.Error) {
encodedID, err := id.Encode()
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
var u platform.User
@ -71,7 +76,9 @@ func (c *Client) findUserByID(ctx context.Context, tx *bolt.Tx, id platform.ID)
}
if err := json.Unmarshal(v, &u); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
return &u, nil
@ -82,9 +89,9 @@ func (c *Client) FindUserByName(ctx context.Context, n string) (*platform.User,
var u *platform.User
err := c.db.View(func(tx *bolt.Tx) error {
usr, err := c.findUserByName(ctx, tx, n)
if err != nil {
return err
usr, pe := c.findUserByName(ctx, tx, n)
if pe != nil {
return pe
}
u = usr
return nil
@ -93,10 +100,9 @@ func (c *Client) FindUserByName(ctx context.Context, n string) (*platform.User,
return u, err
}
func (c *Client) findUserByName(ctx context.Context, tx *bolt.Tx, n string) (*platform.User, error) {
func (c *Client) findUserByName(ctx context.Context, tx *bolt.Tx, n string) (*platform.User, *platform.Error) {
u := tx.Bucket(userIndex).Get(userIndexKey(n))
if u == nil {
// TODO: Make standard error
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "user not found",
@ -105,7 +111,9 @@ func (c *Client) findUserByName(ctx context.Context, tx *bolt.Tx, n string) (*pl
var id platform.ID
if err := id.Decode(u); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
return c.findUserByID(ctx, tx, id)
}
@ -114,18 +122,34 @@ func (c *Client) findUserByName(ctx context.Context, tx *bolt.Tx, n string) (*pl
// Filters using ID, or Name should be efficient.
// Other filters will do a linear scan across users until it finds a match.
func (c *Client) FindUser(ctx context.Context, filter platform.UserFilter) (*platform.User, error) {
var u *platform.User
var err error
op := getOp(platform.OpFindUser)
if filter.ID != nil {
return c.FindUserByID(ctx, *filter.ID)
u, err = c.FindUserByID(ctx, *filter.ID)
if err != nil {
return nil, &platform.Error{
Op: op,
Err: err,
}
}
return u, nil
}
if filter.Name != nil {
return c.FindUserByName(ctx, *filter.Name)
u, err = c.FindUserByName(ctx, *filter.Name)
if err != nil {
return nil, &platform.Error{
Op: op,
Err: err,
}
}
return u, nil
}
filterFn := filterUsersFn(filter)
var u *platform.User
err := c.db.View(func(tx *bolt.Tx) error {
err = c.db.View(func(tx *bolt.Tx) error {
return forEachUser(ctx, tx, func(usr *platform.User) bool {
if filterFn(usr) {
u = usr
@ -136,11 +160,17 @@ func (c *Client) FindUser(ctx context.Context, filter platform.UserFilter) (*pla
})
if err != nil {
return nil, err
return nil, &platform.Error{
Op: op,
Err: err,
}
}
if u == nil {
return nil, fmt.Errorf("user not found")
return nil, &platform.Error{
Code: platform.ENotFound,
Msg: "user not found",
}
}
return u, nil
@ -166,10 +196,14 @@ func filterUsersFn(filter platform.UserFilter) func(u *platform.User) bool {
// Filters using ID, or Name should be efficient.
// Other filters will do a linear scan across all users searching for a match.
func (c *Client) FindUsers(ctx context.Context, filter platform.UserFilter, opt ...platform.FindOptions) ([]*platform.User, int, error) {
op := getOp(platform.OpFindUsers)
if filter.ID != nil {
u, err := c.FindUserByID(ctx, *filter.ID)
if err != nil {
return nil, 0, err
return nil, 0, &platform.Error{
Err: err,
Op: op,
}
}
return []*platform.User{u}, 1, nil
@ -178,7 +212,10 @@ func (c *Client) FindUsers(ctx context.Context, filter platform.UserFilter, opt
if filter.Name != nil {
u, err := c.FindUserByName(ctx, *filter.Name)
if err != nil {
return nil, 0, err
return nil, 0, &platform.Error{
Err: err,
Op: op,
}
}
return []*platform.User{u}, 1, nil
@ -204,12 +241,14 @@ func (c *Client) FindUsers(ctx context.Context, filter platform.UserFilter, opt
// CreateUser creates a platform user and sets b.ID.
func (c *Client) CreateUser(ctx context.Context, u *platform.User) error {
return c.db.Update(func(tx *bolt.Tx) error {
err := c.db.Update(func(tx *bolt.Tx) error {
unique := c.uniqueUserName(ctx, tx, u)
if !unique {
// TODO: make standard error
return fmt.Errorf("user with name %s already exists", u.Name)
return &platform.Error{
Code: platform.EConflict,
Msg: fmt.Sprintf("user with name %s already exists", u.Name),
}
}
u.ID = c.IDGenerator.ID()
@ -220,6 +259,13 @@ func (c *Client) CreateUser(ctx context.Context, u *platform.User) error {
return c.putUser(ctx, tx, u)
})
if err != nil {
return &platform.Error{
Err: err,
Op: getOp(platform.OpCreateUser),
}
}
return nil
}
// PutUser will put a user without setting an ID.
@ -273,9 +319,12 @@ func (c *Client) uniqueUserName(ctx context.Context, tx *bolt.Tx, u *platform.Us
func (c *Client) UpdateUser(ctx context.Context, id platform.ID, upd platform.UserUpdate) (*platform.User, error) {
var u *platform.User
err := c.db.Update(func(tx *bolt.Tx) error {
usr, err := c.updateUser(ctx, tx, id, upd)
if err != nil {
return err
usr, pe := c.updateUser(ctx, tx, id, upd)
if pe != nil {
return &platform.Error{
Err: pe,
Op: getOp(platform.OpUpdateUser),
}
}
u = usr
return nil
@ -284,7 +333,7 @@ func (c *Client) UpdateUser(ctx context.Context, id platform.ID, upd platform.Us
return u, err
}
func (c *Client) updateUser(ctx context.Context, tx *bolt.Tx, id platform.ID, upd platform.UserUpdate) (*platform.User, error) {
func (c *Client) updateUser(ctx context.Context, tx *bolt.Tx, id platform.ID, upd platform.UserUpdate) (*platform.User, *platform.Error) {
u, err := c.findUserByID(ctx, tx, id)
if err != nil {
return nil, err
@ -294,17 +343,23 @@ func (c *Client) updateUser(ctx context.Context, tx *bolt.Tx, id platform.ID, up
// Users are indexed by name and so the user index must be pruned
// when name is modified.
if err := tx.Bucket(userIndex).Delete(userIndexKey(u.Name)); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
u.Name = *upd.Name
}
if err := c.appendUserEventToLog(ctx, tx, u.ID, userUpdatedEvent); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
if err := c.putUser(ctx, tx, u); err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
}
}
return u, nil
@ -312,41 +367,64 @@ func (c *Client) updateUser(ctx context.Context, tx *bolt.Tx, id platform.ID, up
// DeleteUser deletes a user and prunes it from the index.
func (c *Client) DeleteUser(ctx context.Context, id platform.ID) error {
return c.db.Update(func(tx *bolt.Tx) error {
if err := c.deleteUsersAuthorizations(ctx, tx, id); err != nil {
return err
err := c.db.Update(func(tx *bolt.Tx) error {
if pe := c.deleteUsersAuthorizations(ctx, tx, id); pe != nil {
return pe
}
return c.deleteUser(ctx, tx, id)
if pe := c.deleteUser(ctx, tx, id); pe != nil {
return pe
}
return nil
})
if err != nil {
return &platform.Error{
Op: getOp(platform.OpDeleteUser),
Err: err,
}
}
return nil
}
func (c *Client) deleteUser(ctx context.Context, tx *bolt.Tx, id platform.ID) error {
u, err := c.findUserByID(ctx, tx, id)
if err != nil {
return err
func (c *Client) deleteUser(ctx context.Context, tx *bolt.Tx, id platform.ID) *platform.Error {
u, pe := c.findUserByID(ctx, tx, id)
if pe != nil {
return pe
}
encodedID, err := id.Encode()
if err != nil {
return err
return &platform.Error{
Err: err,
}
}
if err := tx.Bucket(userIndex).Delete(userIndexKey(u.Name)); err != nil {
return err
return &platform.Error{
Err: err,
}
}
if err := tx.Bucket(userUser).Delete(encodedID); err != nil {
return err
return &platform.Error{
Err: err,
}
}
return c.deleteUserResourceMappings(ctx, tx, platform.UserResourceMappingFilter{
if err := c.deleteUserResourceMappings(ctx, tx, platform.UserResourceMappingFilter{
UserID: id,
})
}); err != nil {
return &platform.Error{
Err: err,
}
}
return nil
}
func (c *Client) deleteUsersAuthorizations(ctx context.Context, tx *bolt.Tx, id platform.ID) error {
func (c *Client) deleteUsersAuthorizations(ctx context.Context, tx *bolt.Tx, id platform.ID) *platform.Error {
authFilter := platform.AuthorizationFilter{
UserID: &id,
}
as, err := c.findAuthorizations(ctx, tx, authFilter)
if err != nil {
return err
return &platform.Error{
Err: err,
}
}
for _, a := range as {
if err := c.deleteAuthorization(ctx, tx, a.ID); err != nil {
@ -356,7 +434,7 @@ func (c *Client) deleteUsersAuthorizations(ctx context.Context, tx *bolt.Tx, id
return nil
}
// GeUserOperationLog retrieves a user operation log.
// GetUserOperationLog retrieves a user operation log.
func (c *Client) GetUserOperationLog(ctx context.Context, id platform.ID, opts platform.FindOptions) ([]*platform.OperationLogEntry, int, error) {
// TODO(desa): might be worthwhile to allocate a slice of size opts.Limit
log := []*platform.OperationLogEntry{}

View File

@ -5,10 +5,11 @@ import (
"testing"
"github.com/influxdata/platform"
bolt "github.com/influxdata/platform/bolt"
platformtesting "github.com/influxdata/platform/testing"
)
func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, func()) {
func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, string, func()) {
c, closeFn, err := NewTestClient()
if err != nil {
t.Fatalf("failed to create new bolt client: %v", err)
@ -20,7 +21,7 @@ func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserS
t.Fatalf("failed to populate users")
}
}
return c, func() {
return c, bolt.OpPrefix, func() {
defer closeFn()
for _, u := range f.Users {
if err := c.DeleteUser(ctx, u.ID); err != nil {
@ -30,26 +31,6 @@ func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserS
}
}
func TestUserService_CreateUser(t *testing.T) {
platformtesting.CreateUser(initUserService, t)
}
func TestUserService_FindUserByID(t *testing.T) {
platformtesting.FindUserByID(initUserService, t)
}
func TestUserService_FindUsers(t *testing.T) {
platformtesting.FindUsers(initUserService, t)
}
func TestUserService_DeleteUser(t *testing.T) {
platformtesting.DeleteUser(initUserService, t)
}
func TestUserService_FindUser(t *testing.T) {
platformtesting.FindUser(initUserService, t)
}
func TestUserService_UpdateUser(t *testing.T) {
platformtesting.UpdateUser(initUserService, t)
func TestUserService(t *testing.T) {
platformtesting.UserService(initUserService, t)
}

View File

@ -413,6 +413,8 @@ type UserService struct {
Addr string
Token string
InsecureSkipVerify bool
// OpPrefix is the ops of not found error.
OpPrefix string
}
// FindMe returns user information about the owner of the token
@ -436,7 +438,7 @@ func (s *UserService) FindMe(ctx context.Context, id platform.ID) (*platform.Use
defer resp.Body.Close()
if err := CheckError(resp); err != nil {
if err := CheckError(resp, true); err != nil {
return nil, err
}
@ -466,7 +468,7 @@ func (s *UserService) FindUserByID(ctx context.Context, id platform.ID) (*platfo
return nil, err
}
if err := CheckError(resp); err != nil {
if err := CheckError(resp, true); err != nil {
return nil, err
}
@ -483,11 +485,18 @@ func (s *UserService) FindUserByID(ctx context.Context, id platform.ID) (*platfo
func (s *UserService) FindUser(ctx context.Context, filter platform.UserFilter) (*platform.User, error) {
users, n, err := s.FindUsers(ctx, filter)
if err != nil {
return nil, err
return nil, &platform.Error{
Op: s.OpPrefix + platform.OpFindUser,
Err: err,
}
}
if n == 0 {
return nil, ErrNotFound
return nil, &platform.Error{
Code: platform.ENotFound,
Op: s.OpPrefix + platform.OpFindUser,
Msg: "no results found",
}
}
return users[0], nil
@ -564,7 +573,7 @@ func (s *UserService) CreateUser(ctx context.Context, u *platform.User) error {
}
// TODO(jsternberg): Should this check for a 201 explicitly?
if err := CheckError(resp); err != nil {
if err := CheckError(resp, true); err != nil {
return err
}
@ -603,7 +612,7 @@ func (s *UserService) UpdateUser(ctx context.Context, id platform.ID, upd platfo
return nil, err
}
if err := CheckError(resp); err != nil {
if err := CheckError(resp, true); err != nil {
return nil, err
}

View File

@ -10,7 +10,7 @@ import (
platformtesting "github.com/influxdata/platform/testing"
)
func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, func()) {
func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, string, func()) {
t.Helper()
svc := inmem.NewService()
svc.IDGenerator = f.IDGenerator
@ -26,12 +26,13 @@ func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserS
handler.UserService = svc
server := httptest.NewServer(handler)
client := UserService{
Addr: server.URL,
Addr: server.URL,
OpPrefix: inmem.OpPrefix,
}
done := server.Close
return &client, done
return &client, inmem.OpPrefix, done
}
func TestUserService(t *testing.T) {

View File

@ -46,17 +46,21 @@ func (s *Service) FindUserByID(ctx context.Context, id platform.ID) (u *platform
var pe *platform.Error
u, pe = s.loadUser(id)
if pe != nil {
err = pe
err = &platform.Error{
Op: OpPrefix + platform.OpFindUserByID,
Err: pe,
}
}
return u, err
}
func (c *Service) findUserByName(ctx context.Context, n string) (*platform.User, error) {
return c.FindUser(ctx, platform.UserFilter{Name: &n})
func (s *Service) findUserByName(ctx context.Context, n string) (*platform.User, error) {
return s.FindUser(ctx, platform.UserFilter{Name: &n})
}
// FindUser returns the first user that matches a filter.
func (s *Service) FindUser(ctx context.Context, filter platform.UserFilter) (*platform.User, error) {
op := OpPrefix + platform.OpFindUser
if filter.Name != nil {
var o *platform.User
@ -75,6 +79,7 @@ func (s *Service) FindUser(ctx context.Context, filter platform.UserFilter) (*pl
if o == nil {
return nil, &platform.Error{
Code: platform.ENotFound,
Op: op,
Msg: "user not found",
}
}
@ -82,14 +87,23 @@ func (s *Service) FindUser(ctx context.Context, filter platform.UserFilter) (*pl
return o, nil
}
return nil, fmt.Errorf("expected filter to contain name")
return nil, &platform.Error{
Code: platform.EInvalid,
Op: op,
Msg: "expected filter to contain name",
}
}
// FindUsers will retrieve a list of users from storage.
func (s *Service) FindUsers(ctx context.Context, filter platform.UserFilter, opt ...platform.FindOptions) ([]*platform.User, int, error) {
op := OpPrefix + platform.OpFindUsers
if filter.ID != nil {
o, err := s.FindUserByID(ctx, *filter.ID)
if err != nil {
return nil, 0, err
return nil, 0, &platform.Error{
Err: err,
Op: op,
}
}
return []*platform.User{o}, 1, nil
@ -97,7 +111,10 @@ func (s *Service) FindUsers(ctx context.Context, filter platform.UserFilter, opt
if filter.Name != nil {
o, err := s.FindUser(ctx, filter)
if err != nil {
return nil, 0, err
return nil, 0, &platform.Error{
Err: err,
Op: op,
}
}
return []*platform.User{o}, 1, nil
@ -117,24 +134,34 @@ func (s *Service) FindUsers(ctx context.Context, filter platform.UserFilter, opt
return orgs, len(orgs), nil
}
// CreateUser will create an user into storage.
func (s *Service) CreateUser(ctx context.Context, u *platform.User) error {
if _, err := s.FindUser(ctx, platform.UserFilter{Name: &u.Name}); err == nil {
return fmt.Errorf("user with name %s already exists", u.Name)
return &platform.Error{
Code: platform.EConflict,
Op: OpPrefix + platform.OpCreateUser,
Msg: fmt.Sprintf("user with name %s already exists", u.Name),
}
}
u.ID = s.IDGenerator.ID()
s.PutUser(ctx, u)
return nil
}
// PutUser put a user into storage.
func (s *Service) PutUser(ctx context.Context, o *platform.User) error {
s.userKV.Store(o.ID.String(), o)
return nil
}
// UpdateUser update a user in storage.
func (s *Service) UpdateUser(ctx context.Context, id platform.ID, upd platform.UserUpdate) (*platform.User, error) {
o, err := s.FindUserByID(ctx, id)
if err != nil {
return nil, err
return nil, &platform.Error{
Err: err,
Op: OpPrefix + platform.OpUpdateUser,
}
}
if upd.Name != nil {
@ -146,9 +173,13 @@ func (s *Service) UpdateUser(ctx context.Context, id platform.ID, upd platform.U
return o, nil
}
// DeleteUser remove a user from storage.
func (s *Service) DeleteUser(ctx context.Context, id platform.ID) error {
if _, err := s.FindUserByID(ctx, id); err != nil {
return err
return &platform.Error{
Err: err,
Op: OpPrefix + platform.OpDeleteUser,
}
}
s.userKV.Delete(id.String())
return nil

View File

@ -8,7 +8,7 @@ import (
platformtesting "github.com/influxdata/platform/testing"
)
func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, func()) {
func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserService, string, func()) {
s := NewService()
s.IDGenerator = f.IDGenerator
ctx := context.Background()
@ -17,35 +17,10 @@ func initUserService(f platformtesting.UserFields, t *testing.T) (platform.UserS
t.Fatalf("failed to populate users")
}
}
return s, func() {}
return s, OpPrefix, func() {}
}
func TestUserService_CreateUser(t *testing.T) {
func TestUserService(t *testing.T) {
t.Parallel()
platformtesting.CreateUser(initUserService, t)
}
func TestUserService_FindUserByID(t *testing.T) {
t.Parallel()
platformtesting.FindUserByID(initUserService, t)
}
func TestUserService_FindUsers(t *testing.T) {
t.Parallel()
platformtesting.FindUsers(initUserService, t)
}
func TestUserService_DeleteUser(t *testing.T) {
t.Parallel()
platformtesting.DeleteUser(initUserService, t)
}
func TestUserService_FindUser(t *testing.T) {
t.Parallel()
platformtesting.FindUser(initUserService, t)
}
func TestUserService_UpdateUser(t *testing.T) {
t.Parallel()
platformtesting.UpdateUser(initUserService, t)
platformtesting.UserService(initUserService, t)
}

View File

@ -3,7 +3,6 @@ package testing
import (
"bytes"
"context"
"fmt"
"sort"
"testing"
@ -39,11 +38,11 @@ type UserFields struct {
// UserService tests all the service functions.
func UserService(
init func(UserFields, *testing.T) (platform.UserService, func()), t *testing.T,
init func(UserFields, *testing.T) (platform.UserService, string, func()), t *testing.T,
) {
tests := []struct {
name string
fn func(init func(UserFields, *testing.T) (platform.UserService, func()),
fn func(init func(UserFields, *testing.T) (platform.UserService, string, func()),
t *testing.T)
}{
{
@ -80,7 +79,7 @@ func UserService(
// CreateUser testing
func CreateUser(
init func(UserFields, *testing.T) (platform.UserService, func()),
init func(UserFields, *testing.T) (platform.UserService, string, func()),
t *testing.T,
) {
type args struct {
@ -173,26 +172,22 @@ func CreateUser(
Name: "user1",
},
},
err: fmt.Errorf("user with name user1 already exists"),
err: &platform.Error{
Code: platform.EConflict,
Op: platform.OpCreateUser,
Msg: "user with name user1 already exists",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
err := s.CreateUser(ctx, tt.args.user)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error messages to match '%v' got '%v'", tt.wants.err, err.Error())
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
// Delete only created users - ie., having a not nil ID
if tt.args.user.ID.Valid() {
@ -212,7 +207,7 @@ func CreateUser(
// FindUserByID testing
func FindUserByID(
init func(UserFields, *testing.T) (platform.UserService, func()),
init func(UserFields, *testing.T) (platform.UserService, string, func()),
t *testing.T,
) {
type args struct {
@ -253,24 +248,41 @@ func FindUserByID(
},
},
},
{
name: "find user by id not exists",
fields: UserFields{
Users: []*platform.User{
{
ID: MustIDBase16(userOneID),
Name: "user1",
},
{
ID: MustIDBase16(userTwoID),
Name: "user2",
},
},
},
args: args{
id: MustIDBase16(threeID),
},
wants: wants{
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpFindUserByID,
Msg: "user not found",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
user, err := s.FindUserByID(ctx, tt.args.id)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected errors to be equal '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
if diff := cmp.Diff(user, tt.wants.user, userCmpOptions...); diff != "" {
t.Errorf("user is different -got/+want\ndiff %s", diff)
@ -281,7 +293,7 @@ func FindUserByID(
// FindUsers testing
func FindUsers(
init func(UserFields, *testing.T) (platform.UserService, func()),
init func(UserFields, *testing.T) (platform.UserService, string, func()),
t *testing.T,
) {
type args struct {
@ -379,11 +391,61 @@ func FindUsers(
},
},
},
{
name: "find user by id not exists",
fields: UserFields{
Users: []*platform.User{
{
ID: MustIDBase16(userOneID),
Name: "abc",
},
{
ID: MustIDBase16(userTwoID),
Name: "xyz",
},
},
},
args: args{
ID: MustIDBase16(threeID),
},
wants: wants{
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpFindUsers,
Msg: "user not found",
},
},
},
{
name: "find user by name not exists",
fields: UserFields{
Users: []*platform.User{
{
ID: MustIDBase16(userOneID),
Name: "abc",
},
{
ID: MustIDBase16(userTwoID),
Name: "xyz",
},
},
},
args: args{
name: "no_exist",
},
wants: wants{
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpFindUsers,
Msg: "user not found",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
@ -396,15 +458,7 @@ func FindUsers(
}
users, _, err := s.FindUsers(ctx, filter)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected errors to be equal '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
if diff := cmp.Diff(users, tt.wants.users, userCmpOptions...); diff != "" {
t.Errorf("users are different -got/+want\ndiff %s", diff)
@ -415,7 +469,7 @@ func FindUsers(
// DeleteUser testing
func DeleteUser(
init func(UserFields, *testing.T) (platform.UserService, func()),
init func(UserFields, *testing.T) (platform.UserService, string, func()),
t *testing.T,
) {
type args struct {
@ -476,7 +530,11 @@ func DeleteUser(
ID: MustIDBase16(userThreeID),
},
wants: wants{
err: fmt.Errorf("<not found> user not found"),
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpDeleteUser,
Msg: "user not found",
},
users: []*platform.User{
{
Name: "orgA",
@ -493,19 +551,11 @@ func DeleteUser(
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
err := s.DeleteUser(ctx, tt.args.ID)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error messages to match '%v' got '%v'", tt.wants.err, err.Error())
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
filter := platform.UserFilter{}
users, _, err := s.FindUsers(ctx, filter)
@ -521,7 +571,7 @@ func DeleteUser(
// FindUser testing
func FindUser(
init func(UserFields, *testing.T) (platform.UserService, func()),
init func(UserFields, *testing.T) (platform.UserService, string, func()),
t *testing.T,
) {
type args struct {
@ -572,14 +622,18 @@ func FindUser(
name: "abc",
},
wants: wants{
err: fmt.Errorf("<not found> user not found"),
err: &platform.Error{
Code: platform.ENotFound,
Msg: "user not found",
Op: platform.OpFindUser,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
filter := platform.UserFilter{}
@ -588,15 +642,7 @@ func FindUser(
}
user, err := s.FindUser(ctx, filter)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error messages to match '%v' got '%v'", tt.wants.err, err.Error())
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
if diff := cmp.Diff(user, tt.wants.user, userCmpOptions...); diff != "" {
t.Errorf("users are different -got/+want\ndiff %s", diff)
@ -607,7 +653,7 @@ func FindUser(
// UpdateUser testing
func UpdateUser(
init func(UserFields, *testing.T) (platform.UserService, func()),
init func(UserFields, *testing.T) (platform.UserService, string, func()),
t *testing.T,
) {
type args struct {
@ -650,11 +696,37 @@ func UpdateUser(
},
},
},
{
name: "update name with id not exists",
fields: UserFields{
Users: []*platform.User{
{
ID: MustIDBase16(userOneID),
Name: "user1",
},
{
ID: MustIDBase16(userTwoID),
Name: "user2",
},
},
},
args: args{
id: MustIDBase16(threeID),
name: "changed",
},
wants: wants{
err: &platform.Error{
Code: platform.ENotFound,
Op: platform.OpUpdateUser,
Msg: "user not found",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s, done := init(tt.fields, t)
s, opPrefix, done := init(tt.fields, t)
defer done()
ctx := context.TODO()
@ -664,15 +736,7 @@ func UpdateUser(
}
user, err := s.UpdateUser(ctx, tt.args.id, upd)
if (err != nil) != (tt.wants.err != nil) {
t.Fatalf("expected error '%v' got '%v'", tt.wants.err, err)
}
if err != nil && tt.wants.err != nil {
if err.Error() != tt.wants.err.Error() {
t.Fatalf("expected error messages to match '%v' got '%v'", tt.wants.err, err.Error())
}
}
diffPlatformErrors(tt.name, err, tt.wants.err, opPrefix, t)
if diff := cmp.Diff(user, tt.wants.user, userCmpOptions...); diff != "" {
t.Errorf("user is different -got/+want\ndiff %s", diff)

10
user.go
View File

@ -8,6 +8,16 @@ type User struct {
Name string `json:"name"`
}
// Ops for user errors and op log.
const (
OpFindUserByID = "FindUserByID"
OpFindUser = "FindUser"
OpFindUsers = "FindUsers"
OpCreateUser = "CreateUser"
OpUpdateUser = "UpdateUser"
OpDeleteUser = "DeleteUser"
)
// UserService represents a service for managing user data.
type UserService interface {