feat(api): improve verbose error logging for OpenAI connection errors

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-02-23 18:28:49 +00:00
parent cc555c2fb6
commit b9b9456310
2 changed files with 226 additions and 6 deletions
+146 -5
View File
@@ -62,34 +62,143 @@ class TestOpenAIConnectionErrors:
@patch("app.api.openai.settings")
def test_openai_api_key_validation_auth_error(self, mock_settings, mock_openai_class, client):
"""Test OpenAI API key validation with auth error."""
import openai as openai_module
mock_settings.openai_api_key = "sk-invalid-key"
mock_client = MagicMock()
mock_client.models.list.side_effect = Exception("Incorrect API key")
auth_exc = openai_module.AuthenticationError(
message="Incorrect API key provided",
response=MagicMock(status_code=401, headers={}),
body={"error": {"message": "Incorrect API key provided"}},
)
mock_client.models.list.side_effect = auth_exc
mock_openai_class.return_value = mock_client
response = client.get("/api/openai/test")
data = response.json()
assert data["status"] == "error"
assert "api key" in data["message"].lower() or "validation failed" in data["message"].lower()
assert data.get("is_auth_error") is True
assert data.get("error_type") == "authentication_error"
@patch("openai.OpenAI")
@patch("app.api.openai.settings")
def test_openai_api_key_validation_network_error(self, mock_settings, mock_openai_class, client):
"""Test OpenAI API key validation with network error."""
"""Test OpenAI API key validation with network/connection error."""
import openai as openai_module
mock_settings.openai_api_key = "sk-test-key"
mock_client = MagicMock()
mock_client.models.list.side_effect = Exception("Network timeout")
conn_exc = openai_module.APIConnectionError(request=MagicMock())
mock_client.models.list.side_effect = conn_exc
mock_openai_class.return_value = mock_client
response = client.get("/api/openai/test")
data = response.json()
assert data["status"] == "error"
# Not an auth error, so is_auth_error should be False
assert data.get("is_auth_error") is False
assert data.get("error_type") == "connection_error"
assert "connection error" in data["message"].lower()
@patch("openai.OpenAI")
@patch("app.api.openai.settings")
def test_openai_api_connection_error_with_dns_cause(self, mock_settings, mock_openai_class, client):
"""Test that DNS resolution failures are surfaced in the connection error message."""
import openai as openai_module
mock_settings.openai_api_key = "sk-test-key"
dns_err = OSError("[Errno -2] Name or service not known")
conn_exc = openai_module.APIConnectionError(request=MagicMock())
conn_exc.__cause__ = dns_err
mock_client = MagicMock()
mock_client.models.list.side_effect = conn_exc
mock_openai_class.return_value = mock_client
response = client.get("/api/openai/test")
data = response.json()
assert data["status"] == "error"
assert data.get("error_type") == "connection_error"
# The DNS detail should be propagated to the message
assert "name or service not known" in data["message"].lower()
@patch("openai.OpenAI")
@patch("app.api.openai.settings")
def test_openai_api_timeout_error(self, mock_settings, mock_openai_class, client):
"""Test OpenAI API key validation with timeout error."""
import openai as openai_module
mock_settings.openai_api_key = "sk-test-key"
mock_client = MagicMock()
timeout_exc = openai_module.APITimeoutError(request=MagicMock())
mock_client.models.list.side_effect = timeout_exc
mock_openai_class.return_value = mock_client
response = client.get("/api/openai/test")
data = response.json()
assert data["status"] == "error"
assert data.get("is_auth_error") is False
assert data.get("error_type") == "timeout"
assert "timed out" in data["message"].lower()
@patch("openai.OpenAI")
@patch("app.api.openai.settings")
def test_openai_api_status_error(self, mock_settings, mock_openai_class, client):
"""Test OpenAI API returning an unexpected HTTP status code."""
import openai as openai_module
mock_settings.openai_api_key = "sk-test-key"
mock_response = MagicMock()
mock_response.status_code = 500
mock_response.headers = {"x-request-id": "test-req-id"}
status_exc = openai_module.InternalServerError(
message="Internal Server Error",
response=mock_response,
body={"error": {"message": "Internal Server Error"}},
)
mock_client = MagicMock()
mock_client.models.list.side_effect = status_exc
mock_openai_class.return_value = mock_client
response = client.get("/api/openai/test")
data = response.json()
assert data["status"] == "error"
assert data.get("error_type") == "api_status_error"
assert data.get("http_status") == 500
@patch("openai.OpenAI")
@patch("app.api.openai.settings")
def test_openai_api_rate_limit_error(self, mock_settings, mock_openai_class, client):
"""Test OpenAI API returning a rate-limit error."""
import openai as openai_module
mock_settings.openai_api_key = "sk-test-key"
mock_response = MagicMock()
mock_response.status_code = 429
mock_response.headers = {}
rate_exc = openai_module.RateLimitError(
message="Rate limit exceeded",
response=mock_response,
body={"error": {"message": "Rate limit exceeded"}},
)
mock_client = MagicMock()
mock_client.models.list.side_effect = rate_exc
mock_openai_class.return_value = mock_client
response = client.get("/api/openai/test")
data = response.json()
assert data["status"] == "error"
assert data.get("error_type") == "rate_limit"
assert data.get("is_auth_error") is False
@patch("app.api.openai.settings")
@@ -138,3 +247,35 @@ class TestOpenAIConnectionErrors:
assert data["status"] == "error"
assert "unexpected error" in data["message"].lower()
@patch("openai.OpenAI")
@patch("app.api.openai.settings")
def test_openai_generic_error_still_detects_auth(self, mock_settings, mock_openai_class, client):
"""Test that generic exception fallback still detects auth-related errors."""
mock_settings.openai_api_key = "sk-test-key"
mock_client = MagicMock()
mock_client.models.list.side_effect = Exception("Incorrect API key provided")
mock_openai_class.return_value = mock_client
response = client.get("/api/openai/test")
data = response.json()
assert data["status"] == "error"
assert data.get("is_auth_error") is True
@patch("openai.OpenAI")
@patch("app.api.openai.settings")
def test_openai_generic_network_error_not_auth(self, mock_settings, mock_openai_class, client):
"""Test that generic network errors are not flagged as auth errors."""
mock_settings.openai_api_key = "sk-test-key"
mock_client = MagicMock()
mock_client.models.list.side_effect = Exception("Network timeout")
mock_openai_class.return_value = mock_client
response = client.get("/api/openai/test")
data = response.json()
assert data["status"] == "error"
assert data.get("is_auth_error") is False