fix(http): convert user errors
parent
6670ef9892
commit
831fc8697b
|
@ -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()
|
||||
|
|
|
@ -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{}
|
||||
|
|
174
bolt/user.go
174
bolt/user.go
|
@ -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{}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
10
user.go
|
@ -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 {
|
||||
|
||||
|
|
Loading…
Reference in New Issue