package api import ( "encoding/json" "net/http" "net/http/httptest" "path/filepath" "testing" authmock "geniusrun/backend/internal/auth/mock" "geniusrun/backend/internal/garmin" "geniusrun/backend/internal/garmin/mock" "geniusrun/backend/internal/store" appsync "geniusrun/backend/internal/sync" ) func TestSetup_ProvisionsNewUserWithDisplayName(t *testing.T) { // This test specifically needs an *unprovisioned* session, unlike every // other test in this package -- build the server without the // newTestServer helper's automatic ProvisionUser call. db, err := store.Open(filepath.Join(t.TempDir(), "geniusrun_test.db")) if err != nil { t.Fatalf("store.Open: %v", err) } t.Cleanup(func() { db.Close() }) m := &mock.Client{} s := NewServer(db, func(garmin.Config) garmin.Client { return m }, garmin.Config{}, appsync.Config{}, &authmock.Verifier{}, testSessionConfig) router := s.Router() rec := doJSON(t, router, http.MethodGet, "/api/session/me", nil) var me sessionMeResponse unmarshalBody(t, rec, &me) if me.HasProfile { t.Fatal("expected a brand-new session to have no profile yet") } rec = doJSON(t, router, http.MethodPost, "/api/setup", map[string]any{"display_name": "Lucie"}) if rec.Code != http.StatusOK { t.Fatalf("setup status = %d, body = %s", rec.Code, rec.Body.String()) } rec = doJSON(t, router, http.MethodGet, "/api/session/me", nil) unmarshalBody(t, rec, &me) if !me.HasProfile || me.DisplayName != "Lucie" { t.Fatalf("session/me after setup = %+v, want HasProfile=true DisplayName=Lucie", me) } u, found, err := db.GetUserBySub(newCtx(), "test-user") // doJSON's test cookie's Sub if err != nil || !found { t.Fatalf("GetUserBySub: found=%v err=%v", found, err) } if u.DisplayName != "Lucie" { t.Errorf("stored DisplayName = %q, want Lucie", u.DisplayName) } } func TestSetup_RejectsEmptyDisplayName(t *testing.T) { db, err := store.Open(filepath.Join(t.TempDir(), "geniusrun_test.db")) if err != nil { t.Fatalf("store.Open: %v", err) } t.Cleanup(func() { db.Close() }) m := &mock.Client{} s := NewServer(db, func(garmin.Config) garmin.Client { return m }, garmin.Config{}, appsync.Config{}, &authmock.Verifier{}, testSessionConfig) rec := doJSON(t, s.Router(), http.MethodPost, "/api/setup", map[string]any{"display_name": ""}) if rec.Code != http.StatusBadRequest { t.Fatalf("status = %d, want 400", rec.Code) } } func TestSetup_RejectsWhenAlreadyProvisioned(t *testing.T) { s, _, _ := newTestServer(t) rec := doJSON(t, s.Router(), http.MethodPost, "/api/setup", map[string]any{"display_name": "Someone Else"}) if rec.Code != http.StatusConflict { t.Fatalf("status = %d, want 409, body = %s", rec.Code, rec.Body.String()) } } func unmarshalBody(t *testing.T, rec *httptest.ResponseRecorder, v any) { t.Helper() if err := json.Unmarshal(rec.Body.Bytes(), v); err != nil { t.Fatalf("unmarshal response body %q: %v", rec.Body.String(), err) } }