Issue 9 chat api (#25)
This commit is contained in:
218
server/handlers/chats_test.go
Normal file
218
server/handlers/chats_test.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gin.SetMode(gin.TestMode)
|
||||
}
|
||||
|
||||
// ── Chat Request Validation ─────────────────
|
||||
|
||||
func TestCreateChatMissingTitle(t *testing.T) {
|
||||
h := NewChatHandler()
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = httptest.NewRequest("POST", "/api/v1/chats",
|
||||
strings.NewReader(`{}`))
|
||||
c.Request.Header.Set("Content-Type", "application/json")
|
||||
|
||||
h.CreateChat(c)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected 400, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateChatTitleTooLong(t *testing.T) {
|
||||
h := NewChatHandler()
|
||||
|
||||
longTitle := strings.Repeat("x", 501)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = httptest.NewRequest("POST", "/api/v1/chats",
|
||||
strings.NewReader(`{"title":"`+longTitle+`"}`))
|
||||
c.Request.Header.Set("Content-Type", "application/json")
|
||||
|
||||
h.CreateChat(c)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected 400 for title > 500 chars, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateChatEmptyBody(t *testing.T) {
|
||||
h := NewChatHandler()
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Set("user_id", "test-user-id")
|
||||
c.Params = gin.Params{{Key: "id", Value: "test-chat-id"}}
|
||||
c.Request = httptest.NewRequest("PUT", "/api/v1/chats/test-chat-id",
|
||||
strings.NewReader(`{}`))
|
||||
c.Request.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Without a DB connection, UpdateChat will fail at ownership check.
|
||||
// Integration tests with a real DB would validate the "no fields" path.
|
||||
// Here we just confirm it doesn't return 400 for valid JSON.
|
||||
h.UpdateChat(c)
|
||||
|
||||
if w.Code == http.StatusBadRequest {
|
||||
t.Error("Empty JSON body should not be a parse error")
|
||||
}
|
||||
}
|
||||
|
||||
// ── Message Request Validation ──────────────
|
||||
|
||||
func TestCreateMessageMissingRole(t *testing.T) {
|
||||
h := NewMessageHandler()
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Params = gin.Params{{Key: "id", Value: "test-chat"}}
|
||||
c.Request = httptest.NewRequest("POST", "/api/v1/chats/test-chat/messages",
|
||||
strings.NewReader(`{"content":"hello"}`))
|
||||
c.Request.Header.Set("Content-Type", "application/json")
|
||||
|
||||
h.CreateMessage(c)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected 400 for missing role, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateMessageInvalidRole(t *testing.T) {
|
||||
h := NewMessageHandler()
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Params = gin.Params{{Key: "id", Value: "test-chat"}}
|
||||
c.Request = httptest.NewRequest("POST", "/api/v1/chats/test-chat/messages",
|
||||
strings.NewReader(`{"role":"invalid","content":"hello"}`))
|
||||
c.Request.Header.Set("Content-Type", "application/json")
|
||||
|
||||
h.CreateMessage(c)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected 400 for invalid role, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateMessageMissingContent(t *testing.T) {
|
||||
h := NewMessageHandler()
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Params = gin.Params{{Key: "id", Value: "test-chat"}}
|
||||
c.Request = httptest.NewRequest("POST", "/api/v1/chats/test-chat/messages",
|
||||
strings.NewReader(`{"role":"user"}`))
|
||||
c.Request.Header.Set("Content-Type", "application/json")
|
||||
|
||||
h.CreateMessage(c)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("Expected 400 for missing content, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateMessageValidRoles(t *testing.T) {
|
||||
// Valid roles should pass validation (not return 400).
|
||||
// They'll fail at ownership check (no DB), which is expected.
|
||||
t.Skip("requires database connection for ownership check")
|
||||
}
|
||||
|
||||
// ── Regenerate Stub ─────────────────────────
|
||||
|
||||
func TestRegenerateReturns501(t *testing.T) {
|
||||
h := NewMessageHandler()
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = httptest.NewRequest("POST", "/api/v1/chats/x/regenerate", nil)
|
||||
|
||||
h.Regenerate(c)
|
||||
|
||||
if w.Code != http.StatusNotImplemented {
|
||||
t.Errorf("Expected 501, got %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// ── Pagination Helpers ──────────────────────
|
||||
|
||||
func TestParsePaginationDefaults(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = httptest.NewRequest("GET", "/api/v1/chats", nil)
|
||||
|
||||
page, perPage, offset := parsePagination(c)
|
||||
|
||||
if page != 1 {
|
||||
t.Errorf("Default page should be 1, got %d", page)
|
||||
}
|
||||
if perPage != 50 {
|
||||
t.Errorf("Default per_page should be 50, got %d", perPage)
|
||||
}
|
||||
if offset != 0 {
|
||||
t.Errorf("Default offset should be 0, got %d", offset)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePaginationCustom(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = httptest.NewRequest("GET", "/api/v1/chats?page=3&per_page=10", nil)
|
||||
|
||||
page, perPage, offset := parsePagination(c)
|
||||
|
||||
if page != 3 {
|
||||
t.Errorf("Page should be 3, got %d", page)
|
||||
}
|
||||
if perPage != 10 {
|
||||
t.Errorf("Per page should be 10, got %d", perPage)
|
||||
}
|
||||
if offset != 20 {
|
||||
t.Errorf("Offset should be 20, got %d", offset)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePaginationClampMax(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = httptest.NewRequest("GET", "/api/v1/chats?per_page=500", nil)
|
||||
|
||||
_, perPage, _ := parsePagination(c)
|
||||
|
||||
if perPage != 100 {
|
||||
t.Errorf("Per page should be clamped to 100, got %d", perPage)
|
||||
}
|
||||
}
|
||||
|
||||
// ── getUserID ───────────────────────────────
|
||||
|
||||
func TestGetUserID(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Set("user_id", "abc-123")
|
||||
|
||||
uid := getUserID(c)
|
||||
if uid != "abc-123" {
|
||||
t.Errorf("Expected abc-123, got %s", uid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUserIDMissing(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
|
||||
uid := getUserID(c)
|
||||
if uid != "" {
|
||||
t.Errorf("Expected empty string, got %s", uid)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user