Files
mygo/internal/service/admin_test.go
T
ld a18f96912d feat(repository): refactor query/mutation ports with capability-safe
interfaces

- refactor: split UserRepository into AuthUserRepository and
  AdminUserRepository capabilities
- refactor: split SessionRepository into AuthSessionRepository and
  repository-owned CLI/admin methods
- refactor: replace generic Repository Update/Delete with
  operation-specific params and ownership predicates
- refactor: replace CredentialRepository generic CRUD with
  passkey-specific methods
- refactor: replace FileRepository generic Create/Update/Delete with
  UploadedFileParams, DirectoryParams, and owned soft-delete
- refactor: remove repository fields from WebApp struct; repositories
  are now composition-time wiring only
- feat: add domain error kinds ErrParentNotFound, ErrParentNotDir,
  ErrDirectoryNotEmpty, ErrInvalidMove
- feat: add CredentialTypeAppPasskey constant
- feat: add testutil.SetUserAdmin for test fixture setup that bypasses
  production service ports
- test: add architecture test banning GORM Save in repository package
- test: add capability interface contract tests ensuring each service
  receives the minimal interface
- test: add blockingStorage helper for concurrent promotion tests
- test: add preserved DSN parameter test for sqliteImmediateDSN
- docs: update architecture decisions with repository write rules and
  capability separation
- docs: update roadmap to clarify atomic single-use refresh sessions
- docs: add -race test target to development docs
2026-07-16 12:24:36 +08:00

70 lines
2.0 KiB
Go

package service
import (
"context"
"errors"
"testing"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"github.com/dhao2001/mygo/internal/model"
"github.com/dhao2001/mygo/internal/repository"
)
func setupAdminService(t *testing.T) (*AdminService, repository.UserRepository) {
t.Helper()
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatalf("open db: %v", err)
}
if err := db.AutoMigrate(&model.User{}); err != nil {
t.Fatalf("migrate: %v", err)
}
userRepo := repository.NewUserRepository(db)
return NewAdminService(userRepo), userRepo
}
func TestAdminServiceGetUserMissingReturnsNotFound(t *testing.T) {
svc, _ := setupAdminService(t)
_, err := svc.GetUser(context.Background(), "missing")
var ae *model.AppError
if !errors.As(err, &ae) {
t.Fatalf("expected AppError, got %T: %v", err, err)
}
if ae.Kind != model.KindNotFound {
t.Fatalf("kind = %q, want %q", ae.Kind, model.KindNotFound)
}
}
func TestAdminServiceListIncludesDeletedUsers(t *testing.T) {
svc, repo := setupAdminService(t)
ctx := context.Background()
active := &model.User{ID: "active-1", Username: "active", Email: "active@example.com", Status: model.StatusActive}
deleted := &model.User{ID: "deleted-1", Username: "deleted", Email: "deleted@example.com", Status: model.StatusActive}
if _, err := repo.CreateRegisteredUser(ctx, repository.RegisteredUserParams{ID: active.ID, Username: active.Username, Email: active.Email, PasswordHash: "hash"}); err != nil {
t.Fatalf("create active: %v", err)
}
if _, err := repo.CreateRegisteredUser(ctx, repository.RegisteredUserParams{ID: deleted.ID, Username: deleted.Username, Email: deleted.Email, PasswordHash: "hash"}); err != nil {
t.Fatalf("create deleted: %v", err)
}
if err := repo.MarkAdminDeleted(ctx, deleted.ID); err != nil {
t.Fatalf("delete user: %v", err)
}
users, total, err := svc.ListUsers(ctx, 0, 10)
if err != nil {
t.Fatalf("ListUsers = %v", err)
}
if total != 2 {
t.Fatalf("total = %d, want 2", total)
}
if len(users) != 2 {
t.Fatalf("len(users) = %d, want 2", len(users))
}
}