Files
ss-tools/backend/tests/test_agent/test_run.py
busya ce0369ae5c test(backend): add 55+ test files to push coverage to 98%
Subagents delivered tests across all uncovered backend modules:

Schemas (100%): agent, auth, health, profile, settings, validation
Services (98-100%): auth, profile, health, llm, mapping, resource,
  security, git, superset_lookup, sql_table_extractor, rbac
API routes (new): auth, admin, health, environments, plugins,
  dashboards (helpers, projection, actions, listing),
  git (config, deps, env, helpers)
Clean Release (100%): DTO, facade, policy_engine, stages,
  repos, preparation, source_isolation, compliance
Git services: base, remote_providers
Agent module: app, run, middleware, langgraph_setup
Core: trace, cleanup, ws_log_handler, timezone, auth (config/oauth/security), matching
Reports: normalizer, report_service, type_profiles
Notifications: service, providers

Also:
- .gitignore: add .coverage, *.cover, coverage-* dirs
- src/schemas/auth.py: fix AD group DN regex (comma in CN=...)
- Remove co-located src/services/__tests__/ (caused pytest module collision)
2026-06-15 13:55:57 +03:00

129 lines
5.5 KiB
Python

# #region Test.AgentChat.Run [C:3] [TYPE Module] [SEMANTICS test,agent,run,entrypoint]
# @BRIEF Tests for agent/run.py — _find_free_port and _fetch_llm_config.
# @RELATION BINDS_TO -> [AgentChat.Run]
from pathlib import Path
import sys
sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))
import socket
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
# #region test_find_free_port [C:2] [TYPE Function]
# @BRIEF Test _find_free_port for port scanning behavior.
class TestFindFreePort:
def test_returns_free_port(self):
from src.agent.run import _find_free_port
with patch("socket.socket") as mock_socket:
mock_instance = MagicMock()
mock_socket.return_value.__enter__.return_value = mock_instance
result = _find_free_port(8000, 10)
assert result == 8000
mock_instance.bind.assert_called_once_with(("", 8000))
def test_skips_busy_ports(self):
from src.agent.run import _find_free_port
with patch("socket.socket") as mock_socket:
mock_instance = MagicMock()
mock_socket.return_value.__enter__.return_value = mock_instance
# Ports 8000-8002 busy, 8003 free
mock_instance.bind.side_effect = [
OSError("Address in use"), # 8000
OSError("Address in use"), # 8001
OSError("Address in use"), # 8002
None, # 8003 — success
]
result = _find_free_port(8000, 10)
assert result == 8003
assert mock_instance.bind.call_count == 4
def test_raises_when_all_busy(self):
from src.agent.run import _find_free_port
with patch("socket.socket") as mock_socket:
mock_instance = MagicMock()
mock_socket.return_value.__enter__.return_value = mock_instance
mock_instance.bind.side_effect = OSError("Address in use")
with pytest.raises(OSError, match="No free port found"):
_find_free_port(8000, 3)
assert mock_instance.bind.call_count == 3
# #endregion test_find_free_port
# #region test_fetch_llm_config [C:2] [TYPE Function]
# @BRIEF Test _fetch_llm_config with retry and fallback behavior.
class TestFetchLlmConfig:
def test_returns_config_on_success(self):
from src.agent.run import _fetch_llm_config
with patch("src.agent.run.httpx.get") as mock_get:
mock_response = MagicMock()
mock_response.json.return_value = {"configured": True, "provider_type": "openai", "default_model": "gpt-4o"}
mock_get.return_value = mock_response
result = _fetch_llm_config()
assert result is not None
assert result["configured"] is True
def test_returns_none_when_not_configured(self):
from src.agent.run import _fetch_llm_config
with patch("src.agent.run.httpx.get") as mock_get:
mock_response = MagicMock()
mock_response.json.return_value = {"configured": False, "reason": "no provider"}
mock_get.return_value = mock_response
result = _fetch_llm_config()
assert result is None
def test_retries_on_failure(self):
from src.agent.run import _fetch_llm_config
import time as time_module
with patch("src.agent.run.httpx.get") as mock_get, \
patch.object(time_module, "sleep") as mock_sleep:
mock_get.side_effect = Exception("Connection refused")
result = _fetch_llm_config()
assert result is None
assert mock_get.call_count == 6
def test_retries_then_returns_config(self):
from src.agent.run import _fetch_llm_config
import time as time_module
with patch("src.agent.run.httpx.get") as mock_get, \
patch.object(time_module, "sleep") as mock_sleep:
mock_get.side_effect = [
Exception("Timeout"), # Attempt 1
Exception("Timeout"), # Attempt 2
MagicMock(json=lambda: {"configured": True, "provider_type": "openai"}), # Attempt 3
]
result = _fetch_llm_config()
assert result is not None
assert result["configured"] is True
def test_returns_none_after_max_retries_with_http_error(self):
from src.agent.run import _fetch_llm_config
import time as time_module
with patch("src.agent.run.httpx.get") as mock_get, \
patch.object(time_module, "sleep") as mock_sleep:
mock_response = MagicMock()
mock_response.raise_for_status.side_effect = Exception("HTTP 500")
mock_get.return_value = mock_response
result = _fetch_llm_config()
assert result is None
assert mock_get.call_count == 6
def test_uses_service_token_header(self):
from src.agent.run import _fetch_llm_config
with patch("src.agent.run.httpx.get") as mock_get, \
patch("src.agent.run.os.getenv", return_value="test-token"):
mock_response = MagicMock()
mock_response.json.return_value = {"configured": True}
mock_get.return_value = mock_response
result = _fetch_llm_config()
assert result is not None
# Verify Authorization header was sent
call_kwargs = mock_get.call_args[1]
assert call_kwargs["headers"].get("Authorization") == "Bearer test-token"
# #endregion test_fetch_llm_config
# #endregion Test.AgentChat.Run