feat(phase2): complete openai api surfaces 2.3-2.7
- 2.3: unknown model errors (400 + RFC 9457 problem+json with valid_models) - 2.5: GET /v1/models endpoint (derived from config, not hardcoded) - 2.6: POST /v1/embeddings passthrough (body-based dispatch, no rewrite) - 2.7: POST /v1/rerank with path rewrite (/v1/rerank → /rerank) - wire proxy.Handler in main.go (was using dummy handler) - 140+ tests passing, race detector clean - all requests: client → nginx → gateway → upstreams - ready for config deployment to go live
This commit is contained in:
@@ -223,7 +223,7 @@ func TestStreamingUnbuffered(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestUnknownModelReject verifies that unknown models are rejected.
|
||||
// TestUnknownModelReject verifies that unknown models are rejected with 400 and problem+json.
|
||||
func TestUnknownModelReject(t *testing.T) {
|
||||
upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
@@ -250,14 +250,31 @@ func TestUnknownModelReject(t *testing.T) {
|
||||
|
||||
requestBody := `{"model":"unknown-model","messages":[]}`
|
||||
resp, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(requestBody))
|
||||
resp.Body.Close()
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
t.Errorf("expected 404 for unknown model, got %d", resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusBadRequest {
|
||||
t.Errorf("expected 400 for unknown model, got %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Verify problem+json content type
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if !strings.Contains(ct, "application/problem+json") {
|
||||
t.Errorf("expected content-type application/problem+json, got %s", ct)
|
||||
}
|
||||
|
||||
// Verify response is valid JSON
|
||||
var prob map[string]interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&prob); err != nil {
|
||||
t.Errorf("response is not valid JSON: %v", err)
|
||||
}
|
||||
|
||||
// Verify valid_models is included
|
||||
if prob["valid_models"] == nil {
|
||||
t.Errorf("expected valid_models in problem detail")
|
||||
}
|
||||
}
|
||||
|
||||
// TestMissingModelField verifies that missing model field is rejected.
|
||||
// TestMissingModelField verifies that missing model field is rejected with 400 and problem+json.
|
||||
func TestMissingModelField(t *testing.T) {
|
||||
upstreamServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
@@ -284,10 +301,22 @@ func TestMissingModelField(t *testing.T) {
|
||||
|
||||
requestBody := `{"messages":[]}`
|
||||
resp, _ := http.Post(server.URL+"/v1/chat/completions", "application/json", strings.NewReader(requestBody))
|
||||
resp.Body.Close()
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
t.Errorf("expected 404 for missing model, got %d", resp.StatusCode)
|
||||
if resp.StatusCode != http.StatusBadRequest {
|
||||
t.Errorf("expected 400 for missing model, got %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Verify problem+json content type
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if !strings.Contains(ct, "application/problem+json") {
|
||||
t.Errorf("expected content-type application/problem+json, got %s", ct)
|
||||
}
|
||||
|
||||
// Verify response is valid JSON
|
||||
var prob map[string]interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&prob); err != nil {
|
||||
t.Errorf("response is not valid JSON: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user