From 3232632200b7b6434d640358f9973b472ca82ac1 Mon Sep 17 00:00:00 2001 From: Tim Wundenberg Date: Sat, 5 Oct 2024 23:40:37 +0200 Subject: [PATCH] fix: new test and extract time.Now to mockable Clock #181 --- .mockery.yaml | 1 + handler/default.go | 3 ++- service/auth.go | 10 ++++---- service/auth_test.go | 54 +++++++++++++++++++++++++++++++++++++++----- service/clock.go | 17 ++++++++++++++ 5 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 service/clock.go diff --git a/.mockery.yaml b/.mockery.yaml index b6a04fb..50c6e2e 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -5,6 +5,7 @@ packages: me-fit/service: interfaces: RandomGenerator: + Clock: me-fit/db: interfaces: DbAuth: diff --git a/handler/default.go b/handler/default.go index c19cc5f..6244f08 100644 --- a/handler/default.go +++ b/handler/default.go @@ -16,8 +16,9 @@ func GetHandler(d *sql.DB, serverSettings *types.ServerSettings) http.Handler { router.HandleFunc("/", service.HandleIndexAnd404(d, serverSettings)) randomGenerator := service.NewRandomGeneratorImpl() + clock := service.NewClockImpl() dbAuth := db.NewDbAuthSqlite(d) - serviceAuth := service.NewServiceAuthImpl(dbAuth, randomGenerator, serverSettings) + serviceAuth := service.NewServiceAuthImpl(dbAuth, randomGenerator, clock, serverSettings) handlerAuth := NewHandlerAuth(d, serviceAuth, serverSettings) // Serve static files (CSS, JS and images) diff --git a/service/auth.go b/service/auth.go index 99dcda5..7998b64 100644 --- a/service/auth.go +++ b/service/auth.go @@ -10,7 +10,6 @@ import ( "net/mail" "net/url" "strings" - "time" "me-fit/db" "me-fit/template" @@ -54,14 +53,16 @@ type ServiceAuth interface { type ServiceAuthImpl struct { dbAuth db.DbAuth randomGenerator RandomGenerator + clock Clock serverSettings *types.ServerSettings mailService MailService } -func NewServiceAuthImpl(dbAuth db.DbAuth, randomGenerator RandomGenerator, serverSettings *types.ServerSettings) *ServiceAuthImpl { +func NewServiceAuthImpl(dbAuth db.DbAuth, randomGenerator RandomGenerator, clock Clock, serverSettings *types.ServerSettings) *ServiceAuthImpl { return &ServiceAuthImpl{ dbAuth: dbAuth, randomGenerator: randomGenerator, + clock: clock, serverSettings: serverSettings, mailService: NewMailService(serverSettings), } @@ -96,9 +97,8 @@ func (service ServiceAuthImpl) SignUp(email string, password string) (*User, err return nil, ErrInvalidPassword } - userId, err := uuid.NewRandom() + userId, err := service.randomGenerator.UUID() if err != nil { - utils.LogError("Could not generate UUID", err) return nil, types.ErrInternal } @@ -109,7 +109,7 @@ func (service ServiceAuthImpl) SignUp(email string, password string) (*User, err hash := GetHashPassword(password, salt) - dbUser := db.NewUser(userId, email, false, nil, false, hash, salt, time.Now()) + dbUser := db.NewUser(userId, email, false, nil, false, hash, salt, service.clock.Now()) err = service.dbAuth.InsertUser(dbUser) if err != nil { diff --git a/service/auth_test.go b/service/auth_test.go index 2b2ebb2..78cb7ef 100644 --- a/service/auth_test.go +++ b/service/auth_test.go @@ -14,6 +14,7 @@ import ( ) func TestSignIn(t *testing.T) { + t.Parallel() t.Run("should return user if password is correct", func(t *testing.T) { t.Parallel() @@ -33,8 +34,9 @@ func TestSignIn(t *testing.T) { mockDbAuth := mocks.NewMockDbAuth(t) mockDbAuth.EXPECT().GetUser("test@test.de").Return(user, nil) mockRandom := mocks.NewMockRandomGenerator(t) + mockClock := mocks.NewMockClock(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) actualUser, err := underTest.SignIn(user.Email, "password") assert.Nil(t, err) @@ -67,8 +69,9 @@ func TestSignIn(t *testing.T) { mockDbAuth := mocks.NewMockDbAuth(t) mockDbAuth.EXPECT().GetUser(user.Email).Return(user, nil) mockRandom := mocks.NewMockRandomGenerator(t) + mockClock := mocks.NewMockClock(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) _, err := underTest.SignIn("test@test.de", "wrong password") @@ -80,8 +83,9 @@ func TestSignIn(t *testing.T) { mockDbAuth := mocks.NewMockDbAuth(t) mockDbAuth.EXPECT().GetUser("test").Return(nil, db.ErrUserNotFound) mockRandom := mocks.NewMockRandomGenerator(t) + mockClock := mocks.NewMockClock(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) _, err := underTest.SignIn("test", "test") assert.Equal(t, ErrInvaidCredentials, err) @@ -92,8 +96,9 @@ func TestSignIn(t *testing.T) { mockDbAuth := mocks.NewMockDbAuth(t) mockDbAuth.EXPECT().GetUser("test").Return(nil, errors.New("Some undefined error")) mockRandom := mocks.NewMockRandomGenerator(t) + mockClock := mocks.NewMockClock(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) _, err := underTest.SignIn("test", "test") @@ -108,8 +113,9 @@ func TestSignUp(t *testing.T) { mockDbAuth := mocks.NewMockDbAuth(t) mockRandom := mocks.NewMockRandomGenerator(t) + mockClock := mocks.NewMockClock(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) _, err := underTest.SignUp("invalid email address", "SomeStrongPassword123!") @@ -120,8 +126,9 @@ func TestSignUp(t *testing.T) { mockDbAuth := mocks.NewMockDbAuth(t) mockRandom := mocks.NewMockRandomGenerator(t) + mockClock := mocks.NewMockClock(t) - underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, &types.ServerSettings{}) + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) weakPasswords := []string{ "123!ab", // too short @@ -135,4 +142,39 @@ func TestSignUp(t *testing.T) { assert.Equal(t, ErrInvalidPassword, err) } }) + t.Run("should signup correctly", func(t *testing.T) { + t.Parallel() + + mockDbAuth := mocks.NewMockDbAuth(t) + mockRandom := mocks.NewMockRandomGenerator(t) + mockClock := mocks.NewMockClock(t) + + expected := User{ + Id: uuid.New(), + Email: "some@valid.email", + EmailVerified: false, + } + + random := NewRandomGeneratorImpl() + salt, err := random.Bytes(16) + assert.Nil(t, err) + password := "SomeStrongPassword123!" + + mockRandom.EXPECT().UUID().Return(expected.Id, nil) + mockRandom.EXPECT().Bytes(16).Return(salt, nil) + + createTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) + + mockClock.EXPECT().Now().Return(createTime) + + mockDbAuth.EXPECT().InsertUser(db.NewUser(expected.Id, expected.Email, false, nil, false, GetHashPassword(password, salt), salt, createTime)).Return(nil) + + underTest := NewServiceAuthImpl(mockDbAuth, mockRandom, mockClock, &types.ServerSettings{}) + + actual, err := underTest.SignUp(expected.Email, password) + + assert.Nil(t, err) + + assert.Equal(t, expected, *actual) + }) } diff --git a/service/clock.go b/service/clock.go new file mode 100644 index 0000000..cf7cae9 --- /dev/null +++ b/service/clock.go @@ -0,0 +1,17 @@ +package service + +import "time" + +type Clock interface { + Now() time.Time +} + +type ClockImpl struct{} + +func NewClockImpl() Clock { + return &ClockImpl{} +} + +func (c *ClockImpl) Now() time.Time { + return time.Now() +}