package reseed import ( "context" "errors" "io" "net/http" "net/http/httptest" "strings" "testing" "boostai-backend/internal/config" "boostai-backend/internal/seeddata" "github.com/gofiber/fiber/v2" ) func TestPageRequiresEnableFlag(t *testing.T) { t.Parallel() h := &Handler{cfg: &config.Config{Environment: "production"}} status, _ := performRequest(t, h, http.MethodGet, "/reseed", "", "") if status != fiber.StatusNotFound { t.Fatalf("expected 404, got %d", status) } } func TestLoginSetsCookieAndRedirects(t *testing.T) { t.Parallel() h := newTestHandler(func(ctx context.Context, mockDataDir string) (seeddata.Summary, error) { return seeddata.Summary{}, nil }) status, resp := performRequest(t, h, http.MethodPost, "/reseed/login", "password=1588", "") if status != fiber.StatusSeeOther { t.Fatalf("expected 303, got %d", status) } if location := resp.Header.Get("Location"); location != "/reseed" { t.Fatalf("expected redirect to /reseed, got %q", location) } if cookie := resp.Header.Get("Set-Cookie"); !strings.Contains(cookie, reseedCookieName+"=") { t.Fatalf("expected auth cookie, got %q", cookie) } } func TestRunRequiresAuthCookie(t *testing.T) { t.Parallel() h := newTestHandler(func(ctx context.Context, mockDataDir string) (seeddata.Summary, error) { return seeddata.Summary{}, nil }) status, body := performRequestBody(t, h, http.MethodPost, "/reseed/run", "", "") if status != fiber.StatusUnauthorized { t.Fatalf("expected 401, got %d", status) } if !strings.Contains(body, "Please unlock the reseed page first") { t.Fatalf("expected unlock message, got %q", body) } } func TestRunExecutesReseed(t *testing.T) { t.Parallel() h := newTestHandler(func(ctx context.Context, mockDataDir string) (seeddata.Summary, error) { if mockDataDir != "/app/Mock-Data" { t.Fatalf("expected mock data dir /app/Mock-Data, got %q", mockDataDir) } return seeddata.Summary{Users: 13, Assignments: 8, StudentAnswers: 588, MockDataDir: mockDataDir}, nil }) status, body := performRequestBody(t, h, http.MethodPost, "/reseed/run", "", reseedCookieName+"="+h.authCookieValue()) if status != fiber.StatusOK { t.Fatalf("expected 200, got %d", status) } if !strings.Contains(body, "Reseed completed") || !strings.Contains(body, "student_answers: 588") { t.Fatalf("expected success summary, got %q", body) } } func TestRunSurfacesRunnerError(t *testing.T) { t.Parallel() h := newTestHandler(func(ctx context.Context, mockDataDir string) (seeddata.Summary, error) { return seeddata.Summary{}, errors.New("boom") }) status, body := performRequestBody(t, h, http.MethodPost, "/reseed/run", "", reseedCookieName+"="+h.authCookieValue()) if status != fiber.StatusInternalServerError { t.Fatalf("expected 500, got %d", status) } if !strings.Contains(body, "boom") { t.Fatalf("expected error body, got %q", body) } } func newTestHandler(fn func(context.Context, string) (seeddata.Summary, error)) *Handler { return &Handler{ cfg: &config.Config{ Environment: "production", AdminReseedEnabled: true, MockDataDir: "/app/Mock-Data", JWTSecret: "jwt-secret", ReseedPagePassword: "1588", }, runner: fn, } } func performRequest(t *testing.T, handler *Handler, method, path, formBody, cookieHeader string) (int, *http.Response) { t.Helper() app := testApp(handler) req := httptest.NewRequest(method, path, strings.NewReader(formBody)) if formBody != "" { req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } if cookieHeader != "" { req.Header.Set("Cookie", cookieHeader) } resp, err := app.Test(req) if err != nil { t.Fatalf("app.Test: %v", err) } return resp.StatusCode, resp } func performRequestBody(t *testing.T, handler *Handler, method, path, formBody, cookieHeader string) (int, string) { t.Helper() status, resp := performRequest(t, handler, method, path, formBody, cookieHeader) defer resp.Body.Close() bodyBytes, err := io.ReadAll(resp.Body) if err != nil { t.Fatalf("ReadAll: %v", err) } return status, string(bodyBytes) } func testApp(handler *Handler) *fiber.App { app := fiber.New() app.Get("/reseed", handler.Page) app.Post("/reseed/login", handler.Login) app.Post("/reseed/run", handler.Run) app.Post("/reseed/logout", handler.Logout) return app }