SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
5.4 KB · 97 lines python
Raw Blame History
1"""Cheap deliberate-error smoke tests for the OpenAI API (all requests are rejected before any generation => $0).2Also unit-tests examples/shared/errors/classify_error.py against bodies captured live on 2026-09-18.3Run: .venv/bin/pytest -q tests/openai/test_errors.py4"""5from __future__ import annotations67import sys8from pathlib import Path910import pytest1112ROOT = Path(__file__).resolve().parents[2]13sys.path.insert(0, str(ROOT / "examples/shared/errors"))14from classify_error import classify  # noqa: E402151617def _err(body):18    assert isinstance(body, dict) and "error" in body, body19    return body["error"]202122def test_invalid_api_key_401(openai):23    st, body, _ = openai("GET", "/v1/models", extra_headers={"Authorization": "Bearer sk-invalid"}, note="test_errors invalid key")24    assert st == 40125    e = _err(body)26    assert e["code"] == "invalid_api_key" and e["type"] == "invalid_request_error"27    assert classify("openai", st, body).category == "auth"282930def test_model_not_found_404(openai):31    st, body, _ = openai("POST", "/v1/responses", {"model": "does-not-exist-model", "input": "Reply with OK.", "max_output_tokens": 16}, note="test_errors model_not_found")32    assert st == 404 and _err(body)["code"] == "model_not_found"33    c = classify("openai", st, body)34    assert c.category == "not_found" and not c.retryable353637def test_invalid_type_400(openai):38    st, body, _ = openai("POST", "/v1/responses", {"model": "gpt-5.4-nano", "input": "Reply with OK.", "max_output_tokens": "sixteen"}, note="test_errors invalid_type")39    assert st == 400 and _err(body)["code"] == "invalid_type" and _err(body)["param"] == "max_output_tokens"404142def test_missing_required_parameter_400(openai):43    st, body, _ = openai("POST", "/v1/responses", {"input": "Reply with OK."}, note="test_errors missing model")44    assert st == 400 and _err(body)["code"] == "missing_required_parameter" and _err(body)["param"] == "model"454647def test_invalid_json_400(openai):48    st, body, _ = openai("POST", "/v1/responses", data=b'{"model": ', note="test_errors invalid json")49    assert st == 400 and _err(body)["code"] == "invalid_json"505152def test_unknown_url_404_has_empty_body(openai):53    st, body, hdrs = openai("GET", "/v1/this_endpoint_does_not_exist", note="test_errors unknown url")54    assert st == 40455    assert body in (b"", "", None) or body == b""56    assert not any(k.lower() == "x-request-id" for k in hdrs)  # edge 404: no request id57    assert classify("openai", st, body, hdrs).category == "not_found"585960def test_response_not_found_404(openai):61    st, body, _ = openai("GET", "/v1/responses/resp_000000000000000000000000000000", note="test_errors response 404")62    assert st == 404 and _err(body)["type"] == "invalid_request_error"636465def test_admin_scope_403_bare_string(openai):66    """Admin endpoints answer 403 with `error` as a bare string when the key lacks api.management.read."""67    st, body, _ = openai("GET", "/v1/organization/projects?limit=1", note="test_errors admin 403 shape")68    if st == 200:69        pytest.skip("an Admin key is configured; restriction not reproducible")70    assert st == 403 and isinstance(body["error"], str) and "Missing scopes" in body["error"]71    c = classify("openai", st, body)72    assert c.category == "permission" and not c.retryable737475# ---------------- offline classifier matrix (captured shapes) ----------------76@pytest.mark.parametrize("status,body,category,retryable", [77    (401, {"error": {"message": "Incorrect API key provided", "type": "invalid_request_error", "param": None, "code": "invalid_api_key"}}, "auth", False),78    (403, {"error": "You have insufficient permissions for this operation. Missing scopes: api.management.read."}, "permission", False),79    (403, {"error": {"message": "blocked", "type": "invalid_request_error", "param": None, "code": "misalignment_policy_violation"}}, "safety", False),80    (404, {"error": {"message": "The model `x` does not exist", "type": "invalid_request_error", "param": None, "code": "model_not_found"}}, "not_found", False),81    (404, b"", "not_found", False),82    (400, {"error": {"message": "Unknown parameter: 'x'.", "type": "invalid_request_error", "param": "x", "code": "unknown_parameter"}}, "bad_request", False),83    (422, {"error": {"message": "unprocessable", "type": "invalid_request_error", "param": None, "code": None}}, "bad_request", True),84    (429, {"error": {"message": "Rate limit reached", "type": "rate_limit_error", "param": None, "code": "rate_limit_exceeded"}}, "rate_limit", True),85    (429, {"error": {"message": "slow down", "type": "rate_limit_error", "param": None, "code": "slow_down"}}, "rate_limit", True),86    (429, {"error": {"message": "quota", "type": "insufficient_quota", "param": None, "code": "insufficient_quota"}}, "quota_billing", False),87    (429, {"error": {"message": "spend", "type": "insufficient_quota", "param": None, "code": "project_spend_limit_exceeded"}}, "quota_billing", False),88    (500, {"error": {"message": "server had an error", "type": "server_error", "param": None, "code": None}}, "server", True),89    (503, {"error": {"message": "overloaded", "type": "service_unavailable_error", "param": None, "code": "server_is_overloaded"}}, "server", True),90    (None, None, "network", True),91])92def test_classifier_matrix(status, body, category, retryable):93    c = classify("openai", status, body, {"retry-after": "3", "x-request-id": "req_x"})94    assert (c.category, c.retryable) == (category, retryable)95    assert c.retry_after == 3.0 and c.request_id == "req_x"96    assert 3.0 <= c.backoff(1) <= 3.397