Skip to content

Commit 3af7469

Browse files
fix: address reviewer feedback - add error handling for invalid timeout env var
- Add try/catch for float() conversion to prevent ValueError crashes - Prevent real server spawning in unit tests via Thread.start mocking - Add test for invalid env var fallback behavior - Preserve other env vars during testing (avoid clear=True) Addresses feedback from Gemini, CodeRabbit, Qodo, and Copilot reviewers. Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
1 parent 98af1cd commit 3af7469

2 files changed

Lines changed: 72 additions & 38 deletions

File tree

src/praisonai-agents/praisonaiagents/agents/agents.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,11 @@ def run_server():
128128
thread.start()
129129

130130
# Check for configurable timeout via environment variable
131-
timeout = float(os.environ.get("PRAISONAI_SERVER_READY_TIMEOUT", "5.0"))
131+
try:
132+
timeout = float(os.environ.get("PRAISONAI_SERVER_READY_TIMEOUT", "5.0"))
133+
except ValueError:
134+
logger.warning("Invalid PRAISONAI_SERVER_READY_TIMEOUT value. Using default 5.0s.")
135+
timeout = 5.0
132136
became_ready = ready_event.wait(timeout=timeout)
133137

134138
if not became_ready:

src/praisonai-agents/tests/unit/agents/test_server_registry_timeout.py

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,16 @@ def test_server_readiness_timeout_emits_warning(caplog):
1818
with patch.dict(registry._apps, {8000: mock_app}):
1919
with patch.dict(registry._ready_events, {8000: threading.Event()}):
2020
with patch.dict(registry._started, {8000: False}):
21-
with caplog.at_level(logging.WARNING):
22-
# Use a very short timeout to ensure the test doesn't hang
23-
with patch.dict("os.environ", {"PRAISONAI_SERVER_READY_TIMEOUT": "0.1"}):
24-
result = registry.start_server_if_needed(8000, host="127.0.0.1")
25-
26-
# The method should still return True but log a warning
27-
assert result is True
28-
assert "8000" in caplog.text
29-
assert "did not become ready" in caplog.text.lower()
21+
with patch("threading.Thread.start"): # Prevent real server spawning
22+
with caplog.at_level(logging.WARNING):
23+
# Use a very short timeout to ensure the test doesn't hang
24+
with patch.dict("os.environ", {"PRAISONAI_SERVER_READY_TIMEOUT": "0.1"}):
25+
result = registry.start_server_if_needed(8000, host="127.0.0.1")
26+
27+
# The method should still return True but log a warning
28+
assert result is True
29+
assert "8000" in caplog.text
30+
assert "did not become ready" in caplog.text.lower()
3031

3132

3233
def test_server_readiness_timeout_configurable_via_env():
@@ -40,16 +41,17 @@ def test_server_readiness_timeout_configurable_via_env():
4041
with patch.dict(registry._apps, {8001: mock_app}):
4142
with patch.dict(registry._ready_events, {8001: threading.Event()}):
4243
with patch.dict(registry._started, {8001: False}):
43-
# Test with custom timeout
44-
with patch.dict("os.environ", {"PRAISONAI_SERVER_READY_TIMEOUT": "0.05"}):
45-
import time
46-
start_time = time.time()
47-
result = registry.start_server_if_needed(8001, host="127.0.0.1")
48-
duration = time.time() - start_time
49-
50-
# Should respect the custom timeout and complete quickly
51-
assert result is True
52-
assert duration < 1.0 # Should be much less than default 5s
44+
with patch("threading.Thread.start"): # Prevent real server spawning
45+
# Test with custom timeout
46+
with patch.dict("os.environ", {"PRAISONAI_SERVER_READY_TIMEOUT": "0.05"}):
47+
import time
48+
start_time = time.time()
49+
result = registry.start_server_if_needed(8001, host="127.0.0.1")
50+
duration = time.time() - start_time
51+
52+
# Should respect the custom timeout and complete quickly
53+
assert result is True
54+
assert duration < 1.0 # Should be much less than default 5s
5355

