Skip to content

Commit 22b383c

Browse files
author
Tom Softreck
committed
update
1 parent ff50dfb commit 22b383c

File tree

3 files changed

+673
-0
lines changed

3 files changed

+673
-0
lines changed

tests/unit/test_connectors.py

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
"""Unit tests for the connectors module."""
2+
import asyncio
3+
import json
4+
from unittest.mock import AsyncMock, MagicMock, patch
5+
6+
import pytest
7+
import aiohttp
8+
import pytest_asyncio
9+
10+
from dialogchain import connectors
11+
from dialogchain.config import Config
12+
13+
14+
class TestBaseConnector:
15+
"""Test the base connector functionality."""
16+
17+
def test_init(self):
18+
"""Test connector initialization."""
19+
config = {"name": "test_connector", "type": "test", "timeout": 30}
20+
connector = connectors.BaseConnector(config)
21+
assert connector.name == "test_connector"
22+
assert connector.timeout == 30
23+
assert connector.is_connected is False
24+
25+
@pytest.mark.asyncio
26+
async def test_connect_disconnect(self):
27+
"""Test connect and disconnect methods."""
28+
connector = connectors.BaseConnector({"name": "test"})
29+
await connector.connect()
30+
assert connector.is_connected is True
31+
await connector.disconnect()
32+
assert connector.is_connected is False
33+
34+
@pytest.mark.asyncio
35+
async def test_context_manager(self):
36+
"""Test connector as a context manager."""
37+
connector = connectors.BaseConnector({"name": "test"})
38+
async with connector:
39+
assert connector.is_connected is True
40+
assert connector.is_connected is False
41+
42+
43+
class TestHttpConnector:
44+
"""Test the HTTP connector implementation."""
45+
46+
@pytest.fixture
47+
def connector_config(self):
48+
"""Return a sample HTTP connector config."""
49+
return {
50+
"name": "http_test",
51+
"type": "http",
52+
"base_url": "http://example.com/api",
53+
"timeout": 10,
54+
"headers": {"X-Test": "test"},
55+
"auth": {"username": "user", "password": "pass"},
56+
}
57+
58+
@pytest.fixture
59+
def mock_response(self):
60+
"""Create a mock aiohttp response."""
61+
response = AsyncMock(spec=aiohttp.ClientResponse)
62+
response.status = 200
63+
response.json.return_value = {"status": "ok"}
64+
response.text.return_value = '{"status": "ok"}'
65+
response.__aenter__.return_value = response
66+
return response
67+
68+
@pytest.fixture
69+
def mock_session(self, mock_response):
70+
"""Create a mock aiohttp client session."""
71+
session = AsyncMock(spec=aiohttp.ClientSession)
72+
session.request.return_value = mock_response
73+
session.__aenter__.return_value = session
74+
return session
75+
76+
@pytest.mark.asyncio
77+
async def test_http_connector_init(self, connector_config):
78+
"""Test HTTP connector initialization."""
79+
connector = connectors.HttpConnector(connector_config)
80+
assert connector.base_url == "http://example.com/api"
81+
assert connector.timeout == 10
82+
assert connector.headers == {"X-Test": "test"}
83+
assert connector.auth == aiohttp.BasicAuth("user", "pass")
84+
85+
@pytest.mark.asyncio
86+
async def test_http_connector_connect(self, connector_config, mock_session):
87+
"""Test HTTP connector connection."""
88+
with patch('aiohttp.ClientSession', return_value=mock_session):
89+
connector = connectors.HttpConnector(connector_config)
90+
await connector.connect()
91+
assert connector.is_connected is True
92+
assert connector.session is not None
93+
94+
@pytest.mark.asyncio
95+
async def test_http_connector_request(self, connector_config, mock_session, mock_response):
96+
"""Test HTTP connector request method."""
97+
with patch('aiohttp.ClientSession', return_value=mock_session):
98+
connector = connectors.HttpConnector(connector_config)
99+
await connector.connect()
100+
101+
# Test GET request
102+
response = await connector.request("GET", "/test")
103+
assert response == {"status": "ok"}
104+
mock_session.request.assert_called_once_with(
105+
"GET",
106+
"http://example.com/api/test",
107+
headers={"X-Test": "test"},
108+
auth=aiohttp.BasicAuth("user", "pass"),
109+
timeout=10,
110+
json=None,
111+
data=None,
112+
params=None
113+
)
114+
115+
# Reset mock for next test
116+
mock_session.request.reset_mock()
117+
118+
# Test POST with data
119+
await connector.request(
120+
"POST",
121+
"/test",
122+
json={"key": "value"},
123+
headers={"X-Custom": "header"},
124+
params={"q": "test"}
125+
)
126+
mock_session.request.assert_called_once_with(
127+
"POST",
128+
"http://example.com/api/test",
129+
headers={"X-Test": "test", "X-Custom": "header"},
130+
auth=aiohttp.BasicAuth("user", "pass"),
131+
timeout=10,
132+
json={"key": "value"},
133+
data=None,
134+
params={"q": "test"}
135+
)
136+
137+
@pytest.mark.asyncio
138+
async def test_http_connector_http_errors(self, connector_config, mock_session, mock_response):
139+
"""Test HTTP connector error handling."""
140+
# Test 404 error
141+
mock_response.status = 404
142+
mock_response.text.return_value = '{"error": "Not found"}'
143+
144+
with patch('aiohttp.ClientSession', return_value=mock_session):
145+
connector = connectors.HttpConnector(connector_config)
146+
await connector.connect()
147+
148+
with pytest.raises(connectors.ConnectorError) as exc_info:
149+
await connector.request("GET", "/nonexistent")
150+
assert "404" in str(exc_info.value)
151+
152+
153+
class TestMqttConnector:
154+
"""Test the MQTT connector implementation."""
155+
156+
@pytest.fixture
157+
def connector_config(self):
158+
"""Return a sample MQTT connector config."""
159+
return {
160+
"name": "mqtt_test",
161+
"type": "mqtt",
162+
"host": "test.mosquitto.org",
163+
"port": 1883,
164+
"client_id": "test_client",
165+
"clean_session": True,
166+
"topics": ["test/topic"],
167+
}
168+
169+
@pytest.fixture
170+
def mock_mqtt_client(self):
171+
"""Create a mock MQTT client."""
172+
client = AsyncMock()
173+
client.connect = AsyncMock()
174+
client.disconnect = AsyncMock()
175+
client.subscribe = AsyncMock()
176+
client.unsubscribe = AsyncMock()
177+
client.publish = AsyncMock()
178+
return client
179+
180+
@pytest.mark.asyncio
181+
async def test_mqtt_connector_init(self, connector_config):
182+
"""Test MQTT connector initialization."""
183+
with patch('asyncio_mqtt.Client') as mock_client:
184+
connector = connectors.MqttConnector(connector_config)
185+
assert connector.host == "test.mosquitto.org"
186+
assert connector.port == 1883
187+
assert connector.client_id == "test_client"
188+
189+
@pytest.mark.asyncio
190+
async def test_mqtt_connector_connect_disconnect(self, connector_config, mock_mqtt_client):
191+
"""Test MQTT connector connection and disconnection."""
192+
with patch('asyncio_mqtt.Client', return_value=mock_mqtt_client):
193+
connector = connectors.MqttConnector(connector_config)
194+
195+
# Test connect
196+
await connector.connect()
197+
assert connector.is_connected is True
198+
mock_mqtt_client.connect.assert_awaited_once()
199+
200+
# Test subscribe on connect
201+
mock_mqtt_client.subscribe.assert_awaited_once_with("test/topic")
202+
203+
# Test disconnect
204+
await connector.disconnect()
205+
assert connector.is_connected is False
206+
mock_mqtt_client.disconnect.assert_awaited_once()
207+
208+
@pytest.mark.asyncio
209+
async def test_mqtt_connector_publish(self, connector_config, mock_mqtt_client):
210+
"""Test MQTT connector publish method."""
211+
with patch('asyncio_mqtt.Client', return_value=mock_mqtt_client):
212+
connector = connectors.MqttConnector(connector_config)
213+
await connector.connect()
214+
215+
# Test publish
216+
await connector.publish("test/topic", {"key": "value"}, qos=1)
217+
mock_mqtt_client.publish.assert_awaited_once()
218+
219+
# Get the actual call arguments
220+
args, kwargs = mock_mqtt_client.publish.call_args
221+
assert args[0] == "test/topic"
222+
assert json.loads(args[1]) == {"key": "value"}
223+
assert kwargs["qos"] == 1
224+
225+
226+
class TestConnectorFactory:
227+
"""Test the connector factory."""
228+
229+
def test_create_connector_http(self):
230+
"""Test creating an HTTP connector."""
231+
config = {"name": "http_test", "type": "http", "base_url": "http://example.com"}
232+
connector = connectors.create_connector(config)
233+
assert isinstance(connector, connectors.HttpConnector)
234+
assert connector.name == "http_test"
235+
assert connector.base_url == "http://example.com"
236+
237+
def test_create_connector_mqtt(self):
238+
"""Test creating an MQTT connector."""
239+
config = {"name": "mqtt_test", "type": "mqtt", "host": "test.mosquitto.org"}
240+
connector = connectors.create_connector(config)
241+
assert isinstance(connector, connectors.MqttConnector)
242+
assert connector.name == "mqtt_test"
243+
assert connector.host == "test.mosquitto.org"
244+
245+
def test_create_connector_invalid_type(self):
246+
"""Test creating a connector with an invalid type."""
247+
config = {"name": "invalid", "type": "invalid_type"}
248+
with pytest.raises(ValueError) as exc_info:
249+
connectors.create_connector(config)
250+
assert "Unknown connector type" in str(exc_info.value)

0 commit comments

Comments
 (0)