diff --git a/internals/modules/users/manager/api_test.go b/internals/modules/users/manager/api_test.go new file mode 100644 index 0000000..3ee4522 --- /dev/null +++ b/internals/modules/users/manager/api_test.go @@ -0,0 +1,48 @@ +package manager + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/golang/mock/gomock" + "github.com/gorilla/mux" + nbcontext "github.com/netbirdio/netbird/management/server/context" + "github.com/stretchr/testify/require" + + "github.com/netbirdio/management-refactor/internals/modules/users" + "github.com/netbirdio/management-refactor/internals/shared/permissions" + "github.com/netbirdio/management-refactor/internals/shared/permissions/modules" + "github.com/netbirdio/management-refactor/internals/shared/permissions/operations" +) + +func TestGetAllUsersReturnsUsers(t *testing.T) { + ctrl := gomock.NewController(t) + managerMock := NewMockManager(ctrl) + permissionsMock := permissions.NewMockManager(ctrl) + permissionsMock.EXPECT().WithPermission(modules.Users, operations.Read, gomock.Any()).DoAndReturn( + func(module modules.Module, operation operations.Operation, handlerFunc func(http.ResponseWriter, *http.Request, *nbcontext.UserAuth)) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + handlerFunc(w, r, &nbcontext.UserAuth{UserId: "123", AccountId: "abc"}) + } + }).AnyTimes() + + managerMock.EXPECT().GetAllUsers(gomock.Any(), gomock.Any(), gomock.Any(), "abc").Return([]users.User{{Id: "1"}, {Id: "2"}}, nil).Times(1) + + router := mux.NewRouter() + RegisterEndpoints(router, permissionsMock, managerMock) + + req := httptest.NewRequest(http.MethodGet, "/users", nil) + req.Header.Set("Authorization", "Bearer token") + w := httptest.NewRecorder() + + router.ServeHTTP(w, req) + + require.Equal(t, http.StatusOK, w.Code) + var response []users.User + err := json.NewDecoder(w.Body).Decode(&response) + require.NoError(t, err) + require.Len(t, response, 2) + require.Equal(t, "1", response[0].Id) +} diff --git a/internals/modules/users/manager/manager.go b/internals/modules/users/manager/manager.go index 8eec930..10dddc2 100644 --- a/internals/modules/users/manager/manager.go +++ b/internals/modules/users/manager/manager.go @@ -1,5 +1,7 @@ package manager +//go:generate go run github.com/golang/mock/mockgen -package manager -destination=manager_mock.go -source=../interface.go -build_flags=-mod=mod + import ( "context" @@ -20,5 +22,12 @@ func (m *Manager) GetAllUsers(ctx context.Context, tx db.Transaction, strength d } func (m *Manager) GetUserByID(ctx context.Context, tx db.Transaction, strength db.LockingStrength, id string) (*users.User, error) { - return m.repo.GetUserByID(tx, strength, id) + user, err := m.repo.GetUserByID(tx, strength, id) + if err != nil { + return nil, err + } + + user.Issued = "****" + + return user, nil } diff --git a/internals/modules/users/manager/manager_mock.go b/internals/modules/users/manager/manager_mock.go new file mode 100644 index 0000000..dfd46df --- /dev/null +++ b/internals/modules/users/manager/manager_mock.go @@ -0,0 +1,67 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ../interface.go + +// Package manager is a generated GoMock package. +package manager + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + users "github.com/netbirdio/management-refactor/internals/modules/users" + db "github.com/netbirdio/management-refactor/internals/shared/db" +) + +// MockManager is a mock of Manager interface. +type MockManager struct { + ctrl *gomock.Controller + recorder *MockManagerMockRecorder +} + +// MockManagerMockRecorder is the mock recorder for MockManager. +type MockManagerMockRecorder struct { + mock *MockManager +} + +// NewMockManager creates a new mock instance. +func NewMockManager(ctrl *gomock.Controller) *MockManager { + mock := &MockManager{ctrl: ctrl} + mock.recorder = &MockManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockManager) EXPECT() *MockManagerMockRecorder { + return m.recorder +} + +// GetAllUsers mocks base method. +func (m *MockManager) GetAllUsers(ctx context.Context, tx db.Transaction, strength db.LockingStrength, accountID string) ([]users.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllUsers", ctx, tx, strength, accountID) + ret0, _ := ret[0].([]users.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllUsers indicates an expected call of GetAllUsers. +func (mr *MockManagerMockRecorder) GetAllUsers(ctx, tx, strength, accountID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllUsers", reflect.TypeOf((*MockManager)(nil).GetAllUsers), ctx, tx, strength, accountID) +} + +// GetUserByID mocks base method. +func (m *MockManager) GetUserByID(ctx context.Context, tx db.Transaction, strength db.LockingStrength, id string) (*users.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserByID", ctx, tx, strength, id) + ret0, _ := ret[0].(*users.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserByID indicates an expected call of GetUserByID. +func (mr *MockManagerMockRecorder) GetUserByID(ctx, tx, strength, id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByID", reflect.TypeOf((*MockManager)(nil).GetUserByID), ctx, tx, strength, id) +} diff --git a/internals/modules/users/manager/manager_test.go b/internals/modules/users/manager/manager_test.go new file mode 100644 index 0000000..8f53809 --- /dev/null +++ b/internals/modules/users/manager/manager_test.go @@ -0,0 +1,26 @@ +package manager + +import ( + "context" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + + "github.com/netbirdio/management-refactor/internals/modules/users" + "github.com/netbirdio/management-refactor/internals/shared/db" +) + +func TestHideUserIssued(t *testing.T) { + ctrl := gomock.NewController(t) + repoMock := NewMockRepository(ctrl) + repoMock.EXPECT().GetUserByID(gomock.Any(), gomock.Any(), "5").Return(&users.User{Id: "5", Issued: "top secret"}, nil).AnyTimes() + + manager := NewManager(repoMock) + + result, err := manager.GetUserByID(context.Background(), nil, db.LockingStrengthShare, "5") + assert.NoError(t, err) + + assert.Equal(t, "****", result.Issued) + +} diff --git a/internals/modules/users/manager/repository.go b/internals/modules/users/manager/repository.go index 1ba8e2e..a64d614 100644 --- a/internals/modules/users/manager/repository.go +++ b/internals/modules/users/manager/repository.go @@ -1,5 +1,7 @@ package manager +//go:generate go run github.com/golang/mock/mockgen -package manager -destination=repository_mock.go -source=./repository.go -build_flags=-mod=mod + import ( log "github.com/sirupsen/logrus" diff --git a/internals/modules/users/manager/repository_mock.go b/internals/modules/users/manager/repository_mock.go new file mode 100644 index 0000000..cc6d86c --- /dev/null +++ b/internals/modules/users/manager/repository_mock.go @@ -0,0 +1,94 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./repository.go + +// Package manager is a generated GoMock package. +package manager + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + users "github.com/netbirdio/management-refactor/internals/modules/users" + db "github.com/netbirdio/management-refactor/internals/shared/db" +) + +// MockRepository is a mock of Repository interface. +type MockRepository struct { + ctrl *gomock.Controller + recorder *MockRepositoryMockRecorder +} + +// MockRepositoryMockRecorder is the mock recorder for MockRepository. +type MockRepositoryMockRecorder struct { + mock *MockRepository +} + +// NewMockRepository creates a new mock instance. +func NewMockRepository(ctrl *gomock.Controller) *MockRepository { + mock := &MockRepository{ctrl: ctrl} + mock.recorder = &MockRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { + return m.recorder +} + +// CreateUser mocks base method. +func (m *MockRepository) CreateUser(tx db.Transaction, u *users.User) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateUser", tx, u) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateUser indicates an expected call of CreateUser. +func (mr *MockRepositoryMockRecorder) CreateUser(tx, u interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUser", reflect.TypeOf((*MockRepository)(nil).CreateUser), tx, u) +} + +// GetAllUsers mocks base method. +func (m *MockRepository) GetAllUsers(tx db.Transaction, strength db.LockingStrength, accountID string) ([]users.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllUsers", tx, strength, accountID) + ret0, _ := ret[0].([]users.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAllUsers indicates an expected call of GetAllUsers. +func (mr *MockRepositoryMockRecorder) GetAllUsers(tx, strength, accountID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllUsers", reflect.TypeOf((*MockRepository)(nil).GetAllUsers), tx, strength, accountID) +} + +// GetUserByID mocks base method. +func (m *MockRepository) GetUserByID(tx db.Transaction, strength db.LockingStrength, id string) (*users.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserByID", tx, strength, id) + ret0, _ := ret[0].(*users.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserByID indicates an expected call of GetUserByID. +func (mr *MockRepositoryMockRecorder) GetUserByID(tx, strength, id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByID", reflect.TypeOf((*MockRepository)(nil).GetUserByID), tx, strength, id) +} + +// RunInTx mocks base method. +func (m *MockRepository) RunInTx(fn func(db.Transaction) error) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RunInTx", fn) + ret0, _ := ret[0].(error) + return ret0 +} + +// RunInTx indicates an expected call of RunInTx. +func (mr *MockRepositoryMockRecorder) RunInTx(fn interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunInTx", reflect.TypeOf((*MockRepository)(nil).RunInTx), fn) +} diff --git a/internals/modules/users/manager/repository_test.go b/internals/modules/users/manager/repository_test.go new file mode 100644 index 0000000..2f19c0a --- /dev/null +++ b/internals/modules/users/manager/repository_test.go @@ -0,0 +1,27 @@ +package manager + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/netbirdio/management-refactor/internals/shared/db" +) + +func TestGetUserByID(t *testing.T) { + cfg := &db.Config{ + Engine: "", + PostgresDsn: "", + DataDir: "", + } + dbConn, err := db.NewDatabaseConn(context.Background(), cfg) + assert.NoError(t, err) + store := db.NewStore(context.Background(), dbConn) + repo := NewRepository(store) + + result, err := repo.GetUserByID(nil, db.LockingStrengthShare, "5") + assert.NoError(t, err) + + assert.Equal(t, "5", result.Id) +} diff --git a/internals/server/boot.go b/internals/server/boot.go index 1f3d33d..ed8e91b 100644 --- a/internals/server/boot.go +++ b/internals/server/boot.go @@ -14,12 +14,19 @@ import ( "github.com/netbirdio/management-refactor/internals/shared/api/rest" "github.com/netbirdio/management-refactor/internals/shared/db" "github.com/netbirdio/management-refactor/internals/shared/metrics" + "github.com/netbirdio/management-refactor/pkg/configuration" ) func (s *BaseServer) Store() *db.Store { return Create(s, func() *db.Store { ctx := context.Background() - dbConn, err := db.NewDatabaseConn(ctx) + + cfg, err := configuration.Parse[db.Config]() + if err != nil { + log.Fatalf("failed to parse config: %v", err) + } + + dbConn, err := db.NewDatabaseConn(ctx, cfg) if err != nil { log.Fatalf("error while creating database connection: %s", err) } diff --git a/internals/shared/db/config.go b/internals/shared/db/config.go index 99a06b0..33a8277 100644 --- a/internals/shared/db/config.go +++ b/internals/shared/db/config.go @@ -1,6 +1,6 @@ package db -type config struct { +type Config struct { Engine string `env:"NB_STORE_ENGINE" envDefault:"sqlite"` PostgresDsn string `env:"NB_STORE_ENGINE_POSTGRES_DSN" envDefault:""` DataDir string `env:"NB_STORE_DATA_DIR" envDefault:"/var/lib/netbird"` diff --git a/internals/shared/db/database_connection.go b/internals/shared/db/database_connection.go index 7716a0f..ec9c302 100644 --- a/internals/shared/db/database_connection.go +++ b/internals/shared/db/database_connection.go @@ -13,7 +13,6 @@ import ( "gorm.io/gorm/logger" "github.com/netbirdio/management-refactor/internals/shared/errors" - "github.com/netbirdio/management-refactor/pkg/configuration" ) const ( @@ -26,15 +25,11 @@ type DatabaseConn struct { } // NewDatabaseConn creates a new database connection based on the store engine -func NewDatabaseConn(ctx context.Context) (*DatabaseConn, error) { - cfg, err := configuration.Parse[config]() - if err != nil { - log.Fatalf("failed to parse config: %v", err) - } - +func NewDatabaseConn(ctx context.Context, cfg *Config) (*DatabaseConn, error) { log.WithContext(ctx).Infof("using %s store engine", cfg.Engine) var db *gorm.DB + var err error switch Engine(cfg.Engine) { case SqliteStoreEngine: db, err = openSQLiteDB(cfg) @@ -76,7 +71,7 @@ func openMemoryDB() (*gorm.DB, error) { } // openSQLiteDB opens a new connection to a SQLite database -func openSQLiteDB(cfg *config) (*gorm.DB, error) { +func openSQLiteDB(cfg *Config) (*gorm.DB, error) { storeStr := fmt.Sprintf("%s?cache=shared", storeSqliteFileName) if runtime.GOOS == "windows" { // To avoid `The process cannot access the file because it is being used by another process` on Windows @@ -93,7 +88,7 @@ func openSQLiteDB(cfg *config) (*gorm.DB, error) { } // openPostgresDB opens a new connection to a Postgres database -func openPostgresDB(cfg *config) (*gorm.DB, error) { +func openPostgresDB(cfg *Config) (*gorm.DB, error) { db, err := gorm.Open(postgres.Open(cfg.PostgresDsn), getGormConfig()) if err != nil { return nil, err diff --git a/pkg/logging/logging.properties b/pkg/logging/logging.properties index fd4eb55..b158573 100755 --- a/pkg/logging/logging.properties +++ b/pkg/logging/logging.properties @@ -1,3 +1,3 @@ -rootLogger=ERROR +rootLogger=TRACE management-refactor/integrations/server=ERROR \ No newline at end of file