aixtools 0.1.10__py3-none-any.whl → 0.1.11__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.
Potentially problematic release.
This version of aixtools might be problematic. Click here for more details.
- aixtools/_version.py +2 -2
- aixtools/mcp/client.py +102 -1
- aixtools/testing/aix_test_model.py +2 -0
- {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/METADATA +2 -1
- {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/RECORD +8 -45
- aixtools-0.1.11.dist-info/top_level.txt +1 -0
- aixtools-0.1.10.dist-info/top_level.txt +0 -5
- docker/mcp-base/Dockerfile +0 -33
- docker/mcp-base/zscaler.crt +0 -28
- notebooks/example_faulty_mcp_server.ipynb +0 -74
- notebooks/example_mcp_server_stdio.ipynb +0 -76
- notebooks/example_raw_mcp_client.ipynb +0 -84
- notebooks/example_tool_doctor.ipynb +0 -65
- scripts/config.sh +0 -28
- scripts/lint.sh +0 -32
- scripts/log_view.sh +0 -18
- scripts/run_example_mcp_server.sh +0 -14
- scripts/run_faulty_mcp_server.sh +0 -13
- scripts/run_server.sh +0 -29
- scripts/test.sh +0 -30
- tests/__init__.py +0 -0
- tests/unit/__init__.py +0 -0
- tests/unit/a2a/__init__.py +0 -0
- tests/unit/a2a/google_sdk/__init__.py +0 -0
- tests/unit/a2a/google_sdk/pydantic_ai_adapter/__init__.py +0 -0
- tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_agent_executor.py +0 -188
- tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_storage.py +0 -156
- tests/unit/a2a/google_sdk/test_card.py +0 -114
- tests/unit/a2a/google_sdk/test_remote_agent_connection.py +0 -413
- tests/unit/a2a/google_sdk/test_utils.py +0 -208
- tests/unit/agents/__init__.py +0 -0
- tests/unit/agents/test_prompt.py +0 -363
- tests/unit/compliance/test_private_data.py +0 -329
- tests/unit/google/__init__.py +0 -1
- tests/unit/google/test_client.py +0 -233
- tests/unit/mcp/__init__.py +0 -0
- tests/unit/mcp/test_client.py +0 -242
- tests/unit/server/__init__.py +0 -0
- tests/unit/server/test_path.py +0 -225
- tests/unit/server/test_utils.py +0 -362
- tests/unit/utils/__init__.py +0 -0
- tests/unit/utils/test_files.py +0 -146
- tests/unit/vault/__init__.py +0 -0
- tests/unit/vault/test_vault.py +0 -246
- {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/WHEEL +0 -0
- {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/entry_points.txt +0 -0
tests/unit/google/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"""Unit tests for aixtools.google module."""
|
tests/unit/google/test_client.py
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
"""Unit tests for aixtools.google.client module."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import unittest
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from unittest.mock import Mock, patch, MagicMock
|
|
7
|
-
|
|
8
|
-
from aixtools.google.client import get_genai_client
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class TestGetGenaiClient(unittest.TestCase):
|
|
12
|
-
"""Test cases for get_genai_client function."""
|
|
13
|
-
|
|
14
|
-
def setUp(self):
|
|
15
|
-
"""Set up test fixtures."""
|
|
16
|
-
# Store original environment variables to restore later
|
|
17
|
-
self.original_env = os.environ.copy()
|
|
18
|
-
|
|
19
|
-
def tearDown(self):
|
|
20
|
-
"""Clean up after tests."""
|
|
21
|
-
# Restore original environment variables
|
|
22
|
-
os.environ.clear()
|
|
23
|
-
os.environ.update(self.original_env)
|
|
24
|
-
|
|
25
|
-
@patch('aixtools.google.client.genai.Client')
|
|
26
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
27
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-central1')
|
|
28
|
-
@patch('aixtools.google.client.GOOGLE_GENAI_USE_VERTEXAI', True)
|
|
29
|
-
def test_get_genai_client_basic_success(self, mock_client):
|
|
30
|
-
"""Test get_genai_client with basic valid configuration."""
|
|
31
|
-
mock_client_instance = Mock()
|
|
32
|
-
mock_client.return_value = mock_client_instance
|
|
33
|
-
|
|
34
|
-
result = get_genai_client()
|
|
35
|
-
|
|
36
|
-
mock_client.assert_called_once_with(
|
|
37
|
-
vertexai=True,
|
|
38
|
-
project='test-project',
|
|
39
|
-
location='us-central1'
|
|
40
|
-
)
|
|
41
|
-
self.assertEqual(result, mock_client_instance)
|
|
42
|
-
|
|
43
|
-
@patch('aixtools.google.client.genai.Client')
|
|
44
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
45
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-west1')
|
|
46
|
-
@patch('aixtools.google.client.GOOGLE_GENAI_USE_VERTEXAI', False)
|
|
47
|
-
def test_get_genai_client_without_vertexai(self, mock_client):
|
|
48
|
-
"""Test get_genai_client with GOOGLE_GENAI_USE_VERTEXAI set to False."""
|
|
49
|
-
mock_client_instance = Mock()
|
|
50
|
-
mock_client.return_value = mock_client_instance
|
|
51
|
-
|
|
52
|
-
result = get_genai_client()
|
|
53
|
-
|
|
54
|
-
mock_client.assert_called_once_with(
|
|
55
|
-
vertexai=False,
|
|
56
|
-
project='test-project',
|
|
57
|
-
location='us-west1'
|
|
58
|
-
)
|
|
59
|
-
self.assertEqual(result, mock_client_instance)
|
|
60
|
-
|
|
61
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', None)
|
|
62
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-central1')
|
|
63
|
-
def test_get_genai_client_missing_project(self):
|
|
64
|
-
"""Test get_genai_client raises AssertionError when GOOGLE_CLOUD_PROJECT is not set."""
|
|
65
|
-
with self.assertRaises(AssertionError) as context:
|
|
66
|
-
get_genai_client()
|
|
67
|
-
|
|
68
|
-
self.assertIn("GOOGLE_CLOUD_PROJECT is not set", str(context.exception))
|
|
69
|
-
|
|
70
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
71
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', None)
|
|
72
|
-
def test_get_genai_client_missing_location(self):
|
|
73
|
-
"""Test get_genai_client raises AssertionError when GOOGLE_CLOUD_LOCATION is not set."""
|
|
74
|
-
with self.assertRaises(AssertionError) as context:
|
|
75
|
-
get_genai_client()
|
|
76
|
-
|
|
77
|
-
self.assertIn("GOOGLE_CLOUD_LOCATION is not set", str(context.exception))
|
|
78
|
-
|
|
79
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', '')
|
|
80
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-central1')
|
|
81
|
-
def test_get_genai_client_empty_project(self):
|
|
82
|
-
"""Test get_genai_client raises AssertionError when GOOGLE_CLOUD_PROJECT is empty."""
|
|
83
|
-
with self.assertRaises(AssertionError) as context:
|
|
84
|
-
get_genai_client()
|
|
85
|
-
|
|
86
|
-
self.assertIn("GOOGLE_CLOUD_PROJECT is not set", str(context.exception))
|
|
87
|
-
|
|
88
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
89
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', '')
|
|
90
|
-
def test_get_genai_client_empty_location(self):
|
|
91
|
-
"""Test get_genai_client raises AssertionError when GOOGLE_CLOUD_LOCATION is empty."""
|
|
92
|
-
with self.assertRaises(AssertionError) as context:
|
|
93
|
-
get_genai_client()
|
|
94
|
-
|
|
95
|
-
self.assertIn("GOOGLE_CLOUD_LOCATION is not set", str(context.exception))
|
|
96
|
-
|
|
97
|
-
@patch('aixtools.google.client.genai.Client')
|
|
98
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
99
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-central1')
|
|
100
|
-
@patch('aixtools.google.client.GOOGLE_GENAI_USE_VERTEXAI', True)
|
|
101
|
-
@patch('aixtools.google.client.logger')
|
|
102
|
-
def test_get_genai_client_with_valid_service_account_key(self, mock_logger, mock_client):
|
|
103
|
-
"""Test get_genai_client with valid service account key file."""
|
|
104
|
-
mock_client_instance = Mock()
|
|
105
|
-
mock_client.return_value = mock_client_instance
|
|
106
|
-
|
|
107
|
-
# Create a temporary file path that exists
|
|
108
|
-
with patch('pathlib.Path.exists', return_value=True):
|
|
109
|
-
service_account_path = Path('/tmp/test-service-account.json')
|
|
110
|
-
|
|
111
|
-
result = get_genai_client(service_account_path)
|
|
112
|
-
|
|
113
|
-
# Verify the environment variable was set
|
|
114
|
-
self.assertEqual(os.environ.get('GOOGLE_APPLICATION_CREDENTIALS'), str(service_account_path))
|
|
115
|
-
|
|
116
|
-
# Verify logging was called
|
|
117
|
-
mock_logger.info.assert_called_once_with(f"✅ GCP Service Account Key File: {service_account_path}")
|
|
118
|
-
|
|
119
|
-
# Verify client was created correctly
|
|
120
|
-
mock_client.assert_called_once_with(
|
|
121
|
-
vertexai=True,
|
|
122
|
-
project='test-project',
|
|
123
|
-
location='us-central1'
|
|
124
|
-
)
|
|
125
|
-
self.assertEqual(result, mock_client_instance)
|
|
126
|
-
|
|
127
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
128
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-central1')
|
|
129
|
-
def test_get_genai_client_with_nonexistent_service_account_key(self):
|
|
130
|
-
"""Test get_genai_client raises FileNotFoundError for nonexistent service account key."""
|
|
131
|
-
with patch('pathlib.Path.exists', return_value=False):
|
|
132
|
-
service_account_path = Path('/tmp/nonexistent-service-account.json')
|
|
133
|
-
|
|
134
|
-
with self.assertRaises(FileNotFoundError) as context:
|
|
135
|
-
get_genai_client(service_account_path)
|
|
136
|
-
|
|
137
|
-
self.assertIn(f"Service account key file not found: {service_account_path}", str(context.exception))
|
|
138
|
-
|
|
139
|
-
@patch('aixtools.google.client.genai.Client')
|
|
140
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
141
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-central1')
|
|
142
|
-
@patch('aixtools.google.client.GOOGLE_GENAI_USE_VERTEXAI', True)
|
|
143
|
-
def test_get_genai_client_preserves_existing_credentials_env(self, mock_client):
|
|
144
|
-
"""Test get_genai_client preserves existing GOOGLE_APPLICATION_CREDENTIALS when no service account key provided."""
|
|
145
|
-
mock_client_instance = Mock()
|
|
146
|
-
mock_client.return_value = mock_client_instance
|
|
147
|
-
|
|
148
|
-
# Set existing credentials
|
|
149
|
-
existing_credentials = '/existing/path/to/credentials.json'
|
|
150
|
-
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = existing_credentials
|
|
151
|
-
|
|
152
|
-
result = get_genai_client()
|
|
153
|
-
|
|
154
|
-
# Verify existing credentials are preserved
|
|
155
|
-
self.assertEqual(os.environ.get('GOOGLE_APPLICATION_CREDENTIALS'), existing_credentials)
|
|
156
|
-
|
|
157
|
-
mock_client.assert_called_once_with(
|
|
158
|
-
vertexai=True,
|
|
159
|
-
project='test-project',
|
|
160
|
-
location='us-central1'
|
|
161
|
-
)
|
|
162
|
-
self.assertEqual(result, mock_client_instance)
|
|
163
|
-
|
|
164
|
-
@patch('aixtools.google.client.genai.Client')
|
|
165
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
166
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-central1')
|
|
167
|
-
@patch('aixtools.google.client.GOOGLE_GENAI_USE_VERTEXAI', True)
|
|
168
|
-
@patch('aixtools.google.client.logger')
|
|
169
|
-
def test_get_genai_client_overwrites_existing_credentials_env(self, mock_logger, mock_client):
|
|
170
|
-
"""Test get_genai_client overwrites existing GOOGLE_APPLICATION_CREDENTIALS when service account key provided."""
|
|
171
|
-
mock_client_instance = Mock()
|
|
172
|
-
mock_client.return_value = mock_client_instance
|
|
173
|
-
|
|
174
|
-
# Set existing credentials
|
|
175
|
-
existing_credentials = '/existing/path/to/credentials.json'
|
|
176
|
-
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = existing_credentials
|
|
177
|
-
|
|
178
|
-
with patch('pathlib.Path.exists', return_value=True):
|
|
179
|
-
new_service_account_path = Path('/tmp/new-service-account.json')
|
|
180
|
-
|
|
181
|
-
result = get_genai_client(new_service_account_path)
|
|
182
|
-
|
|
183
|
-
# Verify new credentials overwrite existing ones
|
|
184
|
-
self.assertEqual(os.environ.get('GOOGLE_APPLICATION_CREDENTIALS'), str(new_service_account_path))
|
|
185
|
-
|
|
186
|
-
# Verify logging was called
|
|
187
|
-
mock_logger.info.assert_called_once_with(f"✅ GCP Service Account Key File: {new_service_account_path}")
|
|
188
|
-
|
|
189
|
-
mock_client.assert_called_once_with(
|
|
190
|
-
vertexai=True,
|
|
191
|
-
project='test-project',
|
|
192
|
-
location='us-central1'
|
|
193
|
-
)
|
|
194
|
-
self.assertEqual(result, mock_client_instance)
|
|
195
|
-
|
|
196
|
-
@patch('aixtools.google.client.genai.Client')
|
|
197
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
198
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-central1')
|
|
199
|
-
@patch('aixtools.google.client.GOOGLE_GENAI_USE_VERTEXAI', True)
|
|
200
|
-
def test_get_genai_client_genai_client_exception(self, mock_client):
|
|
201
|
-
"""Test get_genai_client propagates exceptions from genai.Client."""
|
|
202
|
-
mock_client.side_effect = Exception("GenAI client initialization failed")
|
|
203
|
-
|
|
204
|
-
with self.assertRaises(Exception) as context:
|
|
205
|
-
get_genai_client()
|
|
206
|
-
|
|
207
|
-
self.assertIn("GenAI client initialization failed", str(context.exception))
|
|
208
|
-
|
|
209
|
-
@patch('aixtools.google.client.genai.Client')
|
|
210
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_PROJECT', 'test-project')
|
|
211
|
-
@patch('aixtools.google.client.GOOGLE_CLOUD_LOCATION', 'us-central1')
|
|
212
|
-
@patch('aixtools.google.client.GOOGLE_GENAI_USE_VERTEXAI', True)
|
|
213
|
-
@patch('aixtools.google.client.logger')
|
|
214
|
-
def test_get_genai_client_service_account_path_as_string(self, mock_logger, mock_client):
|
|
215
|
-
"""Test get_genai_client handles service account path as string correctly."""
|
|
216
|
-
mock_client_instance = Mock()
|
|
217
|
-
mock_client.return_value = mock_client_instance
|
|
218
|
-
|
|
219
|
-
with patch('pathlib.Path.exists', return_value=True):
|
|
220
|
-
service_account_path = Path('/tmp/test-service-account.json')
|
|
221
|
-
|
|
222
|
-
result = get_genai_client(service_account_path)
|
|
223
|
-
|
|
224
|
-
# Verify the environment variable was set as string
|
|
225
|
-
self.assertEqual(os.environ.get('GOOGLE_APPLICATION_CREDENTIALS'), str(service_account_path))
|
|
226
|
-
self.assertIsInstance(os.environ.get('GOOGLE_APPLICATION_CREDENTIALS'), str)
|
|
227
|
-
|
|
228
|
-
mock_client.assert_called_once()
|
|
229
|
-
self.assertEqual(result, mock_client_instance)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if __name__ == '__main__':
|
|
233
|
-
unittest.main()
|
tests/unit/mcp/__init__.py
DELETED
|
File without changes
|
tests/unit/mcp/test_client.py
DELETED
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
"""Unit tests for aixtools.mcp.client module."""
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
import unittest
|
|
5
|
-
from unittest.mock import Mock, patch
|
|
6
|
-
|
|
7
|
-
from mcp import types as mcp_types
|
|
8
|
-
from pydantic_ai import exceptions
|
|
9
|
-
|
|
10
|
-
from aixtools.mcp.client import (
|
|
11
|
-
CACHE_KEY,
|
|
12
|
-
DEFAULT_MCP_CONNECTION_TIMEOUT,
|
|
13
|
-
CachedMCPServerStreamableHTTP,
|
|
14
|
-
get_configured_mcp_servers,
|
|
15
|
-
get_mcp_headers,
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class TestGetMcpHeaders(unittest.TestCase):
|
|
20
|
-
"""Test cases for get_mcp_headers function."""
|
|
21
|
-
|
|
22
|
-
def test_get_mcp_headers_with_both_ids(self):
|
|
23
|
-
"""Test get_mcp_headers with both user_id and session_id."""
|
|
24
|
-
session_id_tuple = ("user123", "session456")
|
|
25
|
-
result = get_mcp_headers(session_id_tuple)
|
|
26
|
-
|
|
27
|
-
expected = {
|
|
28
|
-
"user-id": "user123",
|
|
29
|
-
"session-id": "session456"
|
|
30
|
-
}
|
|
31
|
-
self.assertEqual(result, expected)
|
|
32
|
-
|
|
33
|
-
def test_get_mcp_headers_with_user_id_only(self):
|
|
34
|
-
"""Test get_mcp_headers with only user_id."""
|
|
35
|
-
session_id_tuple = ("user123", None) # type: ignore
|
|
36
|
-
result = get_mcp_headers(session_id_tuple)
|
|
37
|
-
|
|
38
|
-
expected = {
|
|
39
|
-
"user-id": "user123"
|
|
40
|
-
}
|
|
41
|
-
self.assertEqual(result, expected)
|
|
42
|
-
|
|
43
|
-
def test_get_mcp_headers_with_session_id_only(self):
|
|
44
|
-
"""Test get_mcp_headers with only session_id."""
|
|
45
|
-
session_id_tuple = (None, "session456") # type: ignore
|
|
46
|
-
result = get_mcp_headers(session_id_tuple)
|
|
47
|
-
|
|
48
|
-
expected = {
|
|
49
|
-
"session-id": "session456"
|
|
50
|
-
}
|
|
51
|
-
self.assertEqual(result, expected)
|
|
52
|
-
|
|
53
|
-
def test_get_mcp_headers_with_empty_strings(self):
|
|
54
|
-
"""Test get_mcp_headers with empty strings."""
|
|
55
|
-
session_id_tuple = ("", "")
|
|
56
|
-
result = get_mcp_headers(session_id_tuple)
|
|
57
|
-
|
|
58
|
-
self.assertIsNone(result)
|
|
59
|
-
|
|
60
|
-
def test_get_mcp_headers_with_none_values(self):
|
|
61
|
-
"""Test get_mcp_headers with None values."""
|
|
62
|
-
session_id_tuple = (None, None) # type: ignore
|
|
63
|
-
result = get_mcp_headers(session_id_tuple)
|
|
64
|
-
|
|
65
|
-
self.assertIsNone(result)
|
|
66
|
-
|
|
67
|
-
def test_get_mcp_headers_with_mixed_empty_and_none(self):
|
|
68
|
-
"""Test get_mcp_headers with mixed empty and None values."""
|
|
69
|
-
session_id_tuple = ("", None) # type: ignore
|
|
70
|
-
result = get_mcp_headers(session_id_tuple)
|
|
71
|
-
|
|
72
|
-
self.assertIsNone(result)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
class TestGetConfiguredMcpServers(unittest.TestCase):
|
|
76
|
-
"""Test cases for get_configured_mcp_servers function."""
|
|
77
|
-
|
|
78
|
-
@patch('aixtools.mcp.client.CachedMCPServerStreamableHTTP')
|
|
79
|
-
def test_get_configured_mcp_servers_basic(self, mock_cached_server):
|
|
80
|
-
"""Test get_configured_mcp_servers with basic parameters."""
|
|
81
|
-
session_id_tuple = ("user123", "session456")
|
|
82
|
-
mcp_urls = ["http://server1.com", "http://server2.com"]
|
|
83
|
-
|
|
84
|
-
mock_server_instances = [Mock(), Mock()]
|
|
85
|
-
mock_cached_server.side_effect = mock_server_instances
|
|
86
|
-
|
|
87
|
-
result = get_configured_mcp_servers(session_id_tuple, mcp_urls)
|
|
88
|
-
|
|
89
|
-
self.assertEqual(len(result), 2)
|
|
90
|
-
self.assertEqual(result, mock_server_instances)
|
|
91
|
-
|
|
92
|
-
# Verify that CachedMCPServerStreamableHTTP was called correctly
|
|
93
|
-
expected_headers = {"user-id": "user123", "session-id": "session456"}
|
|
94
|
-
mock_cached_server.assert_any_call(
|
|
95
|
-
url="http://server1.com",
|
|
96
|
-
headers=expected_headers,
|
|
97
|
-
timeout=DEFAULT_MCP_CONNECTION_TIMEOUT
|
|
98
|
-
)
|
|
99
|
-
mock_cached_server.assert_any_call(
|
|
100
|
-
url="http://server2.com",
|
|
101
|
-
headers=expected_headers,
|
|
102
|
-
timeout=DEFAULT_MCP_CONNECTION_TIMEOUT
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
@patch('aixtools.mcp.client.CachedMCPServerStreamableHTTP')
|
|
106
|
-
def test_get_configured_mcp_servers_custom_timeout(self, mock_cached_server):
|
|
107
|
-
"""Test get_configured_mcp_servers with custom timeout."""
|
|
108
|
-
session_id_tuple = ("user123", "session456")
|
|
109
|
-
mcp_urls = ["http://server1.com"]
|
|
110
|
-
custom_timeout = 60
|
|
111
|
-
|
|
112
|
-
mock_server_instance = Mock()
|
|
113
|
-
mock_cached_server.return_value = mock_server_instance
|
|
114
|
-
|
|
115
|
-
result = get_configured_mcp_servers(session_id_tuple, mcp_urls, custom_timeout)
|
|
116
|
-
|
|
117
|
-
self.assertEqual(len(result), 1)
|
|
118
|
-
mock_cached_server.assert_called_once_with(
|
|
119
|
-
url="http://server1.com",
|
|
120
|
-
headers={"user-id": "user123", "session-id": "session456"},
|
|
121
|
-
timeout=custom_timeout
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
@patch('aixtools.mcp.client.CachedMCPServerStreamableHTTP')
|
|
125
|
-
def test_get_configured_mcp_servers_no_headers(self, mock_cached_server):
|
|
126
|
-
"""Test get_configured_mcp_servers when no headers are generated."""
|
|
127
|
-
session_id_tuple = (None, None) # type: ignore
|
|
128
|
-
mcp_urls = ["http://server1.com"]
|
|
129
|
-
|
|
130
|
-
mock_server_instance = Mock()
|
|
131
|
-
mock_cached_server.return_value = mock_server_instance
|
|
132
|
-
|
|
133
|
-
result = get_configured_mcp_servers(session_id_tuple, mcp_urls)
|
|
134
|
-
|
|
135
|
-
self.assertEqual(len(result), 1)
|
|
136
|
-
mock_cached_server.assert_called_once_with(
|
|
137
|
-
url="http://server1.com",
|
|
138
|
-
headers=None,
|
|
139
|
-
timeout=DEFAULT_MCP_CONNECTION_TIMEOUT
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
@patch('aixtools.mcp.client.CachedMCPServerStreamableHTTP')
|
|
143
|
-
def test_get_configured_mcp_servers_empty_urls(self, mock_cached_server):
|
|
144
|
-
"""Test get_configured_mcp_servers with empty URL list."""
|
|
145
|
-
session_id_tuple = ("user123", "session456")
|
|
146
|
-
mcp_urls = []
|
|
147
|
-
|
|
148
|
-
result = get_configured_mcp_servers(session_id_tuple, mcp_urls)
|
|
149
|
-
|
|
150
|
-
self.assertEqual(len(result), 0)
|
|
151
|
-
mock_cached_server.assert_not_called()
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
class TestCachedMCPServerStreamableHTTP(unittest.IsolatedAsyncioTestCase):
|
|
155
|
-
"""Test cases for CachedMCPServerStreamableHTTP class."""
|
|
156
|
-
|
|
157
|
-
def setUp(self):
|
|
158
|
-
"""Set up test fixtures."""
|
|
159
|
-
self.server = CachedMCPServerStreamableHTTP(url="http://test.com")
|
|
160
|
-
self.server._client = Mock()
|
|
161
|
-
|
|
162
|
-
def test_init(self):
|
|
163
|
-
"""Test CachedMCPServerStreamableHTTP initialization."""
|
|
164
|
-
server = CachedMCPServerStreamableHTTP(url="http://test.com")
|
|
165
|
-
|
|
166
|
-
self.assertIsNotNone(server._tools_cache)
|
|
167
|
-
self.assertIsNone(server._tools_list)
|
|
168
|
-
self.assertIsNotNone(server._isolation_lock)
|
|
169
|
-
|
|
170
|
-
async def test_run_direct_or_isolated_success(self):
|
|
171
|
-
"""Test _run_direct_or_isolated with successful execution."""
|
|
172
|
-
async def test_func():
|
|
173
|
-
return "success"
|
|
174
|
-
|
|
175
|
-
def fallback(exc):
|
|
176
|
-
return "fallback"
|
|
177
|
-
|
|
178
|
-
result = await self.server._run_direct_or_isolated(test_func, fallback, None)
|
|
179
|
-
self.assertEqual(result, "success")
|
|
180
|
-
|
|
181
|
-
async def test_run_direct_or_isolated_timeout(self):
|
|
182
|
-
"""Test _run_direct_or_isolated with timeout."""
|
|
183
|
-
async def test_func():
|
|
184
|
-
await asyncio.sleep(2)
|
|
185
|
-
return "success"
|
|
186
|
-
|
|
187
|
-
def fallback(exc):
|
|
188
|
-
return "fallback"
|
|
189
|
-
|
|
190
|
-
result = await self.server._run_direct_or_isolated(test_func, fallback, 0.1)
|
|
191
|
-
self.assertEqual(result, "fallback")
|
|
192
|
-
|
|
193
|
-
async def test_run_direct_or_isolated_exception(self):
|
|
194
|
-
"""Test _run_direct_or_isolated with exception."""
|
|
195
|
-
async def test_func():
|
|
196
|
-
raise ValueError("test error")
|
|
197
|
-
|
|
198
|
-
def fallback(exc):
|
|
199
|
-
return f"fallback: {exc}"
|
|
200
|
-
|
|
201
|
-
result = await self.server._run_direct_or_isolated(test_func, fallback, None)
|
|
202
|
-
self.assertEqual(result, "fallback: test error")
|
|
203
|
-
|
|
204
|
-
async def test_run_direct_or_isolated_model_retry(self):
|
|
205
|
-
"""Test _run_direct_or_isolated with ModelRetry exception."""
|
|
206
|
-
async def test_func():
|
|
207
|
-
raise exceptions.ModelRetry("retry error")
|
|
208
|
-
|
|
209
|
-
def fallback(exc):
|
|
210
|
-
return "fallback"
|
|
211
|
-
|
|
212
|
-
with self.assertRaises(exceptions.ModelRetry):
|
|
213
|
-
await self.server._run_direct_or_isolated(test_func, fallback, None)
|
|
214
|
-
|
|
215
|
-
async def test_list_tools_uninitialized_client(self):
|
|
216
|
-
"""Test list_tools with uninitialized client."""
|
|
217
|
-
self.server._client = None # type: ignore
|
|
218
|
-
|
|
219
|
-
result = await self.server.list_tools()
|
|
220
|
-
|
|
221
|
-
self.assertEqual(result, [])
|
|
222
|
-
|
|
223
|
-
async def test_list_tools_cached(self):
|
|
224
|
-
"""Test list_tools with cached result."""
|
|
225
|
-
cached_tools = [Mock(spec=mcp_types.Tool)]
|
|
226
|
-
self.server._tools_cache[CACHE_KEY] = cached_tools
|
|
227
|
-
|
|
228
|
-
result = await self.server.list_tools()
|
|
229
|
-
|
|
230
|
-
self.assertEqual(result, cached_tools)
|
|
231
|
-
|
|
232
|
-
async def test_call_tool_uninitialized_client(self):
|
|
233
|
-
"""Test call_tool with uninitialized client."""
|
|
234
|
-
self.server._client = None # type: ignore
|
|
235
|
-
|
|
236
|
-
result = await self.server.call_tool("test_tool", {}, Mock(), Mock())
|
|
237
|
-
|
|
238
|
-
self.assertIn("MCP connection is uninitialized", str(result))
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if __name__ == '__main__':
|
|
242
|
-
unittest.main()
|
tests/unit/server/__init__.py
DELETED
|
File without changes
|