mirror of
https://github.com/BaaRai/ARTEX.git
synced 2026-11-15 04:30:55 +08:00
New restores every unfinished task in the shared database and runs its planner, worker and deadline loops on the server context. Tests that passed context.Background() never stopped or joined them, so they kept writing under the manager TempDir after the test returned and the TempDir cleanup failed with directory not empty. Add stopTestServer, which cancels the context, waits for each task to go quiescent, joins its loops, the archive worker and the side-question writer, and defer it right after New in every test that started a live server.
118 lines
3.7 KiB
Go
118 lines
3.7 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestTaskMetadataPatchReturnsRenameAndPin(t *testing.T) {
|
|
m, err := NewManager(t.TempDir(), "")
|
|
if err != nil {
|
|
t.Skipf("postgres unavailable (%v) — skipping", err)
|
|
}
|
|
defer m.Close()
|
|
task, err := m.CreateTask("metadata patch", "goal", nil, 0, 0)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
taskID, _ := strconv.ParseInt(task.ID, 10, 64)
|
|
defer func() { _ = m.pg.DeleteTask(taskID) }()
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
s := New(ctx, m, t.TempDir(), t.TempDir(), t.TempDir())
|
|
defer stopTestServer(t, s, cancel)
|
|
token, err := signJWT(s.jwtKey)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
body, _ := json.Marshal(map[string]any{"name": " renamed task ", "pinned": true})
|
|
req := httptest.NewRequest(http.MethodPatch, "/api/tasks/"+task.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 {
|
|
Name string `json:"name"`
|
|
Pinned bool `json:"pinned"`
|
|
PinnedAt string `json:"pinned_at"`
|
|
}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &updated); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if updated.Name != "renamed task" || !updated.Pinned || updated.PinnedAt == "" {
|
|
t.Fatalf("unexpected task patch response: %+v", updated)
|
|
}
|
|
|
|
body, _ = json.Marshal(map[string]any{"name": strings.Repeat("x", maxTaskNameRunes+1)})
|
|
req = httptest.NewRequest(http.MethodPatch, "/api/tasks/"+task.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 task name status=%d body=%s", rec.Code, rec.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestConversationBatchDeleteReportsMissing(t *testing.T) {
|
|
m, err := NewManager(t.TempDir(), "")
|
|
if err != nil {
|
|
t.Skipf("postgres unavailable (%v) — skipping", err)
|
|
}
|
|
defer m.Close()
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
s := New(ctx, m, t.TempDir(), t.TempDir(), t.TempDir())
|
|
defer stopTestServer(t, s, cancel)
|
|
first, err := m.pg.CreateConversation("mainagent", "batch-http-first", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
second, err := m.pg.CreateConversation("mainagent", "batch-http-second", nil)
|
|
if err != nil {
|
|
_ = m.pg.DeleteConversation(first.ID)
|
|
t.Fatal(err)
|
|
}
|
|
defer func() {
|
|
_ = m.pg.DeleteConversation(first.ID)
|
|
_ = m.pg.DeleteConversation(second.ID)
|
|
}()
|
|
token, err := signJWT(s.jwtKey)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
missing := int64(1<<62 - 1)
|
|
body, _ := json.Marshal(map[string]any{"ids": []int64{first.ID, missing, second.ID}})
|
|
req := httptest.NewRequest(http.MethodPost, "/api/conversations/delete/batch", bytes.NewReader(body))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
rec := httptest.NewRecorder()
|
|
s.Handler().ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("batch delete status=%d body=%s", rec.Code, rec.Body.String())
|
|
}
|
|
var response struct {
|
|
Items []conversationDeleteItem `json:"items"`
|
|
}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &response); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(response.Items) != 3 || !response.Items[0].OK || response.Items[1].OK || !response.Items[2].OK {
|
|
t.Fatalf("batch delete response=%+v", response.Items)
|
|
}
|
|
for _, id := range []int64{first.ID, second.ID} {
|
|
if conversation, err := m.pg.GetConversation(id); err != nil || conversation != nil {
|
|
t.Fatalf("conversation %d still exists: %+v err=%v", id, conversation, err)
|
|
}
|
|
}
|
|
if response.Items[1].Error == "" {
|
|
t.Fatalf("missing conversation %s must include an error", fmt.Sprint(missing))
|
|
}
|
|
}
|