178 lines
5.1 KiB
Go
178 lines
5.1 KiB
Go
package aireview
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"testing"
|
|
)
|
|
|
|
func TestBuildStructuredRequestBodyResponsesStyle(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := NewService("https://example.test/v1/responses", "test-key", "test-model")
|
|
body, err := svc.buildStructuredRequestBody("system prompt", "user prompt", "test_schema", reviewSchema())
|
|
if err != nil {
|
|
t.Fatalf("buildStructuredRequestBody returned error: %v", err)
|
|
}
|
|
|
|
if got := body["model"]; got != "test-model" {
|
|
t.Fatalf("model = %v, want test-model", got)
|
|
}
|
|
|
|
if _, ok := body["input"]; !ok {
|
|
t.Fatalf("responses body missing input field: %#v", body)
|
|
}
|
|
|
|
if _, ok := body["text"]; !ok {
|
|
t.Fatalf("responses body missing text field: %#v", body)
|
|
}
|
|
|
|
if _, ok := body["messages"]; ok {
|
|
t.Fatalf("responses body should not include messages: %#v", body)
|
|
}
|
|
if _, ok := body["response_format"]; ok {
|
|
t.Fatalf("responses body should not include response_format: %#v", body)
|
|
}
|
|
}
|
|
|
|
func TestBuildStructuredRequestBodyVLLMChatStyle(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := NewService("http://100.92.130.19:8000/v1/chat/completions", "test-key", "qwen3.6-27b")
|
|
body, err := svc.buildStructuredRequestBody("system prompt", "user prompt", "assignment_review", reviewSchema())
|
|
if err != nil {
|
|
t.Fatalf("buildStructuredRequestBody returned error: %v", err)
|
|
}
|
|
|
|
if got := body["model"]; got != "qwen3.6-27b" {
|
|
t.Fatalf("model = %v, want qwen3.6-27b", got)
|
|
}
|
|
|
|
if _, ok := body["messages"]; !ok {
|
|
t.Fatalf("chat body missing messages: %#v", body)
|
|
}
|
|
|
|
responseFormat, ok := body["response_format"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("response_format missing or wrong type: %#v", body["response_format"])
|
|
}
|
|
if got := responseFormat["type"]; got != "json_schema" {
|
|
t.Fatalf("response_format.type = %v, want json_schema", got)
|
|
}
|
|
|
|
kwargs, ok := body["chat_template_kwargs"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected chat_template_kwargs for vLLM chat style: %#v", body)
|
|
}
|
|
if got := kwargs["enable_thinking"]; got != false {
|
|
t.Fatalf("enable_thinking = %v, want false", got)
|
|
}
|
|
|
|
if _, ok := body["input"]; ok {
|
|
t.Fatalf("chat body should not include responses input field: %#v", body)
|
|
}
|
|
}
|
|
|
|
func TestBuildStructuredRequestBodyAzureChatStyleDoesNotDisableThinking(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := NewService("https://example.openai.azure.com/openai/deployments/review/chat/completions?api-version=2025-01-01-preview", "test-key", "gpt-4.1-mini")
|
|
body, err := svc.buildStructuredRequestBody("system prompt", "user prompt", "assignment_review", reviewSchema())
|
|
if err != nil {
|
|
t.Fatalf("buildStructuredRequestBody returned error: %v", err)
|
|
}
|
|
|
|
if _, ok := body["chat_template_kwargs"]; ok {
|
|
t.Fatalf("azure chat body should not include chat_template_kwargs: %#v", body)
|
|
}
|
|
}
|
|
|
|
func TestApplyAuthHeader(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("azure uses api-key", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := NewService("https://example.openai.azure.com/openai/deployments/review/chat/completions?api-version=2025-01-01-preview", "azure-key", "gpt-4.1-mini")
|
|
req, err := http.NewRequest(http.MethodPost, svc.endpoint, nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest returned error: %v", err)
|
|
}
|
|
|
|
svc.applyAuthHeader(req)
|
|
|
|
if got := req.Header.Get("api-key"); got != "azure-key" {
|
|
t.Fatalf("api-key header = %q, want azure-key", got)
|
|
}
|
|
if got := req.Header.Get("Authorization"); got != "" {
|
|
t.Fatalf("Authorization header = %q, want empty", got)
|
|
}
|
|
})
|
|
|
|
t.Run("non-azure uses bearer auth", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := NewService("http://100.92.130.19:8000/v1/chat/completions", "vllm-key", "qwen3.6-27b")
|
|
req, err := http.NewRequest(http.MethodPost, svc.endpoint, nil)
|
|
if err != nil {
|
|
t.Fatalf("http.NewRequest returned error: %v", err)
|
|
}
|
|
|
|
svc.applyAuthHeader(req)
|
|
|
|
if got := req.Header.Get("Authorization"); got != "Bearer vllm-key" {
|
|
t.Fatalf("Authorization header = %q, want %q", got, "Bearer vllm-key")
|
|
}
|
|
if got := req.Header.Get("api-key"); got != "" {
|
|
t.Fatalf("api-key header = %q, want empty", got)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestExtractChatCompletionText(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("string content", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
respBytes := []byte(`{"choices":[{"message":{"content":"{\"status\":\"ok\"}"}}]}`)
|
|
got, err := extractChatCompletionText(respBytes)
|
|
if err != nil {
|
|
t.Fatalf("extractChatCompletionText returned error: %v", err)
|
|
}
|
|
if got != `{"status":"ok"}` {
|
|
t.Fatalf("content = %q, want %q", got, `{"status":"ok"}`)
|
|
}
|
|
})
|
|
|
|
t.Run("array content", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
payload := map[string]any{
|
|
"choices": []any{
|
|
map[string]any{
|
|
"message": map[string]any{
|
|
"content": []any{
|
|
map[string]any{"type": "text", "text": "{\"status\":"},
|
|
map[string]any{"type": "text", "text": "\"ok\"}"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
respBytes, err := json.Marshal(payload)
|
|
if err != nil {
|
|
t.Fatalf("json.Marshal returned error: %v", err)
|
|
}
|
|
|
|
got, err := extractChatCompletionText(respBytes)
|
|
if err != nil {
|
|
t.Fatalf("extractChatCompletionText returned error: %v", err)
|
|
}
|
|
if got != "{\"status\":\n\"ok\"}" {
|
|
t.Fatalf("content = %q, want joined text output", got)
|
|
}
|
|
})
|
|
}
|