101 lines
2.4 KiB
Go
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...)
|
|
}
|