mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07:10 +00:00
134 lines
4.0 KiB
Go
134 lines
4.0 KiB
Go
package openrouter
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestChatCompletionRequestShapeAndParse(t *testing.T) {
|
|
var captured map[string]any
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/chat/completions" {
|
|
t.Errorf("path = %q, want /chat/completions", r.URL.Path)
|
|
}
|
|
if got := r.Header.Get("Authorization"); got != "Bearer test-key" {
|
|
t.Errorf("Authorization = %q, want Bearer test-key", got)
|
|
}
|
|
body, _ := io.ReadAll(r.Body)
|
|
if err := json.Unmarshal(body, &captured); err != nil {
|
|
t.Fatalf("unmarshal request: %v", err)
|
|
}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
_, _ = w.Write([]byte(`{"choices":[{"message":{"content":"{\"reasoning\":\"tap login\",\"ranked\":[2,0]}"}}]}`))
|
|
}))
|
|
defer server.Close()
|
|
|
|
t.Setenv("OPENROUTER_API_KEY", "test-key")
|
|
t.Setenv("OPENROUTER_BASE_URL", server.URL)
|
|
client, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New: %v", err)
|
|
}
|
|
|
|
resp, err := client.ChatCompletion(context.Background(), Request{
|
|
Model: "vendor/model",
|
|
Messages: []Message{
|
|
{Role: "system", Content: []ContentPart{TextPart("system")}},
|
|
{Role: "user", Content: []ContentPart{
|
|
TextPart("candidates"),
|
|
ImagePart("data:image/png;base64,AAAA"),
|
|
}},
|
|
},
|
|
ResponseFormat: &ResponseFormat{
|
|
Type: "json_schema",
|
|
JSONSchema: JSONSchema{
|
|
Name: "ranked_actions",
|
|
Strict: true,
|
|
Schema: map[string]any{"type": "object"},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ChatCompletion: %v", err)
|
|
}
|
|
|
|
// Request carried the model.
|
|
if captured["model"] != "vendor/model" {
|
|
t.Errorf("model = %v, want vendor/model", captured["model"])
|
|
}
|
|
// Request carried an image_url content part.
|
|
messages := captured["messages"].([]any)
|
|
user := messages[1].(map[string]any)
|
|
parts := user["content"].([]any)
|
|
foundImage := false
|
|
for _, part := range parts {
|
|
if part.(map[string]any)["type"] == "image_url" {
|
|
foundImage = true
|
|
image := part.(map[string]any)["image_url"].(map[string]any)
|
|
if !strings.HasPrefix(image["url"].(string), "data:image/png;base64,") {
|
|
t.Errorf("image url = %v, want data URL", image["url"])
|
|
}
|
|
}
|
|
}
|
|
if !foundImage {
|
|
t.Error("request carried no image_url content part")
|
|
}
|
|
// Request carried the strict json_schema response_format.
|
|
rf := captured["response_format"].(map[string]any)
|
|
if rf["type"] != "json_schema" {
|
|
t.Errorf("response_format.type = %v, want json_schema", rf["type"])
|
|
}
|
|
if schema := rf["json_schema"].(map[string]any); schema["strict"] != true {
|
|
t.Errorf("json_schema.strict = %v, want true", schema["strict"])
|
|
}
|
|
|
|
// Response parsed into the ranked-index content.
|
|
if len(resp.Choices) != 1 {
|
|
t.Fatalf("choices = %d, want 1", len(resp.Choices))
|
|
}
|
|
var content struct {
|
|
Reasoning string `json:"reasoning"`
|
|
Ranked []int `json:"ranked"`
|
|
}
|
|
if err := json.Unmarshal([]byte(resp.Choices[0].Message.Content), &content); err != nil {
|
|
t.Fatalf("unmarshal content: %v", err)
|
|
}
|
|
if content.Reasoning != "tap login" {
|
|
t.Errorf("reasoning = %q, want tap login", content.Reasoning)
|
|
}
|
|
if len(content.Ranked) != 2 || content.Ranked[0] != 2 || content.Ranked[1] != 0 {
|
|
t.Errorf("ranked = %v, want [2 0]", content.Ranked)
|
|
}
|
|
}
|
|
|
|
func TestNewRequiresAPIKey(t *testing.T) {
|
|
t.Setenv("OPENROUTER_API_KEY", "")
|
|
if _, err := New(); err == nil {
|
|
t.Fatal("expected error when OPENROUTER_API_KEY is unset")
|
|
}
|
|
}
|
|
|
|
func TestChatCompletionSurfacesHTTPError(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusTooManyRequests)
|
|
_, _ = w.Write([]byte(`{"error":"rate limited"}`))
|
|
}))
|
|
defer server.Close()
|
|
|
|
t.Setenv("OPENROUTER_API_KEY", "test-key")
|
|
t.Setenv("OPENROUTER_BASE_URL", server.URL)
|
|
client, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New: %v", err)
|
|
}
|
|
_, err = client.ChatCompletion(context.Background(), Request{Model: "m"})
|
|
if err == nil || !strings.Contains(err.Error(), "429") {
|
|
t.Fatalf("expected 429 error, got %v", err)
|
|
}
|
|
}
|