aiqa-client 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
aiqa/test_tracing.py ADDED
@@ -0,0 +1,230 @@
1
+ """
2
+ Unit tests for tracing.py functions.
3
+ """
4
+
5
+ import os
6
+ import pytest
7
+ from unittest.mock import patch, MagicMock
8
+ from aiqa.tracing import get_span
9
+
10
+
11
+ class TestGetSpan:
12
+ """Tests for get_span function."""
13
+
14
+ def test_get_span_success_with_span_id(self):
15
+ """Test successful retrieval of span using spanId query."""
16
+ span_data = {
17
+ "id": "test-span-123",
18
+ "name": "test_span",
19
+ "trace_id": "abc123",
20
+ "attributes": {"key": "value"},
21
+ }
22
+ mock_response_data = {"hits": [span_data]}
23
+
24
+ with patch.dict(
25
+ os.environ,
26
+ {
27
+ "AIQA_SERVER_URL": "http://localhost:3000",
28
+ "AIQA_API_KEY": "test-api-key",
29
+ "AIQA_ORGANISATION_ID": "test-org",
30
+ },
31
+ ):
32
+ with patch("requests.get") as mock_get:
33
+ mock_response = MagicMock()
34
+ mock_response.status_code = 200
35
+ mock_response.json.return_value = mock_response_data
36
+
37
+ mock_get.return_value = mock_response
38
+
39
+ result = get_span("test-span-123")
40
+
41
+ assert result == span_data
42
+ mock_get.assert_called_once()
43
+ call_args = mock_get.call_args
44
+ assert call_args[0][0] == "http://localhost:3000/span"
45
+ assert "q" in call_args[1]["params"]
46
+ assert call_args[1]["params"]["q"] == "spanId:test-span-123"
47
+
48
+ def test_get_span_success_with_client_span_id(self):
49
+ """Test successful retrieval of span using clientSpanId query when spanId fails."""
50
+ span_data = {
51
+ "id": "test-span-123",
52
+ "name": "test_span",
53
+ "trace_id": "abc123",
54
+ }
55
+ mock_response_data = {"hits": [span_data]}
56
+
57
+ with patch.dict(
58
+ os.environ,
59
+ {
60
+ "AIQA_SERVER_URL": "http://localhost:3000",
61
+ "AIQA_API_KEY": "test-api-key",
62
+ "AIQA_ORGANISATION_ID": "test-org",
63
+ },
64
+ ):
65
+ with patch("requests.get") as mock_get:
66
+ # First call returns 404 (spanId not found), second call succeeds (clientSpanId)
67
+ mock_response_404 = MagicMock()
68
+ mock_response_404.status_code = 404
69
+
70
+ mock_response_200 = MagicMock()
71
+ mock_response_200.status_code = 200
72
+ mock_response_200.json.return_value = mock_response_data
73
+
74
+ mock_get.side_effect = [mock_response_404, mock_response_200]
75
+
76
+ result = get_span("test-span-123")
77
+
78
+ assert result == span_data
79
+ assert mock_get.call_count == 2
80
+ # Check that second call uses clientSpanId
81
+ second_call = mock_get.call_args_list[1]
82
+ assert second_call[1]["params"]["q"] == "clientSpanId:test-span-123"
83
+
84
+ def test_get_span_not_found(self):
85
+ """Test that get_span returns None when span is not found."""
86
+ with patch.dict(
87
+ os.environ,
88
+ {
89
+ "AIQA_SERVER_URL": "http://localhost:3000",
90
+ "AIQA_API_KEY": "test-api-key",
91
+ "AIQA_ORGANISATION_ID": "test-org",
92
+ },
93
+ ):
94
+ with patch("requests.get") as mock_get:
95
+ # Both queries return 404
96
+ mock_response_404 = MagicMock()
97
+ mock_response_404.status_code = 404
98
+
99
+ mock_get.return_value = mock_response_404
100
+
101
+ result = get_span("nonexistent-span")
102
+
103
+ assert result is None
104
+ assert mock_get.call_count == 2
105
+
106
+ def test_get_span_empty_hits(self):
107
+ """Test that get_span returns None when hits array is empty."""
108
+ mock_response_data = {"hits": []}
109
+
110
+ with patch.dict(
111
+ os.environ,
112
+ {
113
+ "AIQA_SERVER_URL": "http://localhost:3000",
114
+ "AIQA_API_KEY": "test-api-key",
115
+ "AIQA_ORGANISATION_ID": "test-org",
116
+ },
117
+ ):
118
+ with patch("requests.get") as mock_get:
119
+ mock_response = MagicMock()
120
+ mock_response.status_code = 200
121
+ mock_response.json.return_value = mock_response_data
122
+
123
+ mock_get.return_value = mock_response
124
+
125
+ result = get_span("test-span-123")
126
+
127
+ assert result is None
128
+
129
+ def test_get_span_missing_server_url(self):
130
+ """Test that get_span raises ValueError when AIQA_SERVER_URL is not set."""
131
+ with patch.dict(os.environ, {}, clear=True):
132
+ with pytest.raises(ValueError, match="AIQA_SERVER_URL is not set"):
133
+ get_span("test-span-123")
134
+
135
+ def test_get_span_missing_organisation_id(self):
136
+ """Test that get_span raises ValueError when organisation ID is not provided."""
137
+ with patch.dict(
138
+ os.environ,
139
+ {
140
+ "AIQA_SERVER_URL": "http://localhost:3000",
141
+ "AIQA_API_KEY": "test-api-key",
142
+ },
143
+ clear=True,
144
+ ):
145
+ with pytest.raises(ValueError, match="Organisation ID is required"):
146
+ get_span("test-span-123")
147
+
148
+ def test_get_span_missing_api_key(self):
149
+ """Test that get_span raises ValueError when AIQA_API_KEY is not set."""
150
+ with patch.dict(
151
+ os.environ,
152
+ {
153
+ "AIQA_SERVER_URL": "http://localhost:3000",
154
+ "AIQA_ORGANISATION_ID": "test-org",
155
+ },
156
+ clear=True,
157
+ ):
158
+ with pytest.raises(ValueError, match="API key is required"):
159
+ get_span("test-span-123")
160
+
161
+ def test_get_span_with_organisation_id_parameter(self):
162
+ """Test that get_span uses organisation_id parameter when provided."""
163
+ span_data = {"id": "test-span-123", "name": "test_span"}
164
+ mock_response_data = {"hits": [span_data]}
165
+
166
+ with patch.dict(
167
+ os.environ,
168
+ {
169
+ "AIQA_SERVER_URL": "http://localhost:3000",
170
+ "AIQA_API_KEY": "test-api-key",
171
+ },
172
+ clear=True,
173
+ ):
174
+ with patch("requests.get") as mock_get:
175
+ mock_response = MagicMock()
176
+ mock_response.status_code = 200
177
+ mock_response.json.return_value = mock_response_data
178
+
179
+ mock_get.return_value = mock_response
180
+
181
+ result = get_span("test-span-123", organisation_id="param-org")
182
+
183
+ assert result == span_data
184
+ call_args = mock_get.call_args
185
+ assert call_args[1]["params"]["organisation"] == "param-org"
186
+
187
+ def test_get_span_server_error(self):
188
+ """Test that get_span raises ValueError on server error."""
189
+ with patch.dict(
190
+ os.environ,
191
+ {
192
+ "AIQA_SERVER_URL": "http://localhost:3000",
193
+ "AIQA_API_KEY": "test-api-key",
194
+ "AIQA_ORGANISATION_ID": "test-org",
195
+ },
196
+ ):
197
+ with patch("requests.get") as mock_get:
198
+ mock_response = MagicMock()
199
+ mock_response.status_code = 500
200
+ mock_response.text = "Internal Server Error"
201
+
202
+ mock_get.return_value = mock_response
203
+
204
+ with pytest.raises(ValueError, match="Failed to get span: 500"):
205
+ get_span("test-span-123")
206
+
207
+ def test_get_span_authorization_header(self):
208
+ """Test that get_span includes Authorization header with API key."""
209
+ span_data = {"id": "test-span-123"}
210
+ mock_response_data = {"hits": [span_data]}
211
+
212
+ with patch.dict(
213
+ os.environ,
214
+ {
215
+ "AIQA_SERVER_URL": "http://localhost:3000",
216
+ "AIQA_API_KEY": "test-api-key-123",
217
+ "AIQA_ORGANISATION_ID": "test-org",
218
+ },
219
+ ):
220
+ with patch("requests.get") as mock_get:
221
+ mock_response = MagicMock()
222
+ mock_response.status_code = 200
223
+ mock_response.json.return_value = mock_response_data
224
+
225
+ mock_get.return_value = mock_response
226
+
227
+ get_span("test-span-123")
228
+
229
+ call_args = mock_get.call_args
230
+ assert call_args[1]["headers"]["Authorization"] == "ApiKey test-api-key-123"