Compare commits
2 Commits
043f387224
...
4ab08d20b8
| Author | SHA1 | Date |
|---|---|---|
|
|
4ab08d20b8 | |
|
|
fe329d2336 |
|
|
@ -22,6 +22,11 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrAccountNotFound = errors.New("account not found")
|
||||||
|
ErrCouldNotCreateSession = errors.New("could not create session")
|
||||||
|
)
|
||||||
|
|
||||||
func (db *PGRunnerStorage) RegisterAccount(ctx context.Context, in RegisterAccountInput) (accountId int, err error) {
|
func (db *PGRunnerStorage) RegisterAccount(ctx context.Context, in RegisterAccountInput) (accountId int, err error) {
|
||||||
var accId int32
|
var accId int32
|
||||||
if accId, err = db.Queries.RegisterAccount(ctx, postgres.RegisterAccountParams{
|
if accId, err = db.Queries.RegisterAccount(ctx, postgres.RegisterAccountParams{
|
||||||
|
|
@ -59,8 +64,11 @@ func (db *PGRunnerStorage) GetAccount(ctx context.Context, in GetAccountInput) (
|
||||||
if row, err = db.Queries.GetAccountByEmailOrID(ctx, postgres.GetAccountByEmailOrIDParams{
|
if row, err = db.Queries.GetAccountByEmailOrID(ctx, postgres.GetAccountByEmailOrIDParams{
|
||||||
Email: in.Email,
|
Email: in.Email,
|
||||||
ID: int32(in.AccountID),
|
ID: int32(in.AccountID),
|
||||||
}); err != nil {
|
}); errors.Is(err, pgx.ErrNoRows) {
|
||||||
err = fmt.Errorf("could not get account: %w", err)
|
err = ErrAccountNotFound
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
err = fmt.Errorf("could not execute GetAccount query: %w", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,6 +103,7 @@ func (db *PGRunnerStorage) CreateSession(ctx context.Context, in CreateSessionIn
|
||||||
Email: in.Email,
|
Email: in.Email,
|
||||||
Passwordhash: in.PasswordHash,
|
Passwordhash: in.PasswordHash,
|
||||||
}); errors.Is(err, pgx.ErrNoRows) {
|
}); errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
err = ErrCouldNotCreateSession
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
err = fmt.Errorf("could not execute query: %w", err)
|
err = fmt.Errorf("could not execute query: %w", err)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import (
|
||||||
|
|
||||||
"git.vdhsn.com/barretthousen/barretthousen/src/auth/internal/data"
|
"git.vdhsn.com/barretthousen/barretthousen/src/auth/internal/data"
|
||||||
"git.vdhsn.com/barretthousen/barretthousen/src/lib/kernel"
|
"git.vdhsn.com/barretthousen/barretthousen/src/lib/kernel"
|
||||||
"github.com/jackc/pgx/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
|
@ -79,12 +78,13 @@ func (d *Domain) CreateAccount(ctx context.Context, in CreateAccountCommand) (ou
|
||||||
|
|
||||||
out = AccountCreated{
|
out = AccountCreated{
|
||||||
Account: Account{
|
Account: Account{
|
||||||
ID: ar.ID,
|
ID: ar.ID,
|
||||||
Created: ar.Created,
|
Created: ar.Created,
|
||||||
Verified: ar.Verified,
|
Verified: ar.Verified,
|
||||||
Email: ar.Email,
|
Email: ar.Email,
|
||||||
Role: Role(ar.Role),
|
PasswordHash: ar.PasswordHash,
|
||||||
Enabled: ar.Enabled,
|
Role: Role(ar.Role),
|
||||||
|
Enabled: ar.Enabled,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,11 +111,12 @@ func (d *Domain) Login(ctx context.Context, in LoginCommand) (out LoggedIn, err
|
||||||
if sess, err = d.Storage.CreateSession(ctx, data.CreateSessionInput{
|
if sess, err = d.Storage.CreateSession(ctx, data.CreateSessionInput{
|
||||||
Email: in.Email,
|
Email: in.Email,
|
||||||
PasswordHash: in.Password,
|
PasswordHash: in.Password,
|
||||||
}); errors.Is(err, pgx.ErrNoRows) {
|
}); errors.Is(err, data.ErrCouldNotCreateSession) {
|
||||||
err = ErrInvalidLogin
|
err = ErrInvalidLogin
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
err = fmt.Errorf("could not create session: %w", err)
|
kernel.ErrorLog.Printf("Error creating session in storage for %q: %w", in.Email, err)
|
||||||
|
err = ErrInvalidLogin
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,166 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.vdhsn.com/barretthousen/barretthousen/src/auth/internal/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDomain_CreateAccount(t *testing.T) {
|
func TestDomain_CreateAccount(t *testing.T) {
|
||||||
type fields struct {
|
SetupTest()
|
||||||
Storage Storage
|
|
||||||
}
|
tests := map[string]struct {
|
||||||
type args struct {
|
input CreateAccountCommand
|
||||||
in CreateAccountCommand
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
args args
|
|
||||||
wantOut AccountCreated
|
wantOut AccountCreated
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
// TODO: Add test cases.
|
"new account": {
|
||||||
|
input: CreateAccountCommand{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
wantOut: AccountCreated{
|
||||||
|
Account: Account{
|
||||||
|
ID: 0,
|
||||||
|
Email: "test@example.com",
|
||||||
|
PasswordHash: "password",
|
||||||
|
Enabled: true,
|
||||||
|
Role: UserRole,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"no email": {
|
||||||
|
input: CreateAccountCommand{
|
||||||
|
Password: "password",
|
||||||
|
Role: UserRole,
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
"no password": {
|
||||||
|
input: CreateAccountCommand{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Role: UserRole,
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
"no inputs": {
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
c := ioc.Scope("CreateAccountTest")
|
||||||
d := &Domain{
|
|
||||||
Storage: tt.fields.Storage,
|
Must(c.Provide(func(s Storage, ms *MockStorage) *Domain {
|
||||||
}
|
return &Domain{Storage: s}
|
||||||
gotOut, err := d.CreateAccount(tt.args.in)
|
}))
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Domain.CreateAccount() error = %v, wantErr %v", err, tt.wantErr)
|
for name, v := range tests {
|
||||||
return
|
params := v
|
||||||
}
|
t.Run(name, func(t *testing.T) {
|
||||||
if !reflect.DeepEqual(gotOut, tt.wantOut) {
|
Must(c.Invoke(func(sut *Domain, ms *MockStorage) {
|
||||||
t.Errorf("Domain.CreateAccount() = %v, want %v", gotOut, tt.wantOut)
|
var a Account
|
||||||
}
|
ms.RegisterAccountFunc = func(ctx context.Context, rai data.RegisterAccountInput) (int, error) {
|
||||||
|
a = Account{
|
||||||
|
Email: rai.Email,
|
||||||
|
PasswordHash: rai.PasswordHash,
|
||||||
|
Role: Role(rai.Role),
|
||||||
|
Enabled: true,
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ms.GetAccountFunc = func(ctx context.Context, gai data.GetAccountInput) (data.AccountResult, error) {
|
||||||
|
if gai.Email != a.Email {
|
||||||
|
return data.AccountResult{}, errors.New("error")
|
||||||
|
}
|
||||||
|
return data.AccountResult{
|
||||||
|
Email: a.Email,
|
||||||
|
PasswordHash: a.PasswordHash,
|
||||||
|
Role: a.Role.String(),
|
||||||
|
Enabled: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := sut.CreateAccount(context.Background(), params.input)
|
||||||
|
if (err != nil) != params.wantErr {
|
||||||
|
t.Errorf("Domain.CreateAccount() error = %v, wantErr %v", err, params.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(out, params.wantOut) {
|
||||||
|
t.Errorf("Domain.CreateAccount():\n%+v\n, want:\n%+v", out, params.wantOut)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDomain_Login(t *testing.T) {
|
||||||
|
tests := map[string]struct {
|
||||||
|
input LoginCommand
|
||||||
|
wantOut LoggedIn
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
"Login Valid User": {
|
||||||
|
input: LoginCommand{
|
||||||
|
Email: "test@example.com",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
wantOut: LoggedIn{
|
||||||
|
Account: Account{
|
||||||
|
ID: 1,
|
||||||
|
Email: "test@example.com",
|
||||||
|
PasswordHash: "",
|
||||||
|
Enabled: true,
|
||||||
|
Role: UserRole,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c := ioc.Scope("LoginTest")
|
||||||
|
|
||||||
|
Must(c.Provide(func(s Storage) *Domain {
|
||||||
|
return &Domain{Storage: s}
|
||||||
|
}))
|
||||||
|
|
||||||
|
for name, v := range tests {
|
||||||
|
params := v
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
Must(c.Invoke(func(sut *Domain, ms *MockStorage) {
|
||||||
|
ms.CreateSessionFunc = func(ctx context.Context, in data.CreateSessionInput) (data.Session, error) {
|
||||||
|
if strings.EqualFold(in.Email, "test@example.com") {
|
||||||
|
return data.Session{AccountID: 1}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.Session{}, data.ErrCouldNotCreateSession
|
||||||
|
}
|
||||||
|
|
||||||
|
ms.GetAccountFunc = func(ctx context.Context, gai data.GetAccountInput) (data.AccountResult, error) {
|
||||||
|
if strings.EqualFold(gai.Email, "test@example.com") || gai.AccountID == 1 {
|
||||||
|
return data.AccountResult{
|
||||||
|
ID: 1,
|
||||||
|
Email: "test@example.com",
|
||||||
|
Role: UserRole.String(),
|
||||||
|
Enabled: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return data.AccountResult{}, data.ErrAccountNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := sut.Login(context.Background(), params.input)
|
||||||
|
if (err != nil) != params.wantErr {
|
||||||
|
t.Errorf("Domain.Login() error = %v, wantErr %v", err, params.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(out, params.wantOut) {
|
||||||
|
t.Errorf("Domain.Login() = %v, want %v", out, params.wantOut)
|
||||||
|
}
|
||||||
|
}))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"git.vdhsn.com/barretthousen/barretthousen/src/auth/internal/data"
|
||||||
|
"go.uber.org/dig"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ioc dig.Container
|
||||||
|
|
||||||
|
func SetupTest() {
|
||||||
|
ioc = *dig.New()
|
||||||
|
|
||||||
|
if err := ioc.Provide(func() (Storage, *MockStorage) {
|
||||||
|
ms := &MockStorage{}
|
||||||
|
return ms, ms
|
||||||
|
}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must panics is err is not nil
|
||||||
|
func Must(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockStorage struct {
|
||||||
|
RegisterAccountFunc func(context.Context, data.RegisterAccountInput) (int, error)
|
||||||
|
GetAccountFunc func(context.Context, data.GetAccountInput) (data.AccountResult, error)
|
||||||
|
CreateSessionFunc func(context.Context, data.CreateSessionInput) (data.Session, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSession implements Storage.
|
||||||
|
func (m *MockStorage) CreateSession(ctx context.Context, in data.CreateSessionInput) (data.Session, error) {
|
||||||
|
if m.CreateSessionFunc == nil {
|
||||||
|
panic("CreateSessionFunc is unset")
|
||||||
|
}
|
||||||
|
return m.CreateSessionFunc(ctx, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccount implements Storage.
|
||||||
|
func (m *MockStorage) GetAccount(ctx context.Context, in data.GetAccountInput) (data.AccountResult, error) {
|
||||||
|
if m.GetAccountFunc == nil {
|
||||||
|
panic("GetAccountFunc is unset")
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.GetAccountFunc(ctx, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterAccount implements Storage.
|
||||||
|
func (m *MockStorage) RegisterAccount(ctx context.Context, in data.RegisterAccountInput) (int, error) {
|
||||||
|
if m.RegisterAccountFunc == nil {
|
||||||
|
panic("RegisterAccountFunc is unset")
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.RegisterAccountFunc(ctx, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyAccount implements Storage.
|
||||||
|
func (*MockStorage) VerifyAccount(context.Context, data.VerifyAccountInput) error {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
@ -10,8 +10,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
"google.golang.org/grpc/backoff"
|
"google.golang.org/grpc/backoff"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
|
"google.golang.org/grpc/reflection"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerBuilder func(grpc.ServiceRegistrar, string)
|
type ServerBuilder func(grpc.ServiceRegistrar, string)
|
||||||
|
|
@ -38,6 +40,8 @@ func StartGRPCServer(ctx context.Context, port int, sb ServerBuilder, opts ...gr
|
||||||
|
|
||||||
grpcServerInstance = grpc.NewServer(opts...)
|
grpcServerInstance = grpc.NewServer(opts...)
|
||||||
|
|
||||||
|
reflection.Register(grpcServerInstance)
|
||||||
|
|
||||||
sb(grpcServerInstance, endpoint)
|
sb(grpcServerInstance, endpoint)
|
||||||
|
|
||||||
if err = grpcServerInstance.Serve(listener); err != nil {
|
if err = grpcServerInstance.Serve(listener); err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue