diff --git a/tests/test_ai_client_proxy.py b/tests/test_ai_client_proxy.py deleted file mode 100644 index 00800c3..0000000 --- a/tests/test_ai_client_proxy.py +++ /dev/null @@ -1,42 +0,0 @@ -import pytest -import threading -from unittest.mock import MagicMock, patch -from src.ai_client_proxy import AIProxyClient - - -def test_proxy_initialization(): - proxy = AIProxyClient() - assert proxy._status == "disconnected" - assert proxy._pending == {} - - -def test_proxy_status_property(): - proxy = AIProxyClient() - assert proxy.status in ("disconnected", "init", "ready", "busy", "error") - - -def test_proxy_status_reflects_internal_state(): - proxy = AIProxyClient() - assert proxy.status == "disconnected" - proxy._status = "ready" - assert proxy.status == "ready" - - -def test_send_command_without_server_returns_error(): - proxy = AIProxyClient() - proxy._status = "ready" - result = proxy.send_command("list_models", {"provider": "gemini"}) - assert "error" in result - - -def test_pending_dict_structure(): - proxy = AIProxyClient() - assert isinstance(proxy._pending, dict) - assert len(proxy._pending) == 0 - - -def test_stop_when_not_started(): - proxy = AIProxyClient() - proxy.stop() - assert proxy._status == "disconnected" - assert proxy._process is None \ No newline at end of file diff --git a/tests/test_ai_client_proxy_run.py b/tests/test_ai_client_proxy_run.py deleted file mode 100644 index 581feff..0000000 --- a/tests/test_ai_client_proxy_run.py +++ /dev/null @@ -1,270 +0,0 @@ -import sys -import threading -import json -from unittest.mock import patch, MagicMock - -sys.path.insert(0, '.') - -from src.ai_client_proxy import AIProxyClient - - -def test_initial_status_is_disconnected(): - client = AIProxyClient() - assert client.status == 'disconnected', f'Expected disconnected, got {client.status}' - print('PASS: test_initial_status_is_disconnected') - - -def test_initial_state_variables(): - client = AIProxyClient() - assert client._process is None, 'Expected _process to be None' - assert client._status == 'disconnected', f'Expected disconnected, got {client._status}' - assert client._pending == {}, f'Expected empty pending, got {client._pending}' - assert client._reader_thread is None, 'Expected _reader_thread to be None' - assert hasattr(client, '_pending_lock'), 'Missing _pending_lock' - assert callable(getattr(client._pending_lock, 'acquire', None)), 'Expected lock with acquire method' - print('PASS: test_initial_state_variables') - - -def test_status_property(): - client = AIProxyClient() - client._status = 'init' - assert client.status == 'init' - client._status = 'ready' - assert client.status == 'ready' - client._status = 'busy' - assert client.status == 'busy' - client._status = 'error' - assert client.status == 'error' - client._status = 'disconnected' - assert client.status == 'disconnected' - print('PASS: test_status_property') - - -def test_start_server_spawns_subprocess(): - client = AIProxyClient() - with patch('subprocess.Popen') as mock_popen: - client.start_server() - mock_popen.assert_called_once() - args = mock_popen.call_args[0][0] - assert '-m' in args, f'Expected -m in args, got {args}' - assert 'src.ai_server' in args, f'Expected src.ai_server in args, got {args}' - print('PASS: test_start_server_spawns_subprocess') - - -def test_start_server_sets_status_to_init(): - client = AIProxyClient() - with patch('subprocess.Popen'): - client.start_server() - assert client._status == 'init', f'Expected init, got {client._status}' - print('PASS: test_start_server_sets_status_to_init') - - -def test_start_server_starts_reader_thread(): - client = AIProxyClient() - with patch('subprocess.Popen'): - client.start_server() - assert client._reader_thread is not None, 'Expected reader thread to be started' - assert isinstance(client._reader_thread, threading.Thread), 'Expected threading.Thread' - print('PASS: test_start_server_starts_reader_thread') - - -def test_send_command_includes_method_and_params(): - client = AIProxyClient() - client._process = MagicMock() - client._status = 'ready' - client._pending_lock = threading.Lock() - client._reader_thread = MagicMock() - written_data = {} - def capture_write(data): - nonlocal written_data - written_data = json.loads(data) - client._write_to_stdin = capture_write - client._pending = {} - client.send_command('test_method', {'param': 'value'}) - assert written_data['id'], f"Expected id to be set" - assert written_data['method'] == 'test_method', f"Expected method test_method, got {written_data.get('method')}" - assert written_data['params'] == {'param': 'value'}, f"Expected params, got {written_data.get('params')}" - print('PASS: test_send_command_includes_method_and_params') - - -def test_send_command_adds_pending_request(): - client = AIProxyClient() - client._process = MagicMock() - client._status = 'ready' - client._pending_lock = threading.Lock() - client._reader_thread = MagicMock() - client._pending = {} - client._write_to_stdin = lambda x: None - client.send_command('test_method', {}) - assert len(client._pending) == 1, f"Expected 1 pending request, got {len(client._pending)}" - req_id = list(client._pending.keys())[0] - assert 'event' in client._pending[req_id], f"Expected 'event' key in pending request" - print('PASS: test_send_command_adds_pending_request') - - -def test_send_command_waits_for_event(): - client = AIProxyClient() - client._process = MagicMock() - client._status = 'ready' - client._pending_lock = threading.Lock() - client._reader_thread = MagicMock() - client._pending = {} - wait_called = [False] - def mock_wait(timeout): - wait_called[0] = True - return True - mock_event = MagicMock() - mock_event.wait = mock_wait - client._write_to_stdin = lambda x: None - original_event = threading.Event - with patch('threading.Event', return_value=mock_event): - client.send_command('test_method', {}) - assert wait_called[0], "Expected wait to be called" - print('PASS: test_send_command_waits_for_event') - - -def test_send_command_returns_response_when_ready(): - client = AIProxyClient() - client._process = MagicMock() - client._status = 'ready' - client._pending_lock = threading.Lock() - client._reader_thread = MagicMock() - test_response = {'id': 'test-uuid-123', 'result': {'output': 'success'}} - mock_event = MagicMock() - mock_event.wait = lambda timeout: True - client._pending = {'test-uuid-123': {'event': mock_event, 'response': test_response}} - client._write_to_stdin = lambda x: None - result = client.send_command('test_method', {}) - assert result == test_response, f'Expected {test_response}, got {result}' - print('PASS: test_send_command_returns_response_when_ready') - - -def test_send_command_timeout_raises(): - client = AIProxyClient() - client._process = MagicMock() - client._status = 'ready' - client._pending_lock = threading.Lock() - client._reader_thread = MagicMock() - mock_event = MagicMock() - mock_event.wait = lambda timeout: False - client._pending = {'test-uuid-123': {'event': mock_event, 'response': None}} - client._write_to_stdin = lambda x: None - try: - client.send_command('test_method', {}) - assert False, 'Expected TimeoutError' - except TimeoutError as e: - assert 'timed out' in str(e), f'Expected timed out message, got {e}' - print('PASS: test_send_command_timeout_raises') - - -def test_send_command_cleans_pending_on_timeout(): - client = AIProxyClient() - client._process = MagicMock() - client._status = 'ready' - client._pending_lock = threading.Lock() - client._reader_thread = MagicMock() - mock_event = MagicMock() - mock_event.wait = lambda timeout: False - client._pending = {'test-uuid-123': {'event': mock_event, 'response': None}} - client._write_to_stdin = lambda x: None - try: - client.send_command('test_method', {}) - except TimeoutError: - pass - assert 'test-uuid-123' not in client._pending, f'Expected cleanup on timeout, got {client._pending}' - print('PASS: test_send_command_cleans_pending_on_timeout') - - -def test_read_loop_parses_json_and_sets_response(): - client = AIProxyClient() - client._pending = {'test-uuid': {'event': MagicMock(), 'response': None}} - client._pending_lock = threading.Lock() - client._process = MagicMock() - lines = [b'{"id": "test-uuid", "result": {"data": "test"}}'] - client._process.stdout = MagicMock() - client._process.stdout.readline.side_effect = lines + [b''] - client._read_loop() - assert client._pending['test-uuid']['response'] == {'id': 'test-uuid', 'result': {'data': 'test'}}, f"Expected parsed response" - client._pending['test-uuid']['event'].set.assert_called_once() - print('PASS: test_read_loop_parses_json_and_sets_response') - - -def test_read_loop_matches_by_id(): - client = AIProxyClient() - client._pending = { - 'uuid-1': {'event': MagicMock(), 'response': None}, - 'uuid-2': {'event': MagicMock(), 'response': None} - } - client._pending_lock = threading.Lock() - client._process = MagicMock() - lines = [b'{"id": "uuid-2", "result": {"data": "from-uuid2"}}'] - client._process.stdout = MagicMock() - client._process.stdout.readline.side_effect = lines + [b''] - client._read_loop() - client._pending['uuid-1']['event'].set.assert_not_called() - client._pending['uuid-2']['event'].set.assert_called_once() - print('PASS: test_read_loop_matches_by_id') - - -def test_stop_terminates_process(): - client = AIProxyClient() - mock_process = MagicMock() - client._process = mock_process - client._status = 'ready' - client._pending = {'test': {'event': MagicMock(), 'response': {}}} - client._pending_lock = threading.Lock() - client.stop() - mock_process.terminate.assert_called_once() - print('PASS: test_stop_terminates_process') - - -def test_stop_cleans_pending(): - client = AIProxyClient() - mock_process = MagicMock() - client._process = mock_process - client._status = 'ready' - client._pending = {'test': {'event': MagicMock(), 'response': {}}} - client._pending_lock = threading.Lock() - client.stop() - assert client._pending == {}, f'Expected empty pending after stop, got {client._pending}' - print('PASS: test_stop_cleans_pending') - - -def test_stop_sets_status_to_disconnected(): - client = AIProxyClient() - mock_process = MagicMock() - client._process = mock_process - client._status = 'ready' - client._pending = {'test': {'event': MagicMock(), 'response': {}}} - client._pending_lock = threading.Lock() - client.stop() - assert client._status == 'disconnected', f'Expected disconnected, got {client._status}' - print('PASS: test_stop_sets_status_to_disconnected') - - -def test_default_timeout_is_60_seconds(): - client = AIProxyClient() - assert client._DEFAULT_TIMEOUT == 60.0, f'Expected 60.0, got {client._DEFAULT_TIMEOUT}' - print('PASS: test_default_timeout_is_60_seconds') - - -if __name__ == '__main__': - test_initial_status_is_disconnected() - test_initial_state_variables() - test_status_property() - test_start_server_spawns_subprocess() - test_start_server_sets_status_to_init() - test_start_server_starts_reader_thread() - test_send_command_includes_method_and_params() - test_send_command_adds_pending_request() - test_send_command_waits_for_event() - test_send_command_returns_response_when_ready() - test_send_command_timeout_raises() - test_send_command_cleans_pending_on_timeout() - test_read_loop_parses_json_and_sets_response() - test_read_loop_matches_by_id() - test_stop_terminates_process() - test_stop_cleans_pending() - test_stop_sets_status_to_disconnected() - test_default_timeout_is_60_seconds() - print('\nAll tests passed!') \ No newline at end of file