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
ornithCalled = false
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()
if !reasoningCalled {
@@ -151,7 +154,10 @@ func TestBodyPreservedUnmodified(t *testing.T) {
// Send a request with specific body content
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()
if string(receivedBody) != originalBody {
@@ -249,7 +255,10 @@ func TestUnknownModelReject(t *testing.T) {
defer server.Close()
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()
if resp.StatusCode != http.StatusBadRequest {
@@ -300,7 +309,10 @@ func TestMissingModelField(t *testing.T) {
defer server.Close()
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()
if resp.StatusCode != http.StatusBadRequest {
+4 -1
View File
@@ -323,7 +323,10 @@ func TestBodySizeCapRejectionLogged(t *testing.T) {
// Send an oversized body
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()
// Verify rejection status
+36 -9
View File
@@ -45,11 +45,14 @@ func TestEmbeddingsPassthroughNoRewrite(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/embeddings",
"application/json",
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()
if !embeddingsCalled {
@@ -91,11 +94,14 @@ func TestEmbeddingsResponsePassthrough(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/embeddings",
"application/json",
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()
body, _ := io.ReadAll(resp.Body)
@@ -135,11 +141,14 @@ func TestRerankPathRewrite(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/rerank",
"application/json",
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()
// Verify path IS rewritten to /rerank
@@ -177,11 +186,14 @@ func TestRerankResponsePassthrough(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/rerank",
"application/json",
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()
body, _ := io.ReadAll(resp.Body)
@@ -209,11 +221,14 @@ func TestEmbeddingsUnknownModel(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/embeddings",
"application/json",
bytes.NewReader([]byte(`{"model":"unknown-embeddings","input":"test"}`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusBadRequest {
@@ -244,11 +259,14 @@ func TestRerankerUnknownModel(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/rerank",
"application/json",
bytes.NewReader([]byte(`{"model":"unknown-reranker","query":"q","texts":["a"]}`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusBadRequest {
@@ -288,11 +306,14 @@ func TestEmbeddingsBodyForwarded(t *testing.T) {
defer server.Close()
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",
"application/json",
bytes.NewReader([]byte(originalBody)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp.Body.Close()
// The received body should match the original (though may have different formatting)
@@ -337,11 +358,14 @@ func TestRerankerBodyForwarded(t *testing.T) {
defer server.Close()
originalBody := `{"model":"BAAI/bge-reranker-base","query":"test","texts":["a","b","c"]}`
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/rerank",
"application/json",
bytes.NewReader([]byte(originalBody)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp.Body.Close()
var orig, received map[string]interface{}
@@ -380,11 +404,14 @@ func TestUpstreamErrorStatusSurfaced(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/embeddings",
"application/json",
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()
if resp.StatusCode != http.StatusInternalServerError {
+36 -9
View File
@@ -74,7 +74,10 @@ func TestModelsEndpointContentType(t *testing.T) {
server := httptest.NewServer(handler)
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()
ct := resp.Header.Get("Content-Type")
@@ -101,7 +104,10 @@ func TestModelsEndpointResponseShape(t *testing.T) {
server := httptest.NewServer(handler)
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()
var result ModelListResponse
@@ -161,7 +167,10 @@ func TestModelsEndpointEnumeratesAllModels(t *testing.T) {
server := httptest.NewServer(handler)
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()
var result ModelListResponse
@@ -211,7 +220,10 @@ func TestModelsEndpointHasRequiredFields(t *testing.T) {
server := httptest.NewServer(handler)
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()
var result ModelListResponse
@@ -292,7 +304,10 @@ func TestModelsEndpointDerivedFromConfig(t *testing.T) {
server := httptest.NewServer(handler)
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()
var result ModelListResponse
@@ -347,18 +362,24 @@ func TestModelsEndpointConsistentWithDispatch(t *testing.T) {
defer server.Close()
// 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
json.NewDecoder(resp.Body).Decode(&result)
resp.Body.Close()
// Try to dispatch to each advertised model
for _, model := range result.Data {
dispatchResp, _ := http.Post(
dispatchResp, err := http.Post(
server.URL+"/v1/chat/completions",
"application/json",
strings.NewReader(`{"model":"`+model.ID+`","messages":[]}`),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer dispatchResp.Body.Close()
// Should not return 400 (unknown model error)
@@ -394,14 +415,20 @@ func TestModelsEndpointResponseIsConsistent(t *testing.T) {
defer server.Close()
// 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
json.NewDecoder(resp1.Body).Decode(&result1)
resp1.Body.Close()
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
json.NewDecoder(resp2.Body).Decode(&result2)
resp2.Body.Close()
+7 -2
View File
@@ -105,7 +105,9 @@ func TestProxyPathRewrite(t *testing.T) {
server := httptest.NewServer(handler)
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 {
t.Fatalf("request failed: %v", err)
}
@@ -402,7 +404,10 @@ func TestProxyPreservesBody(t *testing.T) {
defer server.Close()
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()
if receivedBody != testBody {
+4 -1
View File
@@ -102,7 +102,10 @@ func TestReadTimeout(t *testing.T) {
defer server.Close()
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)
// Should timeout around the read timeout (with some tolerance)
+20 -5
View File
@@ -430,7 +430,10 @@ func TestToolCallMultiTurn(t *testing.T) {
}
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{}
json.NewDecoder(resp1.Body).Decode(&turn1Resp)
resp1.Body.Close()
@@ -472,7 +475,10 @@ func TestToolCallMultiTurn(t *testing.T) {
}
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{}
json.NewDecoder(resp2.Body).Decode(&turn2Resp)
resp2.Body.Close()
@@ -576,7 +582,10 @@ func TestParallelToolCalls(t *testing.T) {
}
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{}
json.NewDecoder(resp.Body).Decode(&respData)
resp.Body.Close()
@@ -714,7 +723,10 @@ func TestAnthropicToolUse(t *testing.T) {
body, _ := json.Marshal(anthropicRequest)
// Note: For now we route through a generic path
// 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{}
json.NewDecoder(resp.Body).Decode(&respData)
resp.Body.Close()
@@ -832,7 +844,10 @@ func TestComplexToolArguments(t *testing.T) {
}
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{}
json.NewDecoder(resp.Body).Decode(&respData)
resp.Body.Close()
+32 -8
View File
@@ -134,11 +134,14 @@ func TestUnknownModelEnumeratesValidModels(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/chat/completions",
"application/json",
bytes.NewReader([]byte(`{"model":"unknown","messages":[]}`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
var prob map[string]interface{}
@@ -188,11 +191,14 @@ func TestMissingModelFieldReturns4xx(t *testing.T) {
defer server.Close()
// Request with no model field
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/chat/completions",
"application/json",
bytes.NewReader([]byte(`{"messages":[]}`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode < 400 || resp.StatusCode >= 500 {
@@ -230,11 +236,14 @@ func TestNullModelFieldReturns4xx(t *testing.T) {
defer server.Close()
// Request with null model
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/chat/completions",
"application/json",
bytes.NewReader([]byte(`{"model":null,"messages":[]}`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode < 400 || resp.StatusCode >= 500 {
@@ -266,11 +275,14 @@ func TestEmptyModelFieldReturns4xx(t *testing.T) {
defer server.Close()
// Request with empty model string
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/chat/completions",
"application/json",
bytes.NewReader([]byte(`{"model":"","messages":[]}`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode < 400 || resp.StatusCode >= 500 {
@@ -297,11 +309,14 @@ func TestInvalidJSONIsDistinguishableError(t *testing.T) {
defer server.Close()
// Request with invalid JSON
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/chat/completions",
"application/json",
bytes.NewReader([]byte(`not json`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode < 400 || resp.StatusCode >= 500 {
@@ -405,19 +420,25 @@ func TestMissingModelAndUnknownModelBothReturn4xx(t *testing.T) {
defer server.Close()
// Test missing model
resp1, _ := http.Post(
resp1, err := http.Post(
server.URL+"/v1/chat/completions",
"application/json",
bytes.NewReader([]byte(`{"messages":[]}`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp1.Body.Close()
// Test unknown model
resp2, _ := http.Post(
resp2, err := http.Post(
server.URL+"/v1/chat/completions",
"application/json",
bytes.NewReader([]byte(`{"model":"unknown","messages":[]}`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
resp2.Body.Close()
// Both should be in 4xx range
@@ -460,11 +481,14 @@ func TestProblemDetailHasRequiredFields(t *testing.T) {
server := httptest.NewServer(handler)
defer server.Close()
resp, _ := http.Post(
resp, err := http.Post(
server.URL+"/v1/chat/completions",
"application/json",
bytes.NewReader([]byte(`{"model":"unknown","messages":[]}`)),
)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
var prob map[string]interface{}