chore: build
ci-api / test (push) Failing after 8m7s
ci-web / test (push) Failing after 5m5s

This commit is contained in:
Xor290
2026-09-20 12:18:33 +02:00
parent 8f4c7fa47a
commit 919c807004
174 changed files with 9669 additions and 1308 deletions
+59 -30
View File
@@ -14,29 +14,29 @@ import (
// fakeRepository is an in-memory users.Repository used to unit-test
// users.Service without a real database.
type fakeRepository struct {
byID map[uuid.UUID]*users.User
byEmail map[string]uuid.UUID
byID map[uuid.UUID]*users.User
byUsername map[string]uuid.UUID
}
func newFakeRepository() *fakeRepository {
return &fakeRepository{
byID: make(map[uuid.UUID]*users.User),
byEmail: make(map[string]uuid.UUID),
byID: make(map[uuid.UUID]*users.User),
byUsername: make(map[string]uuid.UUID),
}
}
func (r *fakeRepository) Create(_ context.Context, u *users.User) error {
if _, exists := r.byEmail[u.Email]; exists {
return users.ErrEmailTaken
if _, exists := r.byUsername[u.Username]; exists {
return users.ErrUsernameTaken
}
cp := *u
r.byID[u.ID] = &cp
r.byEmail[u.Email] = u.ID
r.byUsername[u.Username] = u.ID
return nil
}
func (r *fakeRepository) FindByEmail(_ context.Context, email string) (*users.User, error) {
id, ok := r.byEmail[email]
func (r *fakeRepository) FindByUsername(_ context.Context, username string) (*users.User, error) {
id, ok := r.byUsername[username]
if !ok {
return nil, users.ErrNotFound
}
@@ -67,12 +67,12 @@ func (r *fakeRepository) Update(_ context.Context, u *users.User) error {
if !ok {
return users.ErrNotFound
}
if existing.Email != u.Email {
if _, taken := r.byEmail[u.Email]; taken {
return users.ErrEmailTaken
if existing.Username != u.Username {
if _, taken := r.byUsername[u.Username]; taken {
return users.ErrUsernameTaken
}
delete(r.byEmail, existing.Email)
r.byEmail[u.Email] = u.ID
delete(r.byUsername, existing.Username)
r.byUsername[u.Username] = u.ID
}
cp := *u
r.byID[u.ID] = &cp
@@ -84,16 +84,26 @@ func (r *fakeRepository) Delete(_ context.Context, id uuid.UUID) error {
if !ok {
return users.ErrNotFound
}
delete(r.byEmail, u.Email)
delete(r.byUsername, u.Username)
delete(r.byID, id)
return nil
}
// fakeAccountsGate is an in-memory users.AccountsGate used to unit-test the
// customer-role creation gate without a real site.Service.
type fakeAccountsGate struct {
available bool
}
func (g fakeAccountsGate) CustomerAccountsAvailable(context.Context) (bool, error) {
return g.available, nil
}
func TestService_Create_HashesPasswordAndPersists(t *testing.T) {
svc := users.NewService(newFakeRepository())
svc := users.NewService(newFakeRepository(), fakeAccountsGate{available: true})
ctx := context.Background()
user, err := svc.Create(ctx, "admin@example.com", "super-strong-password", users.RoleAdmin)
user, err := svc.Create(ctx, "admin", "super-strong-password", users.RoleAdmin)
if err != nil {
t.Fatalf("Create() error = %v", err)
}
@@ -108,30 +118,30 @@ func TestService_Create_HashesPasswordAndPersists(t *testing.T) {
}
func TestService_Create_RejectsInvalidRole(t *testing.T) {
svc := users.NewService(newFakeRepository())
if _, err := svc.Create(context.Background(), "a@example.com", "super-strong-password", "superadmin"); err == nil {
svc := users.NewService(newFakeRepository(), fakeAccountsGate{available: true})
if _, err := svc.Create(context.Background(), "user-a", "super-strong-password", "superadmin"); err == nil {
t.Fatal("Create() error = nil, want error for an invalid role")
}
}
func TestService_Create_DuplicateEmailRejected(t *testing.T) {
svc := users.NewService(newFakeRepository())
func TestService_Create_DuplicateUsernameRejected(t *testing.T) {
svc := users.NewService(newFakeRepository(), fakeAccountsGate{available: true})
ctx := context.Background()
if _, err := svc.Create(ctx, "dup@example.com", "super-strong-password", users.RoleAdmin); err != nil {
if _, err := svc.Create(ctx, "dup-user", "super-strong-password", users.RoleAdmin); err != nil {
t.Fatalf("first Create() error = %v", err)
}
_, err := svc.Create(ctx, "dup@example.com", "another-strong-password", users.RoleAdmin)
if !errors.Is(err, users.ErrEmailTaken) {
t.Fatalf("second Create() error = %v, want ErrEmailTaken", err)
_, err := svc.Create(ctx, "dup-user", "another-strong-password", users.RoleAdmin)
if !errors.Is(err, users.ErrUsernameTaken) {
t.Fatalf("second Create() error = %v, want ErrUsernameTaken", err)
}
}
func TestService_SetPassword_ChangesHash(t *testing.T) {
svc := users.NewService(newFakeRepository())
svc := users.NewService(newFakeRepository(), fakeAccountsGate{available: true})
ctx := context.Background()
user, err := svc.Create(ctx, "user@example.com", "first-strong-password", users.RoleAdmin)
user, err := svc.Create(ctx, "user1", "first-strong-password", users.RoleAdmin)
if err != nil {
t.Fatalf("Create() error = %v", err)
}
@@ -159,10 +169,10 @@ func TestService_SetPassword_ChangesHash(t *testing.T) {
}
func TestService_Delete_RemovesUser(t *testing.T) {
svc := users.NewService(newFakeRepository())
svc := users.NewService(newFakeRepository(), fakeAccountsGate{available: true})
ctx := context.Background()
user, err := svc.Create(ctx, "todelete@example.com", "super-strong-password", users.RoleAdmin)
user, err := svc.Create(ctx, "todelete", "super-strong-password", users.RoleAdmin)
if err != nil {
t.Fatalf("Create() error = %v", err)
}
@@ -176,8 +186,27 @@ func TestService_Delete_RemovesUser(t *testing.T) {
}
func TestService_Delete_UnknownUserReturnsNotFound(t *testing.T) {
svc := users.NewService(newFakeRepository())
svc := users.NewService(newFakeRepository(), fakeAccountsGate{available: true})
if err := svc.Delete(context.Background(), uuid.New()); !errors.Is(err, users.ErrNotFound) {
t.Fatalf("Delete() error = %v, want ErrNotFound", err)
}
}
func TestService_Create_CustomerRoleRejectedWhenAccountsDisabled(t *testing.T) {
svc := users.NewService(newFakeRepository(), fakeAccountsGate{available: false})
_, err := svc.Create(context.Background(), "some-customer", "super-strong-password", users.RoleCustomer)
if !errors.Is(err, users.ErrCustomerAccountsDisabled) {
t.Fatalf("Create() error = %v, want ErrCustomerAccountsDisabled", err)
}
}
func TestService_Create_CustomerRoleAllowedWhenAccountsEnabled(t *testing.T) {
svc := users.NewService(newFakeRepository(), fakeAccountsGate{available: true})
user, err := svc.Create(context.Background(), "some-customer", "super-strong-password", users.RoleCustomer)
if err != nil {
t.Fatalf("Create() error = %v", err)
}
if user.Role != users.RoleCustomer {
t.Fatalf("Create() role = %q, want %q", user.Role, users.RoleCustomer)
}
}