package main import ( "bytes" "encoding/json" "io/fs" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "kb-editor/internal/store" ) func TestBulkAllMatchingUsesJSONFilterNames(t *testing.T) { dir := t.TempDir() backup := filepath.Join(t.TempDir(), "backups") t.Setenv("BACKUP_DIR", backup) write := func(name string, auto bool) { t.Helper() b, _ := json.Marshal(map[string]any{"id": name, "title": name, "auto_reply": auto, "language": "de-DE"}) if err := os.WriteFile(filepath.Join(dir, name+".json"), b, 0o644); err != nil { t.Fatal(err) } } write("true-one", true) write("false-one", false) s, err := store.New(dir) if err != nil { t.Fatal(err) } web, err := fs.Sub(webFS, "web") if err != nil { t.Fatal(err) } h := newApp(s, web).routes() body := []byte(`{"keys":[],"all_matching":true,"query":{"auto_reply":"false"},"patch":{"set_language":"en-US"},"dry_run":true}`) req := httptest.NewRequest(http.MethodPost, "/api/bulk", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") rr := httptest.NewRecorder() h.ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Fatalf("status=%d body=%s", rr.Code, rr.Body.String()) } var result store.BulkResult if err := json.Unmarshal(rr.Body.Bytes(), &result); err != nil { t.Fatal(err) } if result.Targeted != 1 || result.Changed != 1 { t.Fatalf("unexpected result: %+v", result) } } func TestGoogleModeBlocksWrites(t *testing.T) { dir := t.TempDir() b, _ := json.Marshal(map[string]any{"id": "KB-1", "title": "Test", "answer": "Lösung"}) if err := os.WriteFile(filepath.Join(dir, "one.json"), b, 0o644); err != nil { t.Fatal(err) } s, err := store.New(dir) if err != nil { t.Fatal(err) } web, err := fs.Sub(webFS, "viewer") if err != nil { t.Fatal(err) } h := newApp(s, web, appConfig{Mode: "google", Title: "Helpdesk", Writable: false}).routes() item := s.List(store.Query{Page: 1, PageSize: 10}).Items[0] req := httptest.NewRequest(http.MethodPut, "/api/items/"+item.Key, bytes.NewBufferString(`{"title":"changed"}`)) req.Header.Set("Content-Type", "application/json") rr := httptest.NewRecorder() h.ServeHTTP(rr, req) if rr.Code != http.StatusForbidden { t.Fatalf("status=%d body=%s", rr.Code, rr.Body.String()) } doc, _, err := s.Get(item.Key) if err != nil { t.Fatal(err) } if doc["title"] != "Test" { t.Fatalf("document changed in google mode: %+v", doc) } } func TestSearchEndpointReturnsRankedHits(t *testing.T) { dir := t.TempDir() write := func(name string, doc map[string]any) { t.Helper() b, _ := json.Marshal(doc) if err := os.WriteFile(filepath.Join(dir, name+".json"), b, 0o644); err != nil { t.Fatal(err) } } write("exact", map[string]any{"id": "0x80070005", "title": "Zugriff verweigert", "text": "Berechtigungen prüfen"}) write("mention", map[string]any{"id": "KB-2", "title": "Allgemeiner Windows-Fehler", "answer": "Kann 0x80070005 enthalten"}) s, err := store.New(dir) if err != nil { t.Fatal(err) } web, err := fs.Sub(webFS, "viewer") if err != nil { t.Fatal(err) } h := newApp(s, web, appConfig{Mode: "google", Title: "Helpdesk", Writable: false}).routes() req := httptest.NewRequest(http.MethodGet, "/api/search?q=0x80070005&page=1&page_size=20", nil) rr := httptest.NewRecorder() h.ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Fatalf("status=%d body=%s", rr.Code, rr.Body.String()) } var result store.SearchResult if err := json.Unmarshal(rr.Body.Bytes(), &result); err != nil { t.Fatal(err) } if result.Total != 2 || len(result.Items) != 2 { t.Fatalf("unexpected result: %+v", result) } if result.Items[0].ID != "0x80070005" { t.Fatalf("exact ID should rank first: %+v", result.Items) } }