145 lines
5.8 KiB
Python
145 lines
5.8 KiB
Python
import pytest
|
|
import requests
|
|
from unittest.mock import MagicMock, patch
|
|
import threading
|
|
import time
|
|
import json
|
|
|
|
# Import HookServer from api_hooks.py
|
|
from api_hooks import HookServer # No need for HookServerInstance, HookHandler here
|
|
|
|
from api_hook_client import ApiHookClient
|
|
|
|
@pytest.fixture(scope="module")
|
|
def hook_server_fixture():
|
|
# Mock the 'app' object that HookServer expects
|
|
mock_app = MagicMock()
|
|
mock_app.test_hooks_enabled = True # Essential for the server to start
|
|
mock_app.project = {'name': 'test_project'}
|
|
mock_app.disc_entries = [{'role': 'user', 'content': 'hello'}]
|
|
mock_app._pending_gui_tasks = []
|
|
mock_app._pending_gui_tasks_lock = threading.Lock()
|
|
|
|
# Use an ephemeral port (0) to avoid conflicts
|
|
server = HookServer(mock_app, port=0)
|
|
server.start()
|
|
|
|
# Wait a moment for the server thread to start and bind
|
|
time.sleep(0.1)
|
|
|
|
# Get the actual port assigned by the OS
|
|
actual_port = server.server.server_address[1]
|
|
|
|
# Update the base_url for the client to use the actual port
|
|
client_base_url = f"http://127.0.0.1:{actual_port}"
|
|
|
|
yield client_base_url, mock_app # Yield the base URL and the mock_app
|
|
|
|
server.stop()
|
|
|
|
def test_get_status_success(hook_server_fixture):
|
|
"""
|
|
Test that get_status successfully retrieves the server status
|
|
when the HookServer is running. This is the 'Green Phase'.
|
|
"""
|
|
base_url, _ = hook_server_fixture
|
|
client = ApiHookClient(base_url=base_url)
|
|
status = client.get_status()
|
|
assert status == {'status': 'ok'}
|
|
|
|
def test_get_project_success(hook_server_fixture):
|
|
"""
|
|
Test successful retrieval of project data.
|
|
"""
|
|
base_url, mock_app = hook_server_fixture
|
|
client = ApiHookClient(base_url=base_url)
|
|
project = client.get_project()
|
|
assert project == {'project': mock_app.project}
|
|
|
|
def test_post_project_success(hook_server_fixture):
|
|
"""Test successful posting and updating of project data."""
|
|
base_url, mock_app = hook_server_fixture
|
|
client = ApiHookClient(base_url=base_url)
|
|
new_project_data = {'name': 'updated_project', 'version': '1.0'}
|
|
response = client.post_project(new_project_data)
|
|
assert response == {'status': 'updated'}
|
|
# Verify that the mock_app.project was updated. Note: the mock_app is reused.
|
|
# The actual server state is in the real app, but for testing client, we check mock.
|
|
# This part depends on how the actual server modifies the app.project.
|
|
# For HookHandler, it does `app.project = data.get('project', app.project)`
|
|
# So, the mock_app.project will actually be the *old* value, because the mock_app
|
|
# is not the real app instance. This test is primarily for the client-server interaction.
|
|
# To test the side effect on app.project, one would need to inspect the server's app instance,
|
|
# which is not directly exposed by the fixture in a simple way.
|
|
# For now, we focus on the client's ability to send and receive the success status.
|
|
|
|
def test_get_session_success(hook_server_fixture):
|
|
"""
|
|
Test successful retrieval of session data.
|
|
"""
|
|
base_url, mock_app = hook_server_fixture
|
|
client = ApiHookClient(base_url=base_url)
|
|
session = client.get_session()
|
|
assert session == {'session': {'entries': mock_app.disc_entries}}
|
|
|
|
def test_post_session_success(hook_server_fixture):
|
|
"""
|
|
Test successful posting and updating of session data.
|
|
"""
|
|
base_url, mock_app = hook_server_fixture
|
|
client = ApiHookClient(base_url=base_url)
|
|
new_session_entries = [{'role': 'agent', 'content': 'hi'}]
|
|
response = client.post_session(new_session_entries)
|
|
assert response == {'status': 'updated'}
|
|
# Similar note as post_project about mock_app.disc_entries not being updated here.
|
|
|
|
def test_post_gui_success(hook_server_fixture):
|
|
"""
|
|
Test successful posting of GUI data.
|
|
"""
|
|
base_url, mock_app = hook_server_fixture
|
|
client = ApiHookClient(base_url=base_url)
|
|
gui_data = {'command': 'set_text', 'id': 'some_item', 'value': 'new_text'}
|
|
response = client.post_gui(gui_data)
|
|
assert response == {'status': 'queued'}
|
|
assert mock_app._pending_gui_tasks == [gui_data] # This should be updated by the server logic.
|
|
|
|
def test_get_status_connection_error_handling():
|
|
"""
|
|
Test that ApiHookClient correctly handles a connection error.
|
|
"""
|
|
client = ApiHookClient(base_url="http://127.0.0.1:1") # Use a port that is highly unlikely to be listening
|
|
with pytest.raises(requests.exceptions.Timeout):
|
|
client.get_status()
|
|
|
|
def test_post_project_server_error_handling(hook_server_fixture):
|
|
"""
|
|
Test that ApiHookClient correctly handles a server-side error (e.g., 500).
|
|
This requires mocking the server\'s response within the fixture or a specific test.
|
|
For simplicity, we\'ll simulate this by causing the HookHandler to raise an exception
|
|
for a specific path, but that\'s complex with the current fixture.
|
|
A simpler way for client-side testing is to mock the requests call directly for this scenario.
|
|
"""
|
|
base_url, _ = hook_server_fixture
|
|
client = ApiHookClient(base_url=base_url)
|
|
|
|
with patch('requests.post') as mock_post:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 500
|
|
mock_response.raise_for_status.side_effect = requests.exceptions.HTTPError("500 Server Error", response=mock_response)
|
|
mock_response.text = "Internal Server Error"
|
|
mock_post.return_value = mock_response
|
|
|
|
with pytest.raises(requests.exceptions.HTTPError) as excinfo:
|
|
client.post_project({'name': 'error_project'})
|
|
assert "HTTP error 500" in str(excinfo.value)
|
|
|
|
|
|
def test_unsupported_method_error():
|
|
"""
|
|
Test that calling an unsupported HTTP method raises a ValueError.
|
|
"""
|
|
client = ApiHookClient()
|
|
with pytest.raises(ValueError, match="Unsupported HTTP method"):
|
|
client._make_request('PUT', '/some_endpoint', data={'key': 'value'})
|