Files
Agent-System-Backend/internal/server/ext9_upload_switch_test.go
T
weichen 4d1ca60067 Expose role and system permission APIs
Why: System, role, and project entry permissions need explicit actions instead of a single administrator flag or unrestricted project creation.

Evidence: The full Backend test suite passed, including role APIs, action isolation, project.create denial/allow, storage migration coverage, and account write fences.

Impact: Adds versioned role and grant endpoints, maps account actions to explicit permissions, and requires project.create authority.

Refs: Focused role and permission system task 3
2026-10-14 17:02:11 +00:00

104 lines
3.3 KiB
Go

package server
import (
"bytes"
"encoding/json"
"fmt"
"mime/multipart"
"net/http"
"net/http/httptest"
"testing"
)
// EXT-9 验收:DisableUploadIndexing=true 时上传不再自动进检索(原件与摄取卡
// 行为不变);=false 恢复现状(可解析文本入索引)。
func TestUploadPreIndexSwitch(t *testing.T) {
srv, st := newAuthTestServer(t)
h := srv.Handler()
alice, err := createLegacyAPIKeyFixture(t, st, "alice", "e2e")
if err != nil {
t.Fatal(err)
}
grantProjectCreateFixture(t, st, "alice")
req := httptest.NewRequest(http.MethodPost, "/api/projects", bytes.NewReader(mustJSON(t, map[string]string{"name": "EXT9"})))
req.Header.Set("Authorization", "Bearer "+alice)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("create project: %d %s", rec.Code, rec.Body.String())
}
var pj map[string]any
json.Unmarshal(rec.Body.Bytes(), &pj)
pid := fmt.Sprint(pj["id"])
upload := func(name, text string) string {
var buf bytes.Buffer
mw := multipart.NewWriter(&buf)
fw, _ := mw.CreateFormFile("file", name)
fw.Write([]byte(text))
mw.Close()
req := httptest.NewRequest(http.MethodPost, "/api/projects/"+pid+"/uploads", &buf)
req.Header.Set("Authorization", "Bearer "+alice)
req.Header.Set("Content-Type", mw.FormDataContentType())
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("upload %s: %d %s", name, rec.Code, rec.Body.String())
}
var up map[string]any
json.Unmarshal(rec.Body.Bytes(), &up)
return fmt.Sprint(up["artifactId"])
}
search := func(q string) int {
req := httptest.NewRequest(http.MethodGet, "/api/knowledge/search?q="+q, nil)
req.Header.Set("Authorization", "Bearer "+alice)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("search: %d %s", rec.Code, rec.Body.String())
}
var arr []any
if err := json.Unmarshal(rec.Body.Bytes(), &arr); err == nil {
return len(arr) // 直接数组形态
}
var out struct {
Hits []any `json:"hits"`
}
if err := json.Unmarshal(rec.Body.Bytes(), &out); err != nil {
t.Fatalf("search decode: %v (%s)", err, rec.Body.String())
}
return len(out.Hits)
}
// 开关开:上传不入检索,但原件完整可取回。
srv.DisableUploadIndexing = true
aid := upload("ext9-off.txt", "EXT9OFF 索引开关独占词甲")
if n := search("索引开关独占词甲"); n != 0 {
t.Fatalf("switch on: search hits=%d, want 0(存疑确认前不入正式检索)", n)
}
reqC := httptest.NewRequest(http.MethodGet, "/api/artifacts/"+aid+"/content", nil)
reqC.Header.Set("Authorization", "Bearer "+alice)
recC := httptest.NewRecorder()
h.ServeHTTP(recC, reqC)
if recC.Code != http.StatusOK || !bytes.Contains(recC.Body.Bytes(), []byte("索引开关独占词甲")) {
t.Fatalf("original must remain retrievable: %d %q", recC.Code, recC.Body.String())
}
// 开关关(现状):同一上传路径恢复自动索引。
srv.DisableUploadIndexing = false
upload("ext9-on.txt", "EXT9ON 索引开关独占词乙")
if n := search("索引开关独占词乙"); n != 1 {
t.Fatalf("switch off: search hits=%d, want 1(现状自动索引)", n)
}
}
func mustJSON(t *testing.T, v any) []byte {
t.Helper()
b, err := json.Marshal(v)
if err != nil {
t.Fatal(err)
}
return b
}