Files
aura-crm/production/backend/internal/aiintake/handler_test.go
T

92 lines
3.2 KiB
Go

package aiintake
import (
"strings"
"testing"
)
func TestExtractInputValidate(t *testing.T) {
valid := strings.Repeat("a", minTextLen)
tooShort := strings.Repeat("a", minTextLen-1)
tooLong := strings.Repeat("a", maxTextLen+1)
tests := []struct {
name string
text string
wantErr bool
}{
{"valid minimum length", valid, false},
{"empty text", "", true},
{"below minimum length", tooShort, true},
{"at maximum length", strings.Repeat("a", maxTextLen), false},
{"above maximum length", tooLong, true},
{"typical customer text", "ноутбук ASUS не включается, клиент Иван, телефон +79991234567", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := extractInput{Text: tt.text}
got := b.validate()
if (got != "") != tt.wantErr {
t.Errorf("validate() = %q, wantErr %v", got, tt.wantErr)
}
})
}
}
func TestBuildGeminiRequestEmbedsTextBetweenMarkers(t *testing.T) {
text := "клиент сказал что принтер полосит"
req := buildGeminiRequest(text, "gemini-2.0-flash")
contents, ok := req["contents"].([]map[string]any)
if !ok || len(contents) != 1 {
t.Fatalf("expected exactly one content entry, got %#v", req["contents"])
}
parts, ok := contents[0]["parts"].([]map[string]any)
if !ok || len(parts) != 1 {
t.Fatalf("expected exactly one part, got %#v", contents[0]["parts"])
}
promptText, ok := parts[0]["text"].(string)
if !ok {
t.Fatalf("expected part text to be a string, got %#v", parts[0]["text"])
}
if !strings.Contains(promptText, text) {
t.Errorf("prompt does not contain the customer text: %q", promptText)
}
if !strings.Contains(promptText, "BEGIN CUSTOMER TEXT") || !strings.Contains(promptText, "END CUSTOMER TEXT") {
t.Error("prompt is missing the delimiter markers meant to fence off untrusted customer text from instructions")
}
genConfig, ok := req["generationConfig"].(map[string]any)
if !ok {
t.Fatalf("expected generationConfig to be present, got %#v", req["generationConfig"])
}
responseFormat, ok := genConfig["responseFormat"].(map[string]any)
if !ok {
t.Fatalf("expected responseFormat to be present, got %#v", genConfig["responseFormat"])
}
textFormat, ok := responseFormat["text"].(map[string]any)
if !ok {
t.Fatalf("expected responseFormat.text to be present, got %#v", responseFormat["text"])
}
if textFormat["mimeType"] != "application/json" {
t.Errorf("expected mimeType application/json, got %#v", textFormat["mimeType"])
}
if textFormat["schema"] == nil {
t.Error("expected a non-nil response schema")
}
}
func TestBuildGeminiRequestDoesNotMutateSchemaBetweenCalls(t *testing.T) {
// extractionSchema is a shared package-level map — building two requests
// must not let one call's mutation bleed into the other's.
req1 := buildGeminiRequest("first text", "gemini-2.0-flash")
req2 := buildGeminiRequest("second text", "gemini-2.0-flash")
schema1 := req1["generationConfig"].(map[string]any)["responseFormat"].(map[string]any)["text"].(map[string]any)["schema"]
schema2 := req2["generationConfig"].(map[string]any)["responseFormat"].(map[string]any)["text"].(map[string]any)["schema"]
if schema1 == nil || schema2 == nil {
t.Fatal("expected non-nil schemas")
}
}