Files
Agent-System/internal/controlcenter/server/export_doc_test.go
T
weichen f79956c498 feat(control-center): P4 .doc importer, agent CLI, task doc export
- internal/controlcenter/importer: scan .doc/ops/{short-term,long-term}
  and .doc/backlog for task docs, upsert cc_tasks keyed by slug; maps doc
  status/stage, auto-creates the three plans, follows doc status only
  while a task is planned/in_progress (terminal statuses never regress),
  skips unchanged docs, and resolves cross-directory slug collisions by
  fixed directory precedence with a warning
- cmd/control-center: import-docs subcommand (also runs at serve startup
  and on the doc-sync ticker) plus the agent CLI: next / instruction /
  claim / heartbeat / release / event / artifact / advance-request /
  decision / report, thin net/http client, compact JSON output
- console API POST /api/v1/tasks/{id}/export-doc renders a task per
  .doc/ops/templates/short-term-task.md into .doc/ops/short-term/, refuses
  overwrite (409) and unsafe slugs, then backfills doc_path
- fix pre-existing TestAgentHasNoAdvanceRoute: SPA catch-all GET / makes
  the mux answer 405 for unmatched POST paths; accept 404 or 405
- archtest allowlist: controlcenter/importer -> pipeline, store
2026-09-17 11:57:47 +00:00

86 lines
2.9 KiB
Go

package server
import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"chat-agent-system/internal/controlcenter/config"
"chat-agent-system/internal/controlcenter/store"
)
func newExportTestServer(t *testing.T, repoRoot string) *httptest.Server {
t.Helper()
dsn := os.Getenv("TEST_CC_DB_DSN")
if dsn == "" {
t.Skip("TEST_CC_DB_DSN not set")
}
_, thisFile, _, _ := runtime.Caller(0)
migrationsDir := filepath.Join(filepath.Dir(thisFile), "..", "..", "..", "deploy", "control-center", "goose")
ctx := t.Context()
require.NoError(t, store.Migrate(ctx, dsn, migrationsDir))
st, err := store.Connect(ctx, dsn)
require.NoError(t, err)
t.Cleanup(st.Close)
srv := New(config.Config{ConsoleToken: testConsoleToken, RepoRoot: repoRoot}, st)
ts := httptest.NewServer(srv.Handler())
t.Cleanup(ts.Close)
return ts
}
func TestTaskExportDoc(t *testing.T) {
repoRoot := t.TempDir()
ts := newExportTestServer(t, repoRoot)
taskSlug := slug("export")
code, raw := doReq(t, "POST", ts.URL+"/api/v1/tasks", testConsoleToken, map[string]any{
"slug": taskSlug, "title": "导出任务", "instruction_md": "## 目标\n\n验证导出。\n",
})
require.Equal(t, http.StatusCreated, code, string(raw))
id := decodeBody(t, raw)["id"].(string)
code, raw = doReq(t, "POST", ts.URL+"/api/v1/tasks/"+id+"/export-doc", testConsoleToken, nil)
require.Equal(t, http.StatusCreated, code, string(raw))
docPath := decodeBody(t, raw)["doc_path"].(string)
today := time.Now().Format("2006-01-02")
assert.Equal(t, ".doc/ops/short-term/"+today+"-"+taskSlug+".md", docPath)
content, err := os.ReadFile(filepath.Join(repoRoot, filepath.FromSlash(docPath)))
require.NoError(t, err)
md := string(content)
assert.True(t, strings.HasPrefix(md, "---\n"), "front matter first")
assert.Contains(t, md, `title: "导出任务"`)
assert.Contains(t, md, "status: planned\n")
assert.Contains(t, md, "created: "+today+"\n")
assert.Contains(t, md, "# 导出任务")
assert.Contains(t, md, "## 目标")
// task doc_path updated
code, raw = doReq(t, "GET", ts.URL+"/api/v1/tasks/"+id, testConsoleToken, nil)
require.Equal(t, http.StatusOK, code)
assert.Equal(t, docPath, decodeBody(t, raw)["doc_path"])
// second export conflicts, file untouched
code, raw = doReq(t, "POST", ts.URL+"/api/v1/tasks/"+id+"/export-doc", testConsoleToken, nil)
assert.Equal(t, http.StatusConflict, code, string(raw))
assert.Contains(t, string(raw), "already exists")
// unsafe slug rejected
code, raw = doReq(t, "POST", ts.URL+"/api/v1/tasks", testConsoleToken, map[string]any{
"slug": slug("Bad_Slug"), "title": "不可导出",
})
require.Equal(t, http.StatusCreated, code, string(raw))
badID := decodeBody(t, raw)["id"].(string)
code, raw = doReq(t, "POST", ts.URL+"/api/v1/tasks/"+badID+"/export-doc", testConsoleToken, nil)
assert.Equal(t, http.StatusBadRequest, code, string(raw))
}