110 lines
4.4 KiB
Go
110 lines
4.4 KiB
Go
package engine
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/local/glpi-neural-brain/internal/config"
|
|
"github.com/local/glpi-neural-brain/internal/model"
|
|
)
|
|
|
|
func TestLoadResearchEvidenceValidatesPortableRecord(t *testing.T) {
|
|
root := t.TempDir()
|
|
result := model.ResearchResult{
|
|
Title: "Audit logging documentation", URL: "https://docs.example.test/audit", Content: "Ausführlicher und fachlich relevanter Volltext für die spätere Wiederverwendung.",
|
|
Fetched: true, Relevant: true, Relevance: .91, SourceQualityScore: .88,
|
|
}
|
|
hash := sha256.Sum256([]byte(result.URL + "\x00" + result.Content))
|
|
record := researchEvidenceRecord{SchemaVersion: researchEvidenceSchemaVersion, SavedAt: time.Now().UTC(), ContentSHA256: hex.EncodeToString(hash[:]), Result: result}
|
|
data, err := json.Marshal(record)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
relPath := filepath.Join("research-evidence", "test.json")
|
|
if err := os.MkdirAll(filepath.Join(root, "research-evidence"), 0o750); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(root, relPath), data, 0o640); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
e := &Engine{Cfg: config.Config{DataDir: root}}
|
|
loaded, err := e.loadResearchEvidence(filepath.ToSlash(relPath))
|
|
if err != nil {
|
|
t.Fatalf("load evidence: %v", err)
|
|
}
|
|
if loaded.Result.URL != result.URL || loaded.Result.Content != result.Content {
|
|
t.Fatalf("unexpected loaded record: %+v", loaded)
|
|
}
|
|
}
|
|
|
|
func TestLoadResearchEvidenceRejectsTraversalAndTampering(t *testing.T) {
|
|
root := t.TempDir()
|
|
e := &Engine{Cfg: config.Config{DataDir: root}}
|
|
if _, err := e.loadResearchEvidence("../outside.json"); err == nil {
|
|
t.Fatal("path traversal must be rejected")
|
|
}
|
|
|
|
result := model.ResearchResult{URL: "https://docs.example.test/audit", Content: "content", Fetched: true, Relevant: true}
|
|
record := researchEvidenceRecord{SchemaVersion: researchEvidenceSchemaVersion, SavedAt: time.Now().UTC(), ContentSHA256: "bad", Result: result}
|
|
data, _ := json.Marshal(record)
|
|
if err := os.MkdirAll(filepath.Join(root, "research-evidence"), 0o750); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(root, "research-evidence", "bad.json"), data, 0o640); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := e.loadResearchEvidence("research-evidence/bad.json"); err == nil {
|
|
t.Fatal("checksum mismatch must be rejected")
|
|
}
|
|
}
|
|
|
|
func TestResearchResultNodeReferencesEvidenceWithoutEmbeddingFullPageInMetadata(t *testing.T) {
|
|
result := model.ResearchResult{Title: "Documentation", URL: "https://docs.example.test/a", Content: "full page content", Fetched: true, Relevant: true}
|
|
node := researchResultNode("id", result, "research-evidence/id.json", "abc", []string{"IT-Security"})
|
|
if node.Metadata["evidence_path"] != "research-evidence/id.json" || node.Metadata["content_sha256"] != "abc" {
|
|
t.Fatalf("evidence reference missing: %+v", node.Metadata)
|
|
}
|
|
if _, exists := node.Metadata["content"]; exists {
|
|
t.Fatal("full page content must not be copied into graph metadata")
|
|
}
|
|
}
|
|
|
|
func TestLoadResearchEvidenceCanReuseInMemoryQueuedRecord(t *testing.T) {
|
|
root := t.TempDir()
|
|
result := model.ResearchResult{URL: "https://docs.example.test/live", Content: "queued full content", Fetched: true, Relevant: true}
|
|
hash := sha256.Sum256([]byte(result.URL + "\x00" + result.Content))
|
|
record := researchEvidenceRecord{SchemaVersion: researchEvidenceSchemaVersion, SavedAt: time.Now().UTC(), ContentSHA256: hex.EncodeToString(hash[:]), Result: result}
|
|
e := &Engine{Cfg: config.Config{DataDir: root}}
|
|
e.cacheResearchEvidence("research-evidence/live.json", record)
|
|
loaded, err := e.loadResearchEvidence("research-evidence/live.json")
|
|
if err != nil {
|
|
t.Fatalf("load cached evidence before disk flush: %v", err)
|
|
}
|
|
if loaded.Result.Content != result.Content {
|
|
t.Fatalf("unexpected cached evidence: %+v", loaded)
|
|
}
|
|
}
|
|
|
|
func TestMetadataStringTreatsMissingAndNilAsEmpty(t *testing.T) {
|
|
cases := []map[string]any{
|
|
nil,
|
|
{},
|
|
{"evidence_path": nil},
|
|
{"evidence_path": "<nil>"},
|
|
{"evidence_path": "null"},
|
|
}
|
|
for _, metadata := range cases {
|
|
if got := metadataString(metadata, "evidence_path"); got != "" {
|
|
t.Fatalf("expected empty metadata string, got %q from %#v", got, metadata)
|
|
}
|
|
}
|
|
if got := metadataString(map[string]any{"evidence_path": " research-evidence/x.json "}, "evidence_path"); got != "research-evidence/x.json" {
|
|
t.Fatalf("unexpected normalized metadata string %q", got)
|
|
}
|
|
}
|