Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

107 wiersze
3.4KB

  1. package mapping
  2. import (
  3. "context"
  4. "encoding/json"
  5. "net/http"
  6. "net/http/httptest"
  7. "strings"
  8. "testing"
  9. "time"
  10. "qctextbuilder/internal/domain"
  11. "qctextbuilder/internal/llmruntime"
  12. )
  13. type stubSettingsReader struct {
  14. settings *domain.AppSettings
  15. err error
  16. }
  17. func (s *stubSettingsReader) GetSettings(context.Context) (*domain.AppSettings, error) {
  18. if s.err != nil {
  19. return nil, s.err
  20. }
  21. return s.settings, nil
  22. }
  23. func TestProviderAwareSuggestionGenerator_UsesActiveProviderModelAndKey(t *testing.T) {
  24. t.Parallel()
  25. var (
  26. gotPath string
  27. gotAuth string
  28. gotModel string
  29. )
  30. server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  31. gotPath = r.URL.Path
  32. gotAuth = r.Header.Get("Authorization")
  33. var payload map[string]any
  34. _ = json.NewDecoder(r.Body).Decode(&payload)
  35. gotModel, _ = payload["model"].(string)
  36. _, _ = w.Write([]byte(`{"choices":[{"message":{"content":"{\"suggestions\":[{\"fieldPath\":\"text.textTitle_m1710_1\",\"value\":\"Provider Hero\",\"reason\":\"focused hero\"}]}"}}]}`))
  37. }))
  38. defer server.Close()
  39. generator := NewProviderAwareSuggestionGenerator(&stubSettingsReader{settings: &domain.AppSettings{
  40. LLMActiveProvider: domain.LLMProviderOpenAI,
  41. LLMActiveModel: "gpt-5.4",
  42. LLMBaseURL: server.URL,
  43. OpenAIAPIKeyEncrypted: "openai-key",
  44. }}, llmruntime.NewFactory(5*time.Second))
  45. result, err := generator.Generate(context.Background(), SuggestionRequest{
  46. Fields: []domain.TemplateField{
  47. {Path: "text.textTitle_m1710_1", KeyName: "textTitle_m1710_1", FieldKind: "text", IsEnabled: true, WebsiteSection: domain.WebsiteSectionHero},
  48. },
  49. GlobalData: map[string]any{"companyName": "Muster AG"},
  50. Existing: map[string]string{},
  51. })
  52. if err != nil {
  53. t.Fatalf("generate failed: %v", err)
  54. }
  55. if got := result.ByFieldPath["text.textTitle_m1710_1"].Value; got != "Provider Hero" {
  56. t.Fatalf("unexpected value: %q", got)
  57. }
  58. if got := result.ByFieldPath["text.textTitle_m1710_1"].Source; got != domain.LLMProviderOpenAI {
  59. t.Fatalf("unexpected source: %q", got)
  60. }
  61. if gotPath != "/v1/chat/completions" {
  62. t.Fatalf("unexpected path: %s", gotPath)
  63. }
  64. if gotAuth != "Bearer openai-key" {
  65. t.Fatalf("unexpected auth header: %q", gotAuth)
  66. }
  67. if gotModel != "gpt-5.4" {
  68. t.Fatalf("unexpected model: %q", gotModel)
  69. }
  70. }
  71. func TestProviderAwareSuggestionGenerator_RequiresAPIKeyForNonOllama(t *testing.T) {
  72. t.Parallel()
  73. generator := NewProviderAwareSuggestionGenerator(&stubSettingsReader{settings: &domain.AppSettings{
  74. LLMActiveProvider: domain.LLMProviderAnthropic,
  75. LLMActiveModel: "claude-sonnet-4-5",
  76. }}, llmruntime.NewFactory(5*time.Second))
  77. _, err := generator.Generate(context.Background(), SuggestionRequest{
  78. Fields: []domain.TemplateField{{Path: "text.textTitle_m1710_1", KeyName: "textTitle_m1710_1", FieldKind: "text", IsEnabled: true, WebsiteSection: domain.WebsiteSectionHero}},
  79. })
  80. if err == nil || !strings.Contains(err.Error(), "api key") {
  81. t.Fatalf("expected api key error, got: %v", err)
  82. }
  83. }
  84. func TestParseProviderSuggestions_AcceptsFencedJSON(t *testing.T) {
  85. t.Parallel()
  86. items, err := parseProviderSuggestions("```json\n{\"suggestions\":[{\"fieldPath\":\"a\",\"value\":\"b\"}]}\n```")
  87. if err != nil {
  88. t.Fatalf("parse failed: %v", err)
  89. }
  90. if len(items) != 1 || items[0].FieldPath != "a" || items[0].Value != "b" {
  91. t.Fatalf("unexpected parsed result: %+v", items)
  92. }
  93. }