import json
import socket
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from typing import Optional
import pytest
try:
from openai import OpenAI HAVE_OPENAI = True
except Exception:
HAVE_OPENAI = False
def _pick_free_port() -> int:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind(("127.0.0.1", 0))
return s.getsockname()[1]
class _MockResponsesHandler(BaseHTTPRequestHandler):
server_version = "MockResponses/0.1"
def do_POST(self):
if not self.path.endswith("/responses"):
self.send_response(404)
self.end_headers()
return
length = int(self.headers.get("Content-Length", "0"))
body = self.rfile.read(length) if length > 0 else b"{}"
try:
req_json = json.loads(body.decode("utf-8"))
except Exception:
req_json = None
auth = self.headers.get("Authorization", "")
auth_header_present = auth.startswith("Bearer ")
resp_json = {
"id": "resp_mock_123",
"object": "response",
"model": req_json.get("model") if isinstance(req_json, dict) else "unknown",
"output": [
{
"type": "message",
"role": "assistant",
"content": [
{"type": "output_text", "text": "ok (mock)"}
],
}
],
"mock": True,
"auth_header_present": auth_header_present,
"echo": req_json,
}
resp_bytes = json.dumps(resp_json).encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(resp_bytes)))
self.end_headers()
self.wfile.write(resp_bytes)
def log_message(self, fmt, *args):
return
class _MockServer:
def __init__(self):
self._httpd: Optional[ThreadingHTTPServer] = None
self._thread: Optional[threading.Thread] = None
self.host = "127.0.0.1"
self.port = 0
def start(self):
self._httpd = ThreadingHTTPServer((self.host, 0), _MockResponsesHandler)
self.port = self._httpd.server_address[1]
self._thread = threading.Thread(target=self._httpd.serve_forever, daemon=True)
self._thread.start()
def stop(self):
if self._httpd:
try:
self._httpd.shutdown()
except Exception:
pass
try:
self._httpd.server_close()
except Exception:
pass
if self._thread:
try:
self._thread.join(timeout=5.0)
except Exception:
pass
@pytest.mark.skipif(not HAVE_OPENAI, reason="openai package not installed")
@pytest.mark.timeout(30)
def test_openai_responses_create_non_streaming_to_mock():
mock = _MockServer()
mock.start()
try:
base_url = f"http://127.0.0.1:{mock.port}/v1"
client = OpenAI(base_url=base_url, api_key="sk-test")
raw_supported = hasattr(client.responses, "with_raw_response")
if raw_supported:
resp = client.responses.with_raw_response.create(
model="gpt-4o-mini",
input="Hello via OpenAI client (mock)",
)
assert hasattr(resp, "status_code"), "raw response missing status_code"
assert resp.status_code == 200
if hasattr(resp, "parse"):
obj = resp.parse()
if hasattr(obj, "model_dump"):
data = obj.model_dump()
elif hasattr(obj, "to_dict"):
data = obj.to_dict()
elif hasattr(obj, "dict"):
data = obj.dict()
elif hasattr(obj, "model_dump_json"):
data = json.loads(obj.model_dump_json())
else:
data = json.loads(json.dumps(obj, default=lambda o: getattr(o, "__dict__", str(o))))
else:
raw = resp.read()
text = raw.decode("utf-8") if isinstance(raw, (bytes, bytearray)) else str(raw)
data = json.loads(text)
else:
obj = client.responses.create(
model="gpt-4o-mini",
input="Hello via OpenAI client (mock)",
)
if hasattr(obj, "model_dump"):
data = obj.model_dump()
elif hasattr(obj, "to_dict"):
data = obj.to_dict()
elif hasattr(obj, "dict"):
data = obj.dict() else:
if hasattr(obj, "model_dump_json"):
data = json.loads(obj.model_dump_json())
else:
data = json.loads(json.dumps(obj, default=lambda o: getattr(o, "__dict__", str(o))))
assert data.get("mock") is True
assert data.get("auth_header_present") is True
assert data.get("object") == "response"
assert data.get("model") == "gpt-4o-mini"
assert isinstance(data.get("output"), list)
assert data.get("echo", {}).get("input") == "Hello via OpenAI client (mock)"
finally:
mock.stop()