@@ -1,8 +1,21 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/example/glpi-ai-agent/internal/config"
|
||||
"github.com/example/glpi-ai-agent/internal/knowledge"
|
||||
"github.com/example/glpi-ai-agent/internal/metrics"
|
||||
"github.com/example/glpi-ai-agent/internal/model"
|
||||
"github.com/example/glpi-ai-agent/internal/queue"
|
||||
)
|
||||
|
||||
func TestExtractTicketID(t *testing.T) {
|
||||
@@ -33,3 +46,128 @@ func TestDashboardTemplateParses(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeFeedback struct{ cats []model.Category }
|
||||
|
||||
func (f fakeFeedback) Categories(context.Context) ([]model.Category, error) { return f.cats, nil }
|
||||
func (f fakeFeedback) RecordCategoryFeedback(context.Context, string, int64) (model.LearningExample, error) {
|
||||
return model.LearningExample{}, nil
|
||||
}
|
||||
func (f fakeFeedback) LearningExamples() []model.LearningExample { return nil }
|
||||
func (f fakeFeedback) DeleteLearning(string) error { return os.ErrNotExist }
|
||||
func (f fakeFeedback) LearningCount() int { return 0 }
|
||||
|
||||
func newKnowledgeTestServer(t *testing.T) (http.Handler, *knowledge.Store) {
|
||||
t.Helper()
|
||||
root := t.TempDir()
|
||||
staticDir := filepath.Join(root, "knowledge")
|
||||
dataDir := filepath.Join(root, "data")
|
||||
if err := os.MkdirAll(staticDir, 0o750); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
store, err := knowledge.Load(context.Background(), staticDir, dataDir, nil, false, []string{"internal-kb"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg := config.Config{WebAllowAnonymous: true, KnowledgeWebEditEnabled: true, CommunicationLanguage: "de-DE", CommunicationStyle: "formal", KnowledgeAllowedSources: []string{"internal-kb"}}
|
||||
srv, err := New(cfg, metrics.New(), nil, queue.New(8), store, fakeFeedback{cats: []model.Category{{ID: 2, Name: "Active Directory", CompleteName: "IT > Active Directory"}}})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return srv.Handler(), store
|
||||
}
|
||||
|
||||
func mutationRequest(t *testing.T, h http.Handler, method, path string, body any) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
var b bytes.Buffer
|
||||
if body != nil {
|
||||
if err := json.NewEncoder(&b).Encode(body); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
req := httptest.NewRequest(method, path, &b)
|
||||
req.Header.Set("X-Requested-With", "GLPI-AI-Agent")
|
||||
if body != nil {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
}
|
||||
rr := httptest.NewRecorder()
|
||||
h.ServeHTTP(rr, req)
|
||||
return rr
|
||||
}
|
||||
|
||||
func TestKnowledgeCreateUpdateDeleteFlow(t *testing.T) {
|
||||
h, store := newKnowledgeTestServer(t)
|
||||
doc := model.KnowledgeDoc{ID: "KB-TEST-1", Title: "Benutzerkonto gesperrt", Text: "Konto ist gesperrt.", Answer: "Bitte versuchen Sie die Anmeldung erneut.", Source: "internal-kb", Language: "de-DE", CommunicationStyle: "formal", MinScore: .7, Categories: []int64{2}}
|
||||
if rr := mutationRequest(t, h, http.MethodPost, "/api/knowledge", doc); rr.Code != http.StatusCreated {
|
||||
t.Fatalf("create = %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
if _, ok := store.ByID(doc.ID); !ok {
|
||||
t.Fatal("created document missing")
|
||||
}
|
||||
if rr := mutationRequest(t, h, http.MethodPost, "/api/knowledge", doc); rr.Code != http.StatusConflict {
|
||||
t.Fatalf("duplicate create = %d, want 409", rr.Code)
|
||||
}
|
||||
|
||||
doc.Title = "Benutzerkonto dauerhaft gesperrt"
|
||||
if rr := mutationRequest(t, h, http.MethodPut, "/api/knowledge/KB-TEST-1", doc); rr.Code != http.StatusOK {
|
||||
t.Fatalf("update = %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
got, ok := store.ByID(doc.ID)
|
||||
if !ok || got.Title != doc.Title {
|
||||
t.Fatalf("updated doc = %#v, ok=%v", got, ok)
|
||||
}
|
||||
|
||||
renamed := doc
|
||||
renamed.ID = "KB-RENAMED"
|
||||
if rr := mutationRequest(t, h, http.MethodPut, "/api/knowledge/KB-TEST-1", renamed); rr.Code != http.StatusConflict {
|
||||
t.Fatalf("rename update = %d, want 409", rr.Code)
|
||||
}
|
||||
if _, ok := store.ByID("KB-RENAMED"); ok {
|
||||
t.Fatal("rename unexpectedly created a second document")
|
||||
}
|
||||
|
||||
if rr := mutationRequest(t, h, http.MethodDelete, "/api/knowledge/KB-TEST-1", nil); rr.Code != http.StatusNoContent {
|
||||
t.Fatalf("delete = %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
if _, ok := store.ByID(doc.ID); ok {
|
||||
t.Fatal("deleted document still present")
|
||||
}
|
||||
}
|
||||
|
||||
func TestKnowledgeGetReturnsManagedState(t *testing.T) {
|
||||
h, _ := newKnowledgeTestServer(t)
|
||||
doc := model.KnowledgeDoc{ID: "KB-TEST-2", Title: "VPN", Text: "VPN Hilfe", Source: "internal-kb", Language: "de-DE", CommunicationStyle: "formal", MinScore: .7}
|
||||
if rr := mutationRequest(t, h, http.MethodPost, "/api/knowledge", doc); rr.Code != http.StatusCreated {
|
||||
t.Fatalf("create = %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
rr := httptest.NewRecorder()
|
||||
h.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/api/knowledge/KB-TEST-2", nil))
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("get = %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
var got struct {
|
||||
Managed bool `json:"managed"`
|
||||
Document model.KnowledgeDoc `json:"document"`
|
||||
}
|
||||
if err := json.Unmarshal(rr.Body.Bytes(), &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !got.Managed || got.Document.ID != doc.ID {
|
||||
t.Fatalf("unexpected get response: %#v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDashboardContainsControlCenterSections(t *testing.T) {
|
||||
h, _ := newKnowledgeTestServer(t)
|
||||
rr := httptest.NewRecorder()
|
||||
h.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/", nil))
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("dashboard = %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
body := rr.Body.String()
|
||||
for _, want := range []string{"Control Center", "Verarbeitungen", "Knowledge Base", "Effektive Konfiguration", "Knowledge-Ranking"} {
|
||||
if !bytes.Contains([]byte(body), []byte(want)) {
|
||||
t.Fatalf("dashboard missing %q", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user