First Commit
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Autumn-27/artex/db"
|
||||
)
|
||||
|
||||
func TestTaskTemplateHTTPCRUD(t *testing.T) {
|
||||
m, err := NewManager(t.TempDir(), "")
|
||||
if err != nil {
|
||||
t.Skipf("postgres unavailable (%v) — skipping", err)
|
||||
}
|
||||
defer m.Close()
|
||||
s := New(context.Background(), m, t.TempDir(), t.TempDir(), t.TempDir())
|
||||
h := s.Handler()
|
||||
token, err := signJWT(s.jwtKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
do := func(method, path string, body any) (int, map[string]any) {
|
||||
var data []byte
|
||||
if body != nil {
|
||||
data, _ = json.Marshal(body)
|
||||
}
|
||||
req := httptest.NewRequest(method, path, bytes.NewReader(data))
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, req)
|
||||
var out map[string]any
|
||||
_ = json.Unmarshal(rec.Body.Bytes(), &out)
|
||||
return rec.Code, out
|
||||
}
|
||||
|
||||
name := fmt.Sprintf("http-template-%d", time.Now().UnixNano())
|
||||
code, created := do(http.MethodPost, "/api/task-templates", map[string]any{
|
||||
"name": name, "description": "description", "goal": "goal",
|
||||
})
|
||||
if code != http.StatusCreated {
|
||||
t.Fatalf("create status=%d body=%v", code, created)
|
||||
}
|
||||
id := int64(created["id"].(float64))
|
||||
t.Cleanup(func() { _, _ = m.pg.DeleteTaskTemplate(id) })
|
||||
|
||||
code, duplicate := do(http.MethodPost, "/api/task-templates", map[string]any{
|
||||
"name": " " + name + " ", "description": "other", "goal": "other",
|
||||
})
|
||||
if code != http.StatusConflict {
|
||||
t.Fatalf("duplicate status=%d body=%v", code, duplicate)
|
||||
}
|
||||
|
||||
code, updated := do(http.MethodPatch, fmt.Sprintf("/api/task-templates/%d", id), map[string]any{"goal": "patched goal"})
|
||||
if code != http.StatusOK || updated["goal"] != "patched goal" || updated["description"] != "description" {
|
||||
t.Fatalf("patch status=%d body=%v", code, updated)
|
||||
}
|
||||
code, _ = do(http.MethodPatch, fmt.Sprintf("/api/task-templates/%d", id), map[string]any{
|
||||
"goal": strings.Repeat("界", db.MaxTaskTemplateTextRunes+1),
|
||||
})
|
||||
if code != http.StatusBadRequest {
|
||||
t.Fatalf("overlong patch status=%d, want %d", code, http.StatusBadRequest)
|
||||
}
|
||||
code, _ = do(http.MethodPost, "/api/task-templates", map[string]any{
|
||||
"name": "oversized", "description": strings.Repeat("x", maxTaskTemplateRequestBytes+1), "goal": "goal",
|
||||
})
|
||||
if code != http.StatusRequestEntityTooLarge {
|
||||
t.Fatalf("oversized create status=%d, want %d", code, http.StatusRequestEntityTooLarge)
|
||||
}
|
||||
code, listed := do(http.MethodGet, "/api/task-templates", nil)
|
||||
if code != http.StatusOK || listed["templates"] == nil {
|
||||
t.Fatalf("list status=%d body=%v", code, listed)
|
||||
}
|
||||
code, deleted := do(http.MethodDelete, fmt.Sprintf("/api/task-templates/%d", id), nil)
|
||||
if code != http.StatusOK || int64(deleted["deleted"].(float64)) != id {
|
||||
t.Fatalf("delete status=%d body=%v", code, deleted)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConversationPatchReturnsPinState(t *testing.T) {
|
||||
m, err := NewManager(t.TempDir(), "")
|
||||
if err != nil {
|
||||
t.Skipf("postgres unavailable (%v) — skipping", err)
|
||||
}
|
||||
defer m.Close()
|
||||
s := New(context.Background(), m, t.TempDir(), t.TempDir(), t.TempDir())
|
||||
conversation, err := m.pg.CreateConversation("mainagent", "pin through http", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = m.pg.DeleteConversation(conversation.ID) })
|
||||
token, err := signJWT(s.jwtKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
body, _ := json.Marshal(map[string]any{"title": " pinned title ", "pinned": true})
|
||||
req := httptest.NewRequest(http.MethodPatch, fmt.Sprintf("/api/conversations/%d", conversation.ID), bytes.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rec := httptest.NewRecorder()
|
||||
s.Handler().ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("patch status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var updated struct {
|
||||
Title string `json:"title"`
|
||||
Pinned bool `json:"pinned"`
|
||||
PinnedAt *string `json:"pinned_at"`
|
||||
}
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &updated); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if updated.Title != "pinned title" || !updated.Pinned || updated.PinnedAt == nil {
|
||||
t.Fatalf("unexpected conversation patch response: %+v", updated)
|
||||
}
|
||||
|
||||
body, _ = json.Marshal(map[string]any{"title": strings.Repeat("会", maxConversationTitleRunes+1)})
|
||||
req = httptest.NewRequest(http.MethodPatch, fmt.Sprintf("/api/conversations/%d", conversation.ID), bytes.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rec = httptest.NewRecorder()
|
||||
s.Handler().ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Fatalf("overlong conversation title status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
body, _ = json.Marshal(map[string]any{"title": strings.Repeat("x", maxConversationRequestBytes+1)})
|
||||
req = httptest.NewRequest(http.MethodPatch, fmt.Sprintf("/api/conversations/%d", conversation.ID), bytes.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rec = httptest.NewRecorder()
|
||||
s.Handler().ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusRequestEntityTooLarge {
|
||||
t.Fatalf("oversized conversation patch status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
body, _ = json.Marshal(map[string]any{
|
||||
"agent_key": "mainagent", "title": strings.Repeat("会", maxConversationTitleRunes+1),
|
||||
})
|
||||
req = httptest.NewRequest(http.MethodPost, "/api/conversations", bytes.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rec = httptest.NewRecorder()
|
||||
s.Handler().ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Fatalf("overlong conversation create status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
body, _ = json.Marshal(map[string]any{
|
||||
"agent_key": "mainagent", "title": strings.Repeat("x", maxConversationRequestBytes+1),
|
||||
})
|
||||
req = httptest.NewRequest(http.MethodPost, "/api/conversations", bytes.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rec = httptest.NewRecorder()
|
||||
s.Handler().ServeHTTP(rec, req)
|
||||
if rec.Code != http.StatusRequestEntityTooLarge {
|
||||
t.Fatalf("oversized conversation create status=%d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user