homelabby/internal/ai/client_test.go
Mikkel Georgsen 8c03780230 feat(02-01): AI package foundation — types, interface, mock, prompts, config extension
- internal/ai/types.go: IntakeRequest, IntakeResult, TierConfig, AIConfig domain types
- internal/ai/client.go: AIClient interface + TierClient (go-openai, BaseURL tier-routing)
- internal/ai/mock.go: MockAIClient test double with HighConfidenceResult/LowConfidenceResult fixtures
- internal/ai/prompts/intake.go: BuildIntakePrompt() JSON-extraction prompt template
- internal/config/config.go: Config.AI AIConfig field, tier defaults, env bindings, ai_config.json merge
- ai_config.json: template config with placeholder Tier2 API key
- .gitignore: add ai_config.local.json pattern for real keys (T-02-01 mitigation)
- All tests pass: TestMockAIClient, TestMockAIClientError, TestTierClientConstruction, TestAIConfigDefaults
2026-04-10 05:45:13 +00:00

65 lines
1.5 KiB
Go

package ai_test
import (
"context"
"errors"
"testing"
"git.georgsen.dk/hwlab/internal/ai"
)
func TestMockAIClient(t *testing.T) {
mock := &ai.MockAIClient{
FixedResult: ai.HighConfidenceResult(),
}
result, err := mock.AnalyzePhotos(context.Background(), ai.IntakeRequest{
PhotosBase64: []string{"data:image/jpeg;base64,AAAA"},
JobID: "test-job-1",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result.Confidence != 0.95 {
t.Errorf("expected confidence 0.95, got %f", result.Confidence)
}
if len(mock.Calls) != 1 {
t.Errorf("expected 1 call recorded, got %d", len(mock.Calls))
}
}
func TestMockAIClientError(t *testing.T) {
mock := &ai.MockAIClient{
FixedError: errors.New("timeout"),
}
result, err := mock.AnalyzePhotos(context.Background(), ai.IntakeRequest{})
if err == nil {
t.Error("expected error, got nil")
}
if result != nil {
t.Errorf("expected nil result on error, got %+v", result)
}
}
func TestTierClientConstruction(t *testing.T) {
cfg := ai.TierConfig{
BaseURL: "http://localhost:9999/v1",
APIKey: "x",
Model: "m",
TimeoutSeconds: 1,
}
client := ai.NewTierClient(cfg)
if client == nil {
t.Fatal("expected non-nil TierClient")
}
// AnalyzePhotos should return a non-nil error (connection refused) — not panic
_, err := client.AnalyzePhotos(context.Background(), ai.IntakeRequest{
PhotosBase64: []string{"data:image/jpeg;base64,AAAA"},
JobID: "test-job-2",
})
if err == nil {
t.Error("expected connection refused error, got nil")
}
}