5456

5557
def test_server_readiness_success_no_warning(caplog):
@@ -64,15 +66,16 @@ def test_server_readiness_success_no_warning(caplog):
6466
with patch.dict(registry._apps, {8002: mock_app}):
6567
with patch.dict(registry._ready_events, {8002: ready_event}):
6668
with patch.dict(registry._started, {8002: False}):
67-
# Set the event immediately to simulate quick startup
68-
ready_event.set()
69-
70-
with caplog.at_level(logging.WARNING):
71-
result = registry.start_server_if_needed(8002, host="127.0.0.1")
72-
73-
# Should succeed without warnings
74-
assert result is True
75-
assert "did not become ready" not in caplog.text.lower()
69+
with patch("threading.Thread.start"): # Prevent real server spawning
70+
# Set the event immediately to simulate quick startup
71+
ready_event.set()
72+
73+
with caplog.at_level(logging.WARNING):
74+
result = registry.start_server_if_needed(8002, host="127.0.0.1")
75+
76+
# Should succeed without warnings
77+
assert result is True
78+
assert "did not become ready" not in caplog.text.lower()
7679

7780

7881
def test_default_timeout_value():
@@ -87,12 +90,39 @@ def test_default_timeout_value():
8790
with patch.dict(registry._apps, {8003: mock_app}):
8891
with patch.dict(registry._ready_events, {8003: ready_event}):
8992
with patch.dict(registry._started, {8003: False}):
90-
# Ensure no custom timeout is set
91-
with patch.dict("os.environ", {}, clear=True):
92-
with patch("threading.Event.wait") as mock_wait:
93-
mock_wait.return_value = False
94-
result = registry.start_server_if_needed(8003, host="127.0.0.1")
95-
96-
# Should have called wait with default timeout of 5.0
97-
mock_wait.assert_called_once_with(timeout=5.0)
98-
assert result is True
93+
with patch("threading.Thread.start"): # Prevent real server spawning
94+
# Ensure no custom timeout is set (but preserve other env vars)
95+
with patch.dict("os.environ", {"PRAISONAI_SERVER_READY_TIMEOUT": ""}, clear=False):
96+
with patch("threading.Event.wait") as mock_wait:
97+
mock_wait.return_value = False
98+
result = registry.start_server_if_needed(8003, host="127.0.0.1")
99+
100+
# Should have called wait with default timeout of 5.0
101+
mock_wait.assert_called_once_with(timeout=5.0)
102+
assert result is True
103+
104+
105+
def test_invalid_timeout_env_var_fallback(caplog):
106+
"""Test that invalid PRAISONAI_SERVER_READY_TIMEOUT falls back to default with warning."""
107+
registry = _AgentServerRegistry()
108+
109+
# Create a mock FastAPI app
110+
mock_app = MagicMock()
111+
ready_event = threading.Event()
112+
113+
# Register the app but don't set the ready event
114+
with patch.dict(registry._apps, {8004: mock_app}):
115+
with patch.dict(registry._ready_events, {8004: ready_event}):
116+
with patch.dict(registry._started, {8004: False}):
117+
with patch("threading.Thread.start"): # Prevent real server spawning
118+
# Test with invalid timeout value
119+
with patch.dict("os.environ", {"PRAISONAI_SERVER_READY_TIMEOUT": "invalid"}):
120+
with caplog.at_level(logging.WARNING):
121+
with patch("threading.Event.wait") as mock_wait:
122+
mock_wait.return_value = False
123+
result = registry.start_server_if_needed(8004, host="127.0.0.1")
124+
125+
# Should have fallen back to 5.0 and logged warning
126+
mock_wait.assert_called_once_with(timeout=5.0)
127+
assert result is True
128+
assert "Invalid PRAISONAI_SERVER_READY_TIMEOUT" in caplog.text

0 commit comments

Comments
 (0)