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) } 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 }