// Integrationstest (SRC-05): echte Manticore-Instanz, TEST_MANTICORE_URL // (gleiche Konvention wie integration_test.go/ranking_test.go). package search import ( "context" "testing" ) func indexFacetDoc(t *testing.T, client *Client, ctx context.Context, tenant string, doc Document) { t.Helper() doc.TenantSlug = tenant doc.ID = DocumentID(tenant, doc.MessageID) if err := client.Index(ctx, doc); err != nil { t.Fatalf("index %s: %v", doc.MessageID, err) } } // TestFacets_CountsMatchActualHits ist die geforderte Pflichtprüfung 1: // Facettenzahlen stimmen mit tatsächlicher Treffermenge überein. func TestFacets_CountsMatchActualHits(t *testing.T) { client := setupClient(t) ctx := context.Background() tenant := "mandant-src05-zahlen" indexFacetDoc(t, client, ctx, tenant, Document{MessageID: "msg-fz-1", Subject: "a", Sender: "alice@example.com", Mailbox: "inbox", AttachmentType: "pdf"}) indexFacetDoc(t, client, ctx, tenant, Document{MessageID: "msg-fz-2", Subject: "b", Sender: "alice@example.com", Mailbox: "inbox", AttachmentType: "docx"}) indexFacetDoc(t, client, ctx, tenant, Document{MessageID: "msg-fz-3", Subject: "c", Sender: "bob@example.com", Mailbox: "archiv", AttachmentType: "pdf"}) result, err := client.Facets(ctx, tenant, "", nil) if err != nil { t.Fatalf("facets: %v", err) } senderCounts := toCountMap(result.Values[FieldSender]) if senderCounts["alice@example.com"] != 2 { t.Fatalf("erwartete 2 treffer für alice@example.com, habe %d (%+v)", senderCounts["alice@example.com"], result.Values[FieldSender]) } if senderCounts["bob@example.com"] != 1 { t.Fatalf("erwartete 1 treffer für bob@example.com, habe %d", senderCounts["bob@example.com"]) } attachmentCounts := toCountMap(result.Values[FieldAttachmentType]) if attachmentCounts["pdf"] != 2 { t.Fatalf("erwartete 2 treffer für pdf, habe %d", attachmentCounts["pdf"]) } } // TestFacets_ThreeFiltersCombineWithAND ist die geforderte Pflichtprüfung // 2: Kombination von drei Filtern liefert korrekt eingeschränkte Treffer. func TestFacets_ThreeFiltersCombineWithAND(t *testing.T) { client := setupClient(t) ctx := context.Background() tenant := "mandant-src05-kombi" indexFacetDoc(t, client, ctx, tenant, Document{MessageID: "msg-kombi-treffer", Subject: "x", Sender: "alice@example.com", Mailbox: "inbox", AttachmentType: "pdf", Tag: "wichtig"}) indexFacetDoc(t, client, ctx, tenant, Document{MessageID: "msg-kombi-falscher-sender", Subject: "x", Sender: "bob@example.com", Mailbox: "inbox", AttachmentType: "pdf", Tag: "wichtig"}) indexFacetDoc(t, client, ctx, tenant, Document{MessageID: "msg-kombi-falsche-mailbox", Subject: "x", Sender: "alice@example.com", Mailbox: "archiv", AttachmentType: "pdf", Tag: "wichtig"}) indexFacetDoc(t, client, ctx, tenant, Document{MessageID: "msg-kombi-falscher-typ", Subject: "x", Sender: "alice@example.com", Mailbox: "inbox", AttachmentType: "docx", Tag: "wichtig"}) filters := []FacetFilter{ {Field: FieldSender, Value: "alice@example.com"}, {Field: FieldMailbox, Value: "inbox"}, {Field: FieldAttachmentType, Value: "pdf"}, } result, err := client.Facets(ctx, tenant, "", filters) if err != nil { t.Fatalf("facets: %v", err) } tagCounts := toCountMap(result.Values[FieldTag]) if tagCounts["wichtig"] != 1 { t.Fatalf("erwartete genau 1 verbleibenden treffer nach 3 UND-verknüpften filtern, habe %d (%+v)", tagCounts["wichtig"], result.Values[FieldTag]) } } // TestFacets_TenantSeparation ist die geforderte Pflichtprüfung 3: // Facetten eines Mandanten enthalten keine Werte eines anderen. func TestFacets_TenantSeparation(t *testing.T) { client := setupClient(t) ctx := context.Background() tenantA := "mandant-src05-facetten-a" tenantB := "mandant-src05-facetten-b" indexFacetDoc(t, client, ctx, tenantA, Document{MessageID: "msg-fa-1", Subject: "a", Sender: "nur-a@example.com", Mailbox: "inbox", AttachmentType: "pdf"}) indexFacetDoc(t, client, ctx, tenantB, Document{MessageID: "msg-fb-1", Subject: "b", Sender: "nur-b@example.com", Mailbox: "inbox", AttachmentType: "pdf"}) resultB, err := client.Facets(ctx, tenantB, "", nil) if err != nil { t.Fatalf("facets mandant b: %v", err) } senderCountsB := toCountMap(resultB.Values[FieldSender]) if _, present := senderCountsB["nur-a@example.com"]; present { t.Fatalf("mandant b sieht facettenwert von mandant a: %+v", resultB.Values[FieldSender]) } if senderCountsB["nur-b@example.com"] != 1 { t.Fatalf("erwartete eigenen facettenwert bei mandant b, habe: %+v", resultB.Values[FieldSender]) } } func toCountMap(values []FacetValue) map[string]int64 { m := make(map[string]int64, len(values)) for _, v := range values { m[v.Value] = v.Count } return m }