Files
Veyra/internal/llm/client_test.go
T

65 lines
3.2 KiB
Go

package llm
import (
"context"
"encoding/json"
"git.sundynix.cn/Blizzard/Veyra/internal/model"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestProtocolsAndFailureIsolation(t *testing.T) {
output := `{"schema_version":"candidate_analysis.v1","symbol":"000042","exchange":"SZSE","decision":"APPROVE","summary":"均线交叉观察","risks":"未复权日线","evidence_indices":[0],"missing_information":["基本面未提供"]}`
for _, protocol := range []string{"responses", "chat_completions"} {
t.Run(protocol, func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") != "Bearer fixture-secret" {
t.Error("missing bearer authentication")
}
var body map[string]any
if json.NewDecoder(r.Body).Decode(&body) != nil {
t.Error("invalid request")
}
if body["store"] != false || body["model"] != "fixture-model" {
t.Error("model/storage config not inherited")
}
if protocol == "responses" {
if r.URL.Path != "/v1/responses" || body["text"] == nil {
t.Error("invalid responses request")
}
_ = json.NewEncoder(w).Encode(map[string]any{"status": "completed", "output": []any{map[string]any{"type": "message", "content": []any{map[string]string{"type": "output_text", "text": output}}}}})
} else {
if r.URL.Path != "/v1/chat/completions" || body["response_format"] == nil {
t.Error("invalid chat request")
}
_ = json.NewEncoder(w).Encode(map[string]any{"choices": []any{map[string]any{"finish_reason": "stop", "message": map[string]string{"content": output}}}})
}
}))
defer server.Close()
p := model.ProviderConfig{Enabled: true, ModelName: "fixture-model", BaseURL: server.URL + "/v1", WireAPI: protocol, TimeoutSeconds: 2, RequiresOpenAIAuth: true, DisableResponseStorage: true}
a, err := New().Analyze(context.Background(), p, "fixture-secret", json.RawMessage(`{}`))
if err != nil || a.Decision != "APPROVE" {
t.Fatalf("call failed: %v", err)
}
})
}
for _, response := range []string{`{"status":"incomplete","output":[]}`, `{"status":"completed","output":[{"content":[{"type":"refusal"}]}]}`, `{"status":"completed","output":[{"content":[{"type":"output_text","text":"{} {}"}]}]}`} {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(response)) }))
_, err := New().Analyze(context.Background(), model.ProviderConfig{Enabled: true, ModelName: "x", BaseURL: server.URL, WireAPI: "responses", TimeoutSeconds: 2}, "", json.RawMessage(`{}`))
server.Close()
if err == nil {
t.Fatal("invalid response accepted")
}
}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "fixture-secret upstream internal detail", 503)
}))
defer server.Close()
_, err := New().Analyze(context.Background(), model.ProviderConfig{Enabled: true, ModelName: "x", BaseURL: server.URL, WireAPI: "responses", TimeoutSeconds: 2}, "", json.RawMessage(`{}`))
if err == nil || strings.Contains(err.Error(), "secret") || err.Error() != "MODEL_HTTP_503" {
t.Fatal("unsafe provider error")
}
}