test: check request errors and stop asserting PathRewrite on /v1/models

/v1/models is served from config by ServeHTTP (task 2.5) so it never reaches
routing; the rewrite test now uses a non-reserved path.
This commit is contained in:
Story Crater Bot
2026-08-19 23:55:42 -07:00
parent c8c656046a
commit 8feee6754b
9 changed files with 183 additions and 67 deletions
+16 -4
View File
@@ -76,7 +76,10 @@ func TestBodyBasedDispatch(t *testing.T) {
reasoningCalled = false reasoningCalled = false
ornithCalled = false ornithCalled = false
requestBody := `{"model":"reasoning","messages":[{"role":"user","content":"hi"}]}` requestBody := `{"model":"reasoning","messages":[{"role":"user","content":"hi"}]}`
resp, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(requestBody)) resp, err := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(requestBody))
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp.Body.Close() resp.Body.Close()
if !reasoningCalled { if !reasoningCalled {
@@ -151,7 +154,10 @@ func TestBodyPreservedUnmodified(t *testing.T) {
// Send a request with specific body content // Send a request with specific body content
originalBody := `{"model":"reasoning","stream":true,"messages":[{"role":"user","content":"hello world"}],"temperature":0.7}` originalBody := `{"model":"reasoning","stream":true,"messages":[{"role":"user","content":"hello world"}],"temperature":0.7}`
resp, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(originalBody)) resp, err := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(originalBody))
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp.Body.Close() resp.Body.Close()
if string(receivedBody) != originalBody { if string(receivedBody) != originalBody {
@@ -249,7 +255,10 @@ func TestUnknownModelReject(t *testing.T) {
defer server.Close() defer server.Close()
requestBody := `{"model":"unknown-model","messages":[]}` requestBody := `{"model":"unknown-model","messages":[]}`
resp, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(requestBody)) resp, err := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(requestBody))
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusBadRequest { if resp.StatusCode != http.StatusBadRequest {
@@ -300,7 +309,10 @@ func TestMissingModelField(t *testing.T) {
defer server.Close() defer server.Close()
requestBody := `{"messages":[]}` requestBody := `{"messages":[]}`
resp, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(requestBody)) resp, err := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(requestBody))
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusBadRequest { if resp.StatusCode != http.StatusBadRequest {
+4 -1
View File
@@ -323,7 +323,10 @@ func TestBodySizeCapRejectionLogged(t *testing.T) {
// Send an oversized body // Send an oversized body
body := strings.Repeat("a", int(maxBodySize)+1) body := strings.Repeat("a", int(maxBodySize)+1)
resp, _ := http.Post(server.URL+"/test", "text/plain", strings.NewReader(body)) resp, err := http.Post(server.URL+"/test", "text/plain", strings.NewReader(body))
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp.Body.Close() resp.Body.Close()
// Verify rejection status // Verify rejection status
+36 -9
View File
@@ -45,11 +45,14 @@ func TestEmbeddingsPassthroughNoRewrite(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/embeddings", server.URL+"/v1/embeddings",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"nomic-ai/nomic-embed-text-v2-moe","input":"hello"}`)), bytes.NewReader([]byte(`{"model":"nomic-ai/nomic-embed-text-v2-moe","input":"hello"}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if !embeddingsCalled { if !embeddingsCalled {
@@ -91,11 +94,14 @@ func TestEmbeddingsResponsePassthrough(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/embeddings", server.URL+"/v1/embeddings",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"nomic-ai/nomic-embed-text-v2-moe","input":"test"}`)), bytes.NewReader([]byte(`{"model":"nomic-ai/nomic-embed-text-v2-moe","input":"test"}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body) body, _ := io.ReadAll(resp.Body)
@@ -135,11 +141,14 @@ func TestRerankPathRewrite(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/rerank", server.URL+"/v1/rerank",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"BAAI/bge-reranker-base","query":"test","texts":["a","b"]}`)), bytes.NewReader([]byte(`{"model":"BAAI/bge-reranker-base","query":"test","texts":["a","b"]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
// Verify path IS rewritten to /rerank // Verify path IS rewritten to /rerank
@@ -177,11 +186,14 @@ func TestRerankResponsePassthrough(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/rerank", server.URL+"/v1/rerank",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"BAAI/bge-reranker-base","query":"q","texts":["a"]}`)), bytes.NewReader([]byte(`{"model":"BAAI/bge-reranker-base","query":"q","texts":["a"]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body) body, _ := io.ReadAll(resp.Body)
@@ -209,11 +221,14 @@ func TestEmbeddingsUnknownModel(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/embeddings", server.URL+"/v1/embeddings",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"unknown-embeddings","input":"test"}`)), bytes.NewReader([]byte(`{"model":"unknown-embeddings","input":"test"}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusBadRequest { if resp.StatusCode != http.StatusBadRequest {
@@ -244,11 +259,14 @@ func TestRerankerUnknownModel(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/rerank", server.URL+"/v1/rerank",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"unknown-reranker","query":"q","texts":["a"]}`)), bytes.NewReader([]byte(`{"model":"unknown-reranker","query":"q","texts":["a"]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusBadRequest { if resp.StatusCode != http.StatusBadRequest {
@@ -288,11 +306,14 @@ func TestEmbeddingsBodyForwarded(t *testing.T) {
defer server.Close() defer server.Close()
originalBody := `{"model":"nomic-ai/nomic-embed-text-v2-moe","input":"test data with special chars: \u0001"}` originalBody := `{"model":"nomic-ai/nomic-embed-text-v2-moe","input":"test data with special chars: \u0001"}`
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/embeddings", server.URL+"/v1/embeddings",
"application/json", "application/json",
bytes.NewReader([]byte(originalBody)), bytes.NewReader([]byte(originalBody)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp.Body.Close() resp.Body.Close()
// The received body should match the original (though may have different formatting) // The received body should match the original (though may have different formatting)
@@ -337,11 +358,14 @@ func TestRerankerBodyForwarded(t *testing.T) {
defer server.Close() defer server.Close()
originalBody := `{"model":"BAAI/bge-reranker-base","query":"test","texts":["a","b","c"]}` originalBody := `{"model":"BAAI/bge-reranker-base","query":"test","texts":["a","b","c"]}`
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/rerank", server.URL+"/v1/rerank",
"application/json", "application/json",
bytes.NewReader([]byte(originalBody)), bytes.NewReader([]byte(originalBody)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp.Body.Close() resp.Body.Close()
var orig, received map[string]interface{} var orig, received map[string]interface{}
@@ -380,11 +404,14 @@ func TestUpstreamErrorStatusSurfaced(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/embeddings", server.URL+"/v1/embeddings",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"nomic-ai/nomic-embed-text-v2-moe","input":"test"}`)), bytes.NewReader([]byte(`{"model":"nomic-ai/nomic-embed-text-v2-moe","input":"test"}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusInternalServerError { if resp.StatusCode != http.StatusInternalServerError {
+36 -9
View File
@@ -74,7 +74,10 @@ func TestModelsEndpointContentType(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Get(server.URL + "/v1/models") resp, err := http.Get(server.URL + "/v1/models")
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
ct := resp.Header.Get("Content-Type") ct := resp.Header.Get("Content-Type")
@@ -101,7 +104,10 @@ func TestModelsEndpointResponseShape(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Get(server.URL + "/v1/models") resp, err := http.Get(server.URL + "/v1/models")
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
var result ModelListResponse var result ModelListResponse
@@ -161,7 +167,10 @@ func TestModelsEndpointEnumeratesAllModels(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Get(server.URL + "/v1/models") resp, err := http.Get(server.URL + "/v1/models")
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
var result ModelListResponse var result ModelListResponse
@@ -211,7 +220,10 @@ func TestModelsEndpointHasRequiredFields(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Get(server.URL + "/v1/models") resp, err := http.Get(server.URL + "/v1/models")
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
var result ModelListResponse var result ModelListResponse
@@ -292,7 +304,10 @@ func TestModelsEndpointDerivedFromConfig(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Get(server.URL + "/v1/models") resp, err := http.Get(server.URL + "/v1/models")
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
var result ModelListResponse var result ModelListResponse
@@ -347,18 +362,24 @@ func TestModelsEndpointConsistentWithDispatch(t *testing.T) {
defer server.Close() defer server.Close()
// Get list of models // Get list of models
resp, _ := http.Get(server.URL + "/v1/models") resp, err := http.Get(server.URL + "/v1/models")
if err != nil {
t.Fatalf("request failed: %v", err)
}
var result ModelListResponse var result ModelListResponse
json.NewDecoder(resp.Body).Decode(&result) json.NewDecoder(resp.Body).Decode(&result)
resp.Body.Close() resp.Body.Close()
// Try to dispatch to each advertised model // Try to dispatch to each advertised model
for _, model := range result.Data { for _, model := range result.Data {
dispatchResp, _ := http.Post( dispatchResp, err := http.Post(
server.URL+"/v1/chat/completions", server.URL+"/v1/chat/completions",
"application/json", "application/json",
strings.NewReader(`{"model":"`+model.ID+`","messages":[]}`), strings.NewReader(`{"model":"`+model.ID+`","messages":[]}`),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer dispatchResp.Body.Close() defer dispatchResp.Body.Close()
// Should not return 400 (unknown model error) // Should not return 400 (unknown model error)
@@ -394,14 +415,20 @@ func TestModelsEndpointResponseIsConsistent(t *testing.T) {
defer server.Close() defer server.Close()
// Call endpoint twice // Call endpoint twice
resp1, _ := http.Get(server.URL + "/v1/models") resp1, err := http.Get(server.URL + "/v1/models")
if err != nil {
t.Fatalf("request failed: %v", err)
}
var result1 ModelListResponse var result1 ModelListResponse
json.NewDecoder(resp1.Body).Decode(&result1) json.NewDecoder(resp1.Body).Decode(&result1)
resp1.Body.Close() resp1.Body.Close()
time.Sleep(10 * time.Millisecond) time.Sleep(10 * time.Millisecond)
resp2, _ := http.Get(server.URL + "/v1/models") resp2, err := http.Get(server.URL + "/v1/models")
if err != nil {
t.Fatalf("request failed: %v", err)
}
var result2 ModelListResponse var result2 ModelListResponse
json.NewDecoder(resp2.Body).Decode(&result2) json.NewDecoder(resp2.Body).Decode(&result2)
resp2.Body.Close() resp2.Body.Close()
+7 -2
View File
@@ -105,7 +105,9 @@ func TestProxyPathRewrite(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, err := http.Get(server.URL + "/v1/models") // Not /v1/models: ServeHTTP serves that endpoint from config (task 2.5)
// and returns before routing, so it never exercises PathRewrite.
resp, err := http.Get(server.URL + "/some/path")
if err != nil { if err != nil {
t.Fatalf("request failed: %v", err) t.Fatalf("request failed: %v", err)
} }
@@ -402,7 +404,10 @@ func TestProxyPreservesBody(t *testing.T) {
defer server.Close() defer server.Close()
testBody := `{"model": "test", "messages": []}` testBody := `{"model": "test", "messages": []}`
resp, _ := http.Post(server.URL+"/test", "application/json", strings.NewReader(testBody)) resp, err := http.Post(server.URL+"/test", "application/json", strings.NewReader(testBody))
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp.Body.Close() resp.Body.Close()
if receivedBody != testBody { if receivedBody != testBody {
+4 -1
View File
@@ -102,7 +102,10 @@ func TestReadTimeout(t *testing.T) {
defer server.Close() defer server.Close()
start := time.Now() start := time.Now()
resp, _ := http.Get(server.URL + "/test") resp, err := http.Get(server.URL + "/test")
if err != nil {
t.Fatalf("request failed: %v", err)
}
elapsed := time.Since(start) elapsed := time.Since(start)
// Should timeout around the read timeout (with some tolerance) // Should timeout around the read timeout (with some tolerance)
+46 -31
View File
@@ -16,8 +16,8 @@ import (
// OpenAI-style tool definition // OpenAI-style tool definition
type Tool struct { type Tool struct {
Type string `json:"type"` Type string `json:"type"`
Function ToolFunction `json:"function"` Function ToolFunction `json:"function"`
} }
type ToolFunction struct { type ToolFunction struct {
@@ -28,21 +28,21 @@ type ToolFunction struct {
// OpenAI chat completion with tools request // OpenAI chat completion with tools request
type ChatCompletionRequest struct { type ChatCompletionRequest struct {
Model string `json:"model"` Model string `json:"model"`
Messages []Message `json:"messages"` Messages []Message `json:"messages"`
Tools []Tool `json:"tools,omitempty"` Tools []Tool `json:"tools,omitempty"`
Stream bool `json:"stream,omitempty"` Stream bool `json:"stream,omitempty"`
} }
type Message struct { type Message struct {
Role string `json:"role"` Role string `json:"role"`
Content interface{} `json:"content"` Content interface{} `json:"content"`
ToolCalls []ToolCall `json:"tool_calls,omitempty"` ToolCalls []ToolCall `json:"tool_calls,omitempty"`
} }
type ToolCall struct { type ToolCall struct {
ID string `json:"id"` ID string `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Function FunctionCall `json:"function"` Function FunctionCall `json:"function"`
} }
@@ -64,21 +64,21 @@ func TestToolCallOpenAIStyle(t *testing.T) {
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
response := map[string]interface{}{ response := map[string]interface{}{
"id": "chatcmpl-123", "id": "chatcmpl-123",
"object": "chat.completion", "object": "chat.completion",
"model": "reasoning", "model": "reasoning",
"choices": []map[string]interface{}{ "choices": []map[string]interface{}{
{ {
"index": 0, "index": 0,
"message": map[string]interface{}{ "message": map[string]interface{}{
"role": "assistant", "role": "assistant",
"content": nil, "content": nil,
"tool_calls": []map[string]interface{}{ "tool_calls": []map[string]interface{}{
{ {
"id": "call_abc123", "id": "call_abc123",
"type": "function", "type": "function",
"function": map[string]interface{}{ "function": map[string]interface{}{
"name": "get_weather", "name": "get_weather",
"arguments": `{"location":"San Francisco","unit":"celsius"}`, "arguments": `{"location":"San Francisco","unit":"celsius"}`,
}, },
}, },
@@ -372,10 +372,10 @@ func TestToolCallMultiTurn(t *testing.T) {
"content": nil, "content": nil,
"tool_calls": []map[string]interface{}{ "tool_calls": []map[string]interface{}{
{ {
"id": "call_abc123", "id": "call_abc123",
"type": "function", "type": "function",
"function": map[string]interface{}{ "function": map[string]interface{}{
"name": "get_weather", "name": "get_weather",
"arguments": `{"location":"San Francisco"}`, "arguments": `{"location":"San Francisco"}`,
}, },
}, },
@@ -430,7 +430,10 @@ func TestToolCallMultiTurn(t *testing.T) {
} }
body1, _ := json.Marshal(turn1) body1, _ := json.Marshal(turn1)
resp1, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", bytes.NewReader(body1)) resp1, err := http.Post(server.URL+"/v1/chat/completions", "application/json", bytes.NewReader(body1))
if err != nil {
t.Fatalf("request failed: %v", err)
}
var turn1Resp map[string]interface{} var turn1Resp map[string]interface{}
json.NewDecoder(resp1.Body).Decode(&turn1Resp) json.NewDecoder(resp1.Body).Decode(&turn1Resp)
resp1.Body.Close() resp1.Body.Close()
@@ -472,7 +475,10 @@ func TestToolCallMultiTurn(t *testing.T) {
} }
body2, _ := json.Marshal(turn2) body2, _ := json.Marshal(turn2)
resp2, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", bytes.NewReader(body2)) resp2, err := http.Post(server.URL+"/v1/chat/completions", "application/json", bytes.NewReader(body2))
if err != nil {
t.Fatalf("request failed: %v", err)
}
var turn2Resp map[string]interface{} var turn2Resp map[string]interface{}
json.NewDecoder(resp2.Body).Decode(&turn2Resp) json.NewDecoder(resp2.Body).Decode(&turn2Resp)
resp2.Body.Close() resp2.Body.Close()
@@ -503,7 +509,7 @@ func TestParallelToolCalls(t *testing.T) {
"content": nil, "content": nil,
"tool_calls": []map[string]interface{}{ "tool_calls": []map[string]interface{}{
{ {
"id": "call_1", "id": "call_1",
"type": "function", "type": "function",
"function": map[string]interface{}{ "function": map[string]interface{}{
"name": "get_weather", "name": "get_weather",
@@ -511,7 +517,7 @@ func TestParallelToolCalls(t *testing.T) {
}, },
}, },
{ {
"id": "call_2", "id": "call_2",
"type": "function", "type": "function",
"function": map[string]interface{}{ "function": map[string]interface{}{
"name": "get_weather", "name": "get_weather",
@@ -519,7 +525,7 @@ func TestParallelToolCalls(t *testing.T) {
}, },
}, },
{ {
"id": "call_3", "id": "call_3",
"type": "function", "type": "function",
"function": map[string]interface{}{ "function": map[string]interface{}{
"name": "get_weather", "name": "get_weather",
@@ -576,7 +582,10 @@ func TestParallelToolCalls(t *testing.T) {
} }
body, _ := json.Marshal(request) body, _ := json.Marshal(request)
resp, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", bytes.NewReader(body)) resp, err := http.Post(server.URL+"/v1/chat/completions", "application/json", bytes.NewReader(body))
if err != nil {
t.Fatalf("request failed: %v", err)
}
var respData map[string]interface{} var respData map[string]interface{}
json.NewDecoder(resp.Body).Decode(&respData) json.NewDecoder(resp.Body).Decode(&respData)
resp.Body.Close() resp.Body.Close()
@@ -627,9 +636,9 @@ func TestAnthropicToolUse(t *testing.T) {
// Anthropic response format with tool_use block // Anthropic response format with tool_use block
response := map[string]interface{}{ response := map[string]interface{}{
"id": "msg_123", "id": "msg_123",
"type": "message", "type": "message",
"role": "assistant", "role": "assistant",
"content": []map[string]interface{}{ "content": []map[string]interface{}{
{ {
"type": "text", "type": "text",
@@ -714,7 +723,10 @@ func TestAnthropicToolUse(t *testing.T) {
body, _ := json.Marshal(anthropicRequest) body, _ := json.Marshal(anthropicRequest)
// Note: For now we route through a generic path // Note: For now we route through a generic path
// In Phase 2.9+, this would be integrated with the Anthropic dialect handler // In Phase 2.9+, this would be integrated with the Anthropic dialect handler
resp, _ := http.Post(server.URL+"/v1/messages", "application/json", bytes.NewReader(body)) resp, err := http.Post(server.URL+"/v1/messages", "application/json", bytes.NewReader(body))
if err != nil {
t.Fatalf("request failed: %v", err)
}
var respData map[string]interface{} var respData map[string]interface{}
json.NewDecoder(resp.Body).Decode(&respData) json.NewDecoder(resp.Body).Decode(&respData)
resp.Body.Close() resp.Body.Close()
@@ -762,7 +774,7 @@ func TestComplexToolArguments(t *testing.T) {
"content": nil, "content": nil,
"tool_calls": []map[string]interface{}{ "tool_calls": []map[string]interface{}{
{ {
"id": "call_complex", "id": "call_complex",
"type": "function", "type": "function",
"function": map[string]interface{}{ "function": map[string]interface{}{
"name": "create_event", "name": "create_event",
@@ -832,7 +844,10 @@ func TestComplexToolArguments(t *testing.T) {
} }
body, _ := json.Marshal(request) body, _ := json.Marshal(request)
resp, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", bytes.NewReader(body)) resp, err := http.Post(server.URL+"/v1/chat/completions", "application/json", bytes.NewReader(body))
if err != nil {
t.Fatalf("request failed: %v", err)
}
var respData map[string]interface{} var respData map[string]interface{}
json.NewDecoder(resp.Body).Decode(&respData) json.NewDecoder(resp.Body).Decode(&respData)
resp.Body.Close() resp.Body.Close()
+32 -8
View File
@@ -134,11 +134,14 @@ func TestUnknownModelEnumeratesValidModels(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/chat/completions", server.URL+"/v1/chat/completions",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"unknown","messages":[]}`)), bytes.NewReader([]byte(`{"model":"unknown","messages":[]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
var prob map[string]interface{} var prob map[string]interface{}
@@ -188,11 +191,14 @@ func TestMissingModelFieldReturns4xx(t *testing.T) {
defer server.Close() defer server.Close()
// Request with no model field // Request with no model field
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/chat/completions", server.URL+"/v1/chat/completions",
"application/json", "application/json",
bytes.NewReader([]byte(`{"messages":[]}`)), bytes.NewReader([]byte(`{"messages":[]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode < 400 || resp.StatusCode >= 500 { if resp.StatusCode < 400 || resp.StatusCode >= 500 {
@@ -230,11 +236,14 @@ func TestNullModelFieldReturns4xx(t *testing.T) {
defer server.Close() defer server.Close()
// Request with null model // Request with null model
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/chat/completions", server.URL+"/v1/chat/completions",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":null,"messages":[]}`)), bytes.NewReader([]byte(`{"model":null,"messages":[]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode < 400 || resp.StatusCode >= 500 { if resp.StatusCode < 400 || resp.StatusCode >= 500 {
@@ -266,11 +275,14 @@ func TestEmptyModelFieldReturns4xx(t *testing.T) {
defer server.Close() defer server.Close()
// Request with empty model string // Request with empty model string
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/chat/completions", server.URL+"/v1/chat/completions",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"","messages":[]}`)), bytes.NewReader([]byte(`{"model":"","messages":[]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode < 400 || resp.StatusCode >= 500 { if resp.StatusCode < 400 || resp.StatusCode >= 500 {
@@ -297,11 +309,14 @@ func TestInvalidJSONIsDistinguishableError(t *testing.T) {
defer server.Close() defer server.Close()
// Request with invalid JSON // Request with invalid JSON
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/chat/completions", server.URL+"/v1/chat/completions",
"application/json", "application/json",
bytes.NewReader([]byte(`not json`)), bytes.NewReader([]byte(`not json`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode < 400 || resp.StatusCode >= 500 { if resp.StatusCode < 400 || resp.StatusCode >= 500 {
@@ -405,19 +420,25 @@ func TestMissingModelAndUnknownModelBothReturn4xx(t *testing.T) {
defer server.Close() defer server.Close()
// Test missing model // Test missing model
resp1, _ := http.Post( resp1, err := http.Post(
server.URL+"/v1/chat/completions", server.URL+"/v1/chat/completions",
"application/json", "application/json",
bytes.NewReader([]byte(`{"messages":[]}`)), bytes.NewReader([]byte(`{"messages":[]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp1.Body.Close() resp1.Body.Close()
// Test unknown model // Test unknown model
resp2, _ := http.Post( resp2, err := http.Post(
server.URL+"/v1/chat/completions", server.URL+"/v1/chat/completions",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"unknown","messages":[]}`)), bytes.NewReader([]byte(`{"model":"unknown","messages":[]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp2.Body.Close() resp2.Body.Close()
// Both should be in 4xx range // Both should be in 4xx range
@@ -460,11 +481,14 @@ func TestProblemDetailHasRequiredFields(t *testing.T) {
server := httptest.NewServer(handler) server := httptest.NewServer(handler)
defer server.Close() defer server.Close()
resp, _ := http.Post( resp, err := http.Post(
server.URL+"/v1/chat/completions", server.URL+"/v1/chat/completions",
"application/json", "application/json",
bytes.NewReader([]byte(`{"model":"unknown","messages":[]}`)), bytes.NewReader([]byte(`{"model":"unknown","messages":[]}`)),
) )
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close() defer resp.Body.Close()
var prob map[string]interface{} var prob map[string]interface{}