update_server/internal/auth/service_test.go
2026-06-10 20:51:17 +03:00

101 lines
2.4 KiB
Go

package auth_test
import (
"context"
"io"
"log/slog"
"path/filepath"
"runtime"
"testing"
"time"
"update_server/internal/auth"
"update_server/internal/config"
"update_server/internal/db"
)
func TestEnsureBootstrapAdminCreatesSingleAdminUser(t *testing.T) {
t.Parallel()
ctx := context.Background()
store := newTestStore(t)
defer store.Close()
cfg := config.Config{
AdminEmail: "admin@example.com",
AdminPassword: "correct horse battery staple",
SessionCookieName: "update_server_session",
SessionTTL: 24 * time.Hour,
}
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
service := auth.NewService(cfg, logger, store)
if err := service.EnsureBootstrapAdmin(ctx); err != nil {
t.Fatalf("bootstrap admin: %v", err)
}
if err := service.EnsureBootstrapAdmin(ctx); err != nil {
t.Fatalf("bootstrap admin second pass: %v", err)
}
user, err := store.Users.GetByEmail(ctx, cfg.AdminEmail)
if err != nil {
t.Fatalf("load bootstrapped admin: %v", err)
}
if user.Role != db.UserRoleAdmin {
t.Fatalf("expected admin role, got %q", user.Role)
}
if !user.IsActive {
t.Fatal("expected bootstrapped admin to be active")
}
if user.PasswordHash == cfg.AdminPassword {
t.Fatal("expected bootstrapped password to be hashed")
}
if err := auth.ComparePassword(user.PasswordHash, cfg.AdminPassword); err != nil {
t.Fatalf("compare hashed password: %v", err)
}
var userCount int
if err := store.DB.QueryRowContext(ctx, `SELECT COUNT(*) FROM users`).Scan(&userCount); err != nil {
t.Fatalf("count users: %v", err)
}
if userCount != 1 {
t.Fatalf("expected one bootstrapped user, got %d", userCount)
}
}
func newTestStore(t *testing.T) *db.Store {
t.Helper()
sqlitePath := filepath.Join(t.TempDir(), "update-server.sqlite")
database, err := db.Open(context.Background(), sqlitePath)
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
if err := db.Migrate(context.Background(), database, testProjectPath(t, "migrations")); err != nil {
database.Close()
t.Fatalf("migrate sqlite: %v", err)
}
return db.NewStore(database)
}
func testProjectPath(t *testing.T, parts ...string) string {
t.Helper()
_, filename, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("resolve caller path")
}
root := filepath.Join(filepath.Dir(filename), "..", "..")
items := append([]string{root}, parts...)
return filepath.Join(items...)
}