package handlers import ( "encoding/json" "net/http" "testing" "github.com/gin-gonic/gin" "armature/config" "armature/database" "armature/middleware" "armature/store" postgres "armature/store/postgres" sqlite "armature/store/sqlite" ) // ── Presence/Resolve Test Harness ────────────── type presenceHarness struct { *testHarness stores store.Stores userToken string userID string } func setupPresenceHarness(t *testing.T) *presenceHarness { t.Helper() database.RequireTestDB(t) database.TruncateAll(t) cfg := &config.Config{ JWTSecret: testJWTSecret, BasePath: "", } var stores store.Stores if database.IsSQLite() { stores = sqlite.NewStores(database.TestDB) } else { stores = postgres.NewStores(database.TestDB) } userCache := middleware.NewUserStatusCache() r := gin.New() api := r.Group("/api/v1") protected := api.Group("") protected.Use(middleware.Auth(cfg, stores.Users, userCache)) presence := NewPresenceHandler(stores) protected.GET("/users/resolve", presence.ResolveUsers) protected.GET("/users/search", presence.SearchUsers) // Seed a caller user userID := database.SeedTestUser(t, "caller", "caller@test.com") database.TestDB.Exec(dialectSQL("UPDATE users SET is_active = true WHERE id = $1"), userID) userToken := makeToken(userID, "caller@test.com", "user") return &presenceHarness{ testHarness: &testHarness{router: r, t: t}, stores: stores, userToken: userToken, userID: userID, } } // ── Tests ────────────────────────────────────── func TestResolveUsers_SingleID(t *testing.T) { h := setupPresenceHarness(t) // Seed a user with display_name targetID := database.SeedTestUser(t, "alice", "alice@test.com") database.TestDB.Exec(dialectSQL("UPDATE users SET is_active = true, display_name = $1 WHERE id = $2"), "Alice Smith", targetID) w := h.request("GET", "/api/v1/users/resolve?ids="+targetID, h.userToken, nil) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) } var resp struct { Data map[string]store.UserSearchResult `json:"data"` } json.NewDecoder(w.Body).Decode(&resp) u, ok := resp.Data[targetID] if !ok { t.Fatalf("expected user %s in response, got %v", targetID, resp.Data) } if u.Username != "alice" { t.Errorf("expected username 'alice', got %q", u.Username) } if u.DisplayName != "Alice Smith" { t.Errorf("expected display_name 'Alice Smith', got %q", u.DisplayName) } } func TestResolveUsers_MultipleIDs(t *testing.T) { h := setupPresenceHarness(t) id1 := database.SeedTestUser(t, "bob", "bob@test.com") id2 := database.SeedTestUser(t, "carol", "carol@test.com") database.TestDB.Exec(dialectSQL("UPDATE users SET is_active = true WHERE id = $1"), id1) database.TestDB.Exec(dialectSQL("UPDATE users SET is_active = true, display_name = $1 WHERE id = $2"), "Carol D", id2) w := h.request("GET", "/api/v1/users/resolve?ids="+id1+","+id2, h.userToken, nil) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } var resp struct { Data map[string]store.UserSearchResult `json:"data"` } json.NewDecoder(w.Body).Decode(&resp) if len(resp.Data) != 2 { t.Fatalf("expected 2 users, got %d", len(resp.Data)) } if resp.Data[id1].Username != "bob" { t.Errorf("expected bob, got %q", resp.Data[id1].Username) } if resp.Data[id2].DisplayName != "Carol D" { t.Errorf("expected 'Carol D', got %q", resp.Data[id2].DisplayName) } } func TestResolveUsers_MissingID(t *testing.T) { h := setupPresenceHarness(t) w := h.request("GET", "/api/v1/users/resolve?ids=00000000-0000-0000-0000-000000000099", h.userToken, nil) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } var resp struct { Data map[string]store.UserSearchResult `json:"data"` } json.NewDecoder(w.Body).Decode(&resp) if len(resp.Data) != 0 { t.Errorf("expected empty map for missing ID, got %d entries", len(resp.Data)) } } func TestResolveUsers_EmptyParam(t *testing.T) { h := setupPresenceHarness(t) w := h.request("GET", "/api/v1/users/resolve?ids=", h.userToken, nil) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } var resp struct { Data map[string]interface{} `json:"data"` } json.NewDecoder(w.Body).Decode(&resp) if len(resp.Data) != 0 { t.Errorf("expected empty map, got %d entries", len(resp.Data)) } } func TestResolveUsers_NoParam(t *testing.T) { h := setupPresenceHarness(t) w := h.request("GET", "/api/v1/users/resolve", h.userToken, nil) if w.Code != http.StatusOK { t.Fatalf("expected 200, got %d", w.Code) } var resp struct { Data map[string]interface{} `json:"data"` } json.NewDecoder(w.Body).Decode(&resp) if len(resp.Data) != 0 { t.Errorf("expected empty map, got %d entries", len(resp.Data)) } }