212 lines
5.9 KiB
Go
212 lines
5.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func init() {
|
|
gin.SetMode(gin.TestMode)
|
|
}
|
|
|
|
// ── Channel Request Validation ─────────────────
|
|
|
|
func TestCreateChannelMissingTitle(t *testing.T) {
|
|
h := NewChannelHandler()
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("POST", "/api/v1/channels",
|
|
strings.NewReader(`{}`))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
h.CreateChannel(c)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("Expected 400, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestCreateChannelTitleTooLong(t *testing.T) {
|
|
h := NewChannelHandler()
|
|
|
|
longTitle := strings.Repeat("x", 501)
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("POST", "/api/v1/channels",
|
|
strings.NewReader(`{"title":"`+longTitle+`"}`))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
h.CreateChannel(c)
|
|
|
|
if w.Code != http.StatusBadRequest {
|
|
t.Errorf("Expected 400 for title > 500 chars, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestUpdateChannelEmptyBody(t *testing.T) {
|
|
h := NewChannelHandler()
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Set("user_id", "test-user-id")
|
|
c.Params = gin.Params{{Key: "id", Value: "test-channel-id"}}
|
|
c.Request = httptest.NewRequest("PUT", "/api/v1/channels/test-channel-id",
|
|
strings.NewReader(`{}`))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
// Without a DB connection, UpdateChannel 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.UpdateChannel(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-channel"}}
|
|
c.Request = httptest.NewRequest("POST", "/api/v1/channels/test-channel/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-channel"}}
|
|
c.Request = httptest.NewRequest("POST", "/api/v1/channels/test-channel/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-channel"}}
|
|
c.Request = httptest.NewRequest("POST", "/api/v1/channels/test-channel/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 ───────────────────────────────
|
|
|
|
func TestRegenerateRequiresDB(t *testing.T) {
|
|
// Regenerate is now a full handler (creates sibling assistant message
|
|
// via tree-aware streaming). It calls userOwnsChannel → database.DB,
|
|
// so it cannot run without a live database connection.
|
|
t.Skip("requires database connection for ownership check")
|
|
}
|
|
|
|
// ── Pagination Helpers ──────────────────────
|
|
|
|
func TestParsePaginationDefaults(t *testing.T) {
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("GET", "/api/v1/channels", 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/channels?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/channels?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)
|
|
}
|
|
}
|