From 024da3e546e98cbaeea5f7bc86af12b671996f41 Mon Sep 17 00:00:00 2001 From: Gabriel Arakaki Giovanini Date: Thu, 29 Jun 2023 23:05:23 +0200 Subject: ref: Refactor how repository is define To make things easier and reduce the number of package I'll move all repository to one folder, starting with auth and user repository. Also implements all testing on top of the repository interface with a im memory implementation. This will later make mescling unit and integration easier. --- pkg/components/auth/controller.go | 18 ++-- pkg/components/auth/controller_test.go | 162 +++------------------------------ pkg/components/auth/mock_test.go | 121 ++++++++++++++++++++++++ pkg/components/auth/model.go | 10 -- pkg/components/user/model.go | 34 ------- 5 files changed, 143 insertions(+), 202 deletions(-) create mode 100644 pkg/components/auth/mock_test.go delete mode 100644 pkg/components/auth/model.go delete mode 100644 pkg/components/user/model.go (limited to 'pkg/components') diff --git a/pkg/components/auth/controller.go b/pkg/components/auth/controller.go index a33d9b3..0b08fcc 100644 --- a/pkg/components/auth/controller.go +++ b/pkg/components/auth/controller.go @@ -6,35 +6,35 @@ import ( "golang.org/x/crypto/bcrypt" "git.sr.ht/~gabrielgio/img/pkg/components" - "git.sr.ht/~gabrielgio/img/pkg/components/user" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/ext" ) type Controller struct { - repository Repository - userRepository user.Repository + authRepository repository.AuthRepository + userRepository repository.UserRepository key []byte } func NewController( - repository Repository, - userRepository user.Repository, + authRepository repository.AuthRepository, + userRepository repository.UserRepository, key []byte, ) *Controller { return &Controller{ - repository: repository, + authRepository: authRepository, userRepository: userRepository, key: key, } } func (c *Controller) Login(ctx context.Context, username, password []byte) ([]byte, error) { - id, err := c.repository.GetIDByUsername(ctx, string(username)) + id, err := c.authRepository.GetIDByUsername(ctx, string(username)) if err != nil { return nil, err } - hashedPassword, err := c.repository.GetPassword(ctx, id) + hashedPassword, err := c.authRepository.GetPassword(ctx, id) if err != nil { return nil, err } @@ -67,7 +67,7 @@ func (c *Controller) InitialRegister(ctx context.Context, username, password []b return err } - _, err = c.userRepository.Create(ctx, &user.CreateUser{ + _, err = c.userRepository.Create(ctx, &repository.CreateUser{ Username: string(username), Password: hash, Path: string(path), diff --git a/pkg/components/auth/controller_test.go b/pkg/components/auth/controller_test.go index 50bf69b..b1ca065 100644 --- a/pkg/components/auth/controller_test.go +++ b/pkg/components/auth/controller_test.go @@ -4,12 +4,9 @@ package auth import ( "context" - "errors" "testing" - "github.com/samber/lo" - - "git.sr.ht/~gabrielgio/img/pkg/components/user" + "git.sr.ht/~gabrielgio/img/pkg/database/repository" "git.sr.ht/~gabrielgio/img/pkg/ext" "git.sr.ht/~gabrielgio/img/pkg/testkit" ) @@ -17,41 +14,23 @@ import ( type ( scene struct { ctx context.Context - mockRepository *MockAuthRepository - controller Controller - } - - mockUser struct { - id uint - username string - password []byte - } - - MockAuthRepository struct { - index uint - users []*mockUser - err error - } - - MockUserRepository struct { - index uint - users []*mockUser - err error + authRepository repository.AuthRepository + userRepository repository.UserRepository + controller *Controller } ) var ( - _ Repository = &MockAuthRepository{} - key = []byte("6368616e676520746869732070617373") + key = []byte("6368616e676520746869732070617373") ) func setUp() *scene { - mockAuthRepository := &MockAuthRepository{} - mockUserRepository := &MockUserRepository{} + userRepository := NewUserRepository() return &scene{ ctx: context.Background(), - mockRepository: mockAuthRepository, - controller: *NewController(mockAuthRepository, mockUserRepository, key), + authRepository: userRepository, + userRepository: userRepository, + controller: NewController(userRepository, userRepository, key), } } @@ -64,7 +43,7 @@ func TestInitialRegisterAndLogin(t *testing.T) { { name: "Normal register", username: "username", - password: []byte("password"), + password: []byte("this is an password"), }, } @@ -75,9 +54,10 @@ func TestInitialRegisterAndLogin(t *testing.T) { err := scene.controller.InitialRegister(scene.ctx, []byte(tc.username), tc.password, []byte("/")) testkit.TestFatalError(t, "Register", err) - userID := scene.mockRepository.GetLastId() + users, err := scene.userRepository.List(scene.ctx) + userID := users[0].ID - user, err := scene.mockRepository.Get(scene.ctx, userID) + user, err := scene.userRepository.Get(scene.ctx, userID) testkit.TestFatalError(t, "Get", err) testkit.TestValue(t, "Register", tc.username, user.Username) @@ -93,122 +73,6 @@ func TestInitialRegisterAndLogin(t *testing.T) { } } -func toUser(m *mockUser, _ int) *user.User { - return &user.User{ - ID: m.id, - Username: m.username, - } -} - -func (m *MockAuthRepository) GetLastId() uint { - return m.index -} - -func (m *MockAuthRepository) List(ctx context.Context) ([]*user.User, error) { - if m.err != nil { - return nil, m.err - } - - return lo.Map(m.users, toUser), nil -} - -func (m *MockAuthRepository) Get(ctx context.Context, id uint) (*user.User, error) { - if m.err != nil { - return nil, m.err - } - - for _, m := range m.users { - if m.id == id { - return toUser(m, 0), nil - } - } - return nil, errors.New("Item not found") -} - -func (m *MockAuthRepository) GetIDByUsername(ctx context.Context, username string) (uint, error) { - if m.err != nil { - return 0, m.err - } - - for _, m := range m.users { - if m.username == username { - return m.id, nil - } - } - return 0, errors.New("Item not found") -} - -func (m *MockAuthRepository) GetPassword(ctx context.Context, id uint) ([]byte, error) { - if m.err != nil { - return nil, m.err - } - - for _, m := range m.users { - if m.id == id { - return m.password, nil - } - } - return nil, errors.New("Item not found") -} - -func (m *MockAuthRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) { - if m.err != nil { - return 0, m.err - } - - m.index++ - - m.users = append(m.users, &mockUser{ - id: m.index, - username: createUser.Username, - password: createUser.Password, - }) - - return m.index, nil -} - -func (m *MockAuthRepository) Update(ctx context.Context, id uint, update *user.UpdateUser) error { - if m.err != nil { - return m.err - } - - for _, m := range m.users { - if m.id == id { - m.username = update.Username - } - } - return nil -} - func remove[T any](slice []T, s int) []T { return append(slice[:s], slice[s+1:]...) } - -func (r *MockAuthRepository) Delete(ctx context.Context, id uint) error { - if r.err != nil { - return r.err - } - - for i, m := range r.users { - if m.id == id { - r.users = remove(r.users, i) - } - } - return nil -} - -func (m *MockUserRepository) List(ctx context.Context) ([]*user.User, error) { - panic("not implemented") // TODO: Implement -} - -func (m *MockUserRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) { - panic("not implemented") // TODO: Implement -} - -func (m *MockUserRepository) Update(ctx context.Context, id uint, updateUser *user.UpdateUser) error { - panic("not implemented") // TODO: Implement -} - -func (m *MockUserRepository) Any(ctx context.Context) (bool, error) { - panic("not implemented") // TODO: Implement -} diff --git a/pkg/components/auth/mock_test.go b/pkg/components/auth/mock_test.go new file mode 100644 index 0000000..885f643 --- /dev/null +++ b/pkg/components/auth/mock_test.go @@ -0,0 +1,121 @@ +//go:build unit + +package auth + +import ( + "context" + "errors" + + "git.sr.ht/~gabrielgio/img/pkg/database/repository" +) + +type ( + User struct { + ID uint + Username string + Name string + Password []byte + IsAdmin bool + Path string + } + + Users map[uint]*User + + UserRepository struct { + icount uint + users Users + } +) + +var _ repository.UserRepository = &UserRepository{} +var _ repository.AuthRepository = &UserRepository{} + +func NewUserRepository() *UserRepository { + return &UserRepository{ + users: make(map[uint]*User), + } +} + +func (u *User) ToModel() *repository.User { + return &repository.User{ + ID: u.ID, + Username: u.Username, + Name: u.Name, + IsAdmin: u.IsAdmin, + Path: u.Path, + } +} + +func (u Users) ToModels() []*repository.User { + users := make([]*repository.User, 0, len(u)) + for _, i := range u { + users = append(users, i.ToModel()) + } + return users +} + +func (u *UserRepository) Get(ctx context.Context, id uint) (*repository.User, error) { + if user, ok := u.users[id]; ok { + return user.ToModel(), nil + } + + return nil, errors.New("Not Found") +} + +func (u *UserRepository) List(_ context.Context) ([]*repository.User, error) { + return u.users.ToModels(), nil +} + +func (u *UserRepository) Create(_ context.Context, createUser *repository.CreateUser) (uint, error) { + id := u.furtherID() + u.users[id] = &User{ + ID: id, + Name: createUser.Name, + Username: createUser.Username, + Path: createUser.Path, + Password: createUser.Password, + } + return id, nil +} + +func (u *UserRepository) Update(_ context.Context, id uint, updateUser *repository.UpdateUser) error { + user, ok := u.users[id] + if !ok { + return errors.New("Invalid ID") + } + + user.Name = updateUser.Name + user.Username = updateUser.Username + if updateUser.Password != "" { + user.Password = []byte(updateUser.Password) + } + + return nil +} + +func (u *UserRepository) Any(_ context.Context) (bool, error) { + return len(u.users) > 0, nil +} + +func (u *UserRepository) GetIDByUsername(ctx context.Context, username string) (uint, error) { + for id, u := range u.users { + if u.Username == username { + return id, nil + } + } + + return 0, errors.New("Not Found") +} + +func (u *UserRepository) GetPassword(ctx context.Context, id uint) ([]byte, error) { + if user, ok := u.users[id]; ok { + return []byte(user.Password), nil + } + + return nil, errors.New("Not Found") +} + +func (u *UserRepository) furtherID() uint { + u.icount++ + return u.icount +} diff --git a/pkg/components/auth/model.go b/pkg/components/auth/model.go deleted file mode 100644 index dd6ce50..0000000 --- a/pkg/components/auth/model.go +++ /dev/null @@ -1,10 +0,0 @@ -package auth - -import "context" - -type ( - Repository interface { - GetIDByUsername(ctx context.Context, username string) (uint, error) - GetPassword(ctx context.Context, id uint) ([]byte, error) - } -) diff --git a/pkg/components/user/model.go b/pkg/components/user/model.go deleted file mode 100644 index 0ff6d0a..0000000 --- a/pkg/components/user/model.go +++ /dev/null @@ -1,34 +0,0 @@ -package user - -import "context" - -type ( - User struct { - ID uint - Username string - Name string - IsAdmin bool - Path string - } - - UpdateUser struct { - Username string - Name string - Password *string - } - - CreateUser struct { - Username string - Name string - Password []byte - IsAdmin bool - Path string - } - - Repository interface { - List(ctx context.Context) ([]*User, error) - Create(ctx context.Context, createUser *CreateUser) (uint, error) - Update(ctx context.Context, id uint, updateUser *UpdateUser) error - Any(ctx context.Context) (bool, error) - } -) -- cgit v1.2.3