|
1 | 1 | """Unit tests for the connectors module.""" |
2 | 2 | import asyncio |
3 | | -import json |
4 | | -from unittest.mock import AsyncMock, MagicMock, patch |
5 | | - |
6 | 3 | import pytest |
7 | | -import aiohttp |
8 | | -import pytest_asyncio |
| 4 | +from unittest.mock import AsyncMock, MagicMock, patch |
9 | 5 |
|
10 | 6 | 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 | 7 |
|
42 | 8 |
|
43 | | -class TestHttpConnector: |
44 | | - """Test the HTTP connector implementation.""" |
| 9 | +class TestSourceConnector: |
| 10 | + """Test the Source connector functionality.""" |
45 | 11 |
|
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 | | - } |
| 12 | + def test_source_initialization(self): |
| 13 | + """Test source connector initialization.""" |
| 14 | + class TestSource(connectors.Source): |
| 15 | + async def receive(self): |
| 16 | + yield "test" |
| 17 | + |
| 18 | + source = TestSource() |
| 19 | + assert isinstance(source, connectors.Source) |
57 | 20 |
|
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 | 21 |
|
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 |
| 22 | +class TestDestinationConnector: |
| 23 | + """Test the Destination connector functionality.""" |
75 | 24 |
|
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") |
| 25 | + def test_destination_initialization(self): |
| 26 | + """Test destination connector initialization.""" |
| 27 | + class TestDestination(connectors.Destination): |
| 28 | + async def send(self, message): |
| 29 | + pass |
| 30 | + |
| 31 | + destination = TestDestination() |
| 32 | + assert isinstance(destination, connectors.Destination) |
84 | 33 |
|
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 | 34 |
|
| 35 | +class TestRTSPSource: |
| 36 | + """Test the RTSP source connector.""" |
| 37 | + |
94 | 38 | @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() |
| 39 | + async def test_rtsp_source_receive(self): |
| 40 | + """Test RTSP source receive method.""" |
| 41 | + with patch('cv2.VideoCapture') as mock_capture: |
| 42 | + # Setup mock |
| 43 | + mock_capture.return_value.isOpened.return_value = True |
| 44 | + mock_capture.return_value.grab.return_value = True |
| 45 | + mock_capture.return_value.retrieve.return_value = (True, "frame_data") |
100 | 46 |
|
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() |
| 47 | + source = connectors.RTSPSource("rtsp://test") |
| 48 | + source.reconnect_attempts = 1 # Limit reconnect attempts for test |
147 | 49 |
|
148 | | - with pytest.raises(connectors.ConnectorError) as exc_info: |
149 | | - await connector.request("GET", "/nonexistent") |
150 | | - assert "404" in str(exc_info.value) |
| 50 | + # Test receive generator |
| 51 | + async for frame in source.receive(): |
| 52 | + assert frame == {"frame": "frame_data", "metadata": {}} |
| 53 | + break # Just test one iteration |
151 | 54 |
|
152 | 55 |
|
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 | | - |
| 56 | +class TestHTTPDestination: |
| 57 | + """Test the HTTP destination connector.""" |
| 58 | + |
189 | 59 | @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() |
| 60 | + async def test_http_destination_send(self): |
| 61 | + """Test HTTP destination send method.""" |
| 62 | + with patch('aiohttp.ClientSession.post') as mock_post: |
| 63 | + # Setup mock response |
| 64 | + mock_response = AsyncMock() |
| 65 | + mock_response.status = 200 |
| 66 | + mock_response.json.return_value = {"status": "success"} |
| 67 | + mock_post.return_value.__aenter__.return_value = mock_response |
199 | 68 |
|
200 | | - # Test subscribe on connect |
201 | | - mock_mqtt_client.subscribe.assert_awaited_once_with("test/topic") |
| 69 | + destination = connectors.HTTPDestination("http://test") |
| 70 | + await destination.send({"test": "data"}) |
202 | 71 |
|
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) |
| 72 | + # Verify the request was made correctly |
| 73 | + mock_post.assert_called_once() |
| 74 | + args, kwargs = mock_post.call_args |
| 75 | + assert kwargs['json'] == {"test": "data"} |
0 commit comments