120 lines
4.1 KiB
Python
120 lines
4.1 KiB
Python
import pytest
|
|
from unittest.mock import patch, ANY
|
|
import time
|
|
import sys
|
|
from src.gui_2 import App
|
|
from src.events import UserRequestEvent
|
|
from src.api_hook_client import ApiHookClient
|
|
|
|
@pytest.mark.timeout(10)
|
|
def test_user_request_integration_flow(mock_app: App) -> None:
|
|
"""
|
|
Verifies that pushing a UserRequestEvent to the event_queue:
|
|
1. Triggers ai_client.send
|
|
2. Results in a 'response' event back to the queue
|
|
3. Eventually updates the UI state (ai_response, ai_status) after processing GUI tasks.
|
|
"""
|
|
app = mock_app
|
|
# Mock all ai_client methods called during _handle_request_event
|
|
mock_response = "This is a test AI response"
|
|
with (
|
|
patch('src.ai_client.send', return_value=mock_response) as mock_send,
|
|
patch('src.ai_client.set_custom_system_prompt'),
|
|
patch('src.ai_client.set_model_params'),
|
|
patch('src.ai_client.set_agent_tools'),
|
|
patch('src.app_controller.AppController._update_gcli_adapter')
|
|
):
|
|
# 1. Create and push a UserRequestEvent
|
|
event = UserRequestEvent(
|
|
prompt="Hello AI",
|
|
stable_md="Context",
|
|
file_items=[],
|
|
disc_text="History",
|
|
base_dir="."
|
|
)
|
|
# 2. Call the handler directly since start_services is mocked (no event loop thread)
|
|
# But _handle_request_event itself puts a 'response' event in the queue.
|
|
# Our mock_app fixture mocks start_services, so _process_event_queue is NOT running.
|
|
# We need to call it manually or not mock start_services.
|
|
|
|
# Let's call the handler
|
|
app.controller._handle_request_event(event)
|
|
|
|
# 3. Verify ai_client.send was called
|
|
assert mock_send.called, "ai_client.send was not called"
|
|
|
|
# 4. Now the 'response' event is in app.controller.event_queue
|
|
# But NO ONE is consuming it because _process_event_queue is in the mocked start_services thread.
|
|
# Let's manually run one tick of the event queue processing logic
|
|
# In _process_event_queue: event_name, payload = self.event_queue.get()
|
|
event_name, payload = app.controller.event_queue.get()
|
|
assert event_name == "response"
|
|
|
|
# Manually push it to _pending_gui_tasks as _process_event_queue would
|
|
app.controller._pending_gui_tasks.append({
|
|
"action": "handle_ai_response",
|
|
"payload": payload
|
|
})
|
|
|
|
# 5. Process the GUI tasks
|
|
app.controller._process_pending_gui_tasks()
|
|
|
|
assert app.controller.ai_response == mock_response
|
|
assert app.controller.ai_status == "done"
|
|
|
|
@pytest.mark.timeout(10)
|
|
def test_user_request_error_handling(mock_app: App) -> None:
|
|
"""
|
|
Verifies that if ai_client.send raises an exception, the UI is updated with the error state.
|
|
"""
|
|
app = mock_app
|
|
with (
|
|
patch('src.ai_client.send', side_effect=Exception("API Failure")),
|
|
patch('src.ai_client.set_custom_system_prompt'),
|
|
patch('src.ai_client.set_model_params'),
|
|
patch('src.ai_client.set_agent_tools'),
|
|
patch('src.app_controller.AppController._update_gcli_adapter')
|
|
):
|
|
event = UserRequestEvent(
|
|
prompt="Trigger Error",
|
|
stable_md="",
|
|
file_items=[],
|
|
disc_text="",
|
|
base_dir="."
|
|
)
|
|
app.controller._handle_request_event(event)
|
|
|
|
# Manually consume from queue
|
|
event_name, payload = app.controller.event_queue.get()
|
|
assert event_name == "response"
|
|
assert payload["status"] == "error"
|
|
|
|
# Manually push to GUI tasks
|
|
app.controller._pending_gui_tasks.append({
|
|
"action": "handle_ai_response",
|
|
"payload": payload
|
|
})
|
|
|
|
app.controller._process_pending_gui_tasks()
|
|
assert app.controller.ai_status == "error"
|
|
assert "ERROR: API Failure" in app.controller.ai_response
|
|
|
|
def test_api_gui_state_live(live_gui) -> None:
|
|
client = ApiHookClient()
|
|
client.set_value('current_provider', 'anthropic')
|
|
client.set_value('current_model', 'claude-3-haiku-20240307')
|
|
|
|
start_time = time.time()
|
|
success = False
|
|
while time.time() - start_time < 10:
|
|
state = client.get_gui_state()
|
|
if state and state.get('current_provider') == 'anthropic' and state.get('current_model') == 'claude-3-haiku-20240307':
|
|
success = True
|
|
break
|
|
time.sleep(0.5)
|
|
|
|
assert success, f"GUI state did not update. Got: {client.get_gui_state()}"
|
|
final_state = client.get_gui_state()
|
|
assert final_state['current_provider'] == 'anthropic'
|
|
assert final_state['current_model'] == 'claude-3-haiku-20240307'
|