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/server/test_path.py
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
"""Unit tests for aixtools.server.path module."""
|
|
2
|
-
|
|
3
|
-
import unittest
|
|
4
|
-
from pathlib import Path, PurePath, PurePosixPath
|
|
5
|
-
from unittest.mock import Mock, patch
|
|
6
|
-
|
|
7
|
-
from aixtools.server.path import (
|
|
8
|
-
CONTAINER_WORKSPACE_PATH,
|
|
9
|
-
WORKSPACES_ROOT_DIR,
|
|
10
|
-
container_to_host_path,
|
|
11
|
-
get_workspace_path,
|
|
12
|
-
host_to_container_path,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class TestGetWorkspacePath(unittest.TestCase):
|
|
17
|
-
"""Test cases for get_workspace_path function."""
|
|
18
|
-
|
|
19
|
-
def setUp(self):
|
|
20
|
-
"""Set up test fixtures."""
|
|
21
|
-
self.mock_ctx = ("test_user", "test_session")
|
|
22
|
-
|
|
23
|
-
def test_sandbox_path_without_service_name(self):
|
|
24
|
-
"""Test getting sandbox path without service name."""
|
|
25
|
-
result = get_workspace_path(in_sandbox=True)
|
|
26
|
-
|
|
27
|
-
self.assertEqual(result, CONTAINER_WORKSPACE_PATH)
|
|
28
|
-
self.assertIsInstance(result, PurePath)
|
|
29
|
-
|
|
30
|
-
def test_sandbox_path_with_service_name(self):
|
|
31
|
-
"""Test getting sandbox path with service name."""
|
|
32
|
-
result = get_workspace_path("mcp_server", in_sandbox=True)
|
|
33
|
-
|
|
34
|
-
expected = CONTAINER_WORKSPACE_PATH / "mcp_server"
|
|
35
|
-
self.assertEqual(result, expected)
|
|
36
|
-
|
|
37
|
-
@patch('aixtools.server.path.get_session_id_tuple')
|
|
38
|
-
def test_host_path_without_service_name(self, mock_get_session):
|
|
39
|
-
"""Test getting host path without service name."""
|
|
40
|
-
mock_get_session.return_value = ("test_user", "test_session")
|
|
41
|
-
|
|
42
|
-
result = get_workspace_path(in_sandbox=False)
|
|
43
|
-
|
|
44
|
-
expected = WORKSPACES_ROOT_DIR / "test_user" / "test_session"
|
|
45
|
-
self.assertEqual(result, expected)
|
|
46
|
-
|
|
47
|
-
@patch('aixtools.server.path.get_session_id_tuple')
|
|
48
|
-
def test_host_path_with_service_name(self, mock_get_session):
|
|
49
|
-
"""Test getting host path with service name."""
|
|
50
|
-
mock_get_session.return_value = ("test_user", "test_session")
|
|
51
|
-
|
|
52
|
-
result = get_workspace_path("mcp_server", in_sandbox=False)
|
|
53
|
-
|
|
54
|
-
expected = WORKSPACES_ROOT_DIR / "test_user" / "test_session" / "mcp_server"
|
|
55
|
-
self.assertEqual(result, expected)
|
|
56
|
-
|
|
57
|
-
def test_host_path_with_tuple_context(self):
|
|
58
|
-
"""Test getting host path with tuple context."""
|
|
59
|
-
result = get_workspace_path("service", in_sandbox=False, ctx=self.mock_ctx)
|
|
60
|
-
|
|
61
|
-
expected = WORKSPACES_ROOT_DIR / "test_user" / "test_session" / "service"
|
|
62
|
-
self.assertEqual(result, expected)
|
|
63
|
-
|
|
64
|
-
@patch('aixtools.server.path.get_session_id_tuple')
|
|
65
|
-
def test_host_path_with_context_object(self, mock_get_session):
|
|
66
|
-
"""Test getting host path with context object."""
|
|
67
|
-
mock_ctx = Mock()
|
|
68
|
-
mock_get_session.return_value = ("ctx_user", "ctx_session")
|
|
69
|
-
|
|
70
|
-
result = get_workspace_path("service", in_sandbox=False, ctx=mock_ctx)
|
|
71
|
-
|
|
72
|
-
expected = WORKSPACES_ROOT_DIR / "ctx_user" / "ctx_session" / "service"
|
|
73
|
-
self.assertEqual(result, expected)
|
|
74
|
-
mock_get_session.assert_called_once_with(mock_ctx)
|
|
75
|
-
|
|
76
|
-
def test_default_parameters(self):
|
|
77
|
-
"""Test function with default parameters."""
|
|
78
|
-
with patch('aixtools.server.path.get_session_id_tuple') as mock_get_session:
|
|
79
|
-
mock_get_session.return_value = ("default_user", "default_session")
|
|
80
|
-
|
|
81
|
-
result = get_workspace_path()
|
|
82
|
-
|
|
83
|
-
expected = WORKSPACES_ROOT_DIR / "default_user" / "default_session"
|
|
84
|
-
self.assertEqual(result, expected)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
class TestContainerToHostPath(unittest.TestCase):
|
|
88
|
-
"""Test cases for container_to_host_path function."""
|
|
89
|
-
|
|
90
|
-
def setUp(self):
|
|
91
|
-
"""Set up test fixtures."""
|
|
92
|
-
self.mock_ctx = ("test_user", "test_session")
|
|
93
|
-
|
|
94
|
-
@patch('aixtools.server.path.get_workspace_path')
|
|
95
|
-
def test_valid_container_path_conversion(self, mock_get_workspace):
|
|
96
|
-
"""Test valid container path conversion."""
|
|
97
|
-
mock_get_workspace.return_value = Path("/data/workspaces/user/session")
|
|
98
|
-
|
|
99
|
-
container_path = PurePosixPath("/workspace/file.txt")
|
|
100
|
-
result = container_to_host_path(container_path, ctx=self.mock_ctx)
|
|
101
|
-
|
|
102
|
-
expected = Path("/data/workspaces/user/session/file.txt")
|
|
103
|
-
self.assertEqual(result, expected)
|
|
104
|
-
|
|
105
|
-
@patch('aixtools.server.path.get_workspace_path')
|
|
106
|
-
def test_container_root_path_conversion(self, mock_get_workspace):
|
|
107
|
-
"""Test container root path conversion."""
|
|
108
|
-
mock_get_workspace.return_value = Path("/data/workspaces/user/session")
|
|
109
|
-
|
|
110
|
-
container_path = PurePosixPath("/workspace")
|
|
111
|
-
result = container_to_host_path(container_path, ctx=self.mock_ctx)
|
|
112
|
-
|
|
113
|
-
expected = Path("/data/workspaces/user/session")
|
|
114
|
-
self.assertEqual(result, expected)
|
|
115
|
-
|
|
116
|
-
@patch('aixtools.server.path.get_workspace_path')
|
|
117
|
-
def test_nested_container_path_conversion(self, mock_get_workspace):
|
|
118
|
-
"""Test nested container path conversion."""
|
|
119
|
-
mock_get_workspace.return_value = Path("/data/workspaces/user/session")
|
|
120
|
-
|
|
121
|
-
container_path = PurePosixPath("/workspace/subdir/nested/file.txt")
|
|
122
|
-
result = container_to_host_path(container_path, ctx=self.mock_ctx)
|
|
123
|
-
|
|
124
|
-
expected = Path("/data/workspaces/user/session/subdir/nested/file.txt")
|
|
125
|
-
self.assertEqual(result, expected)
|
|
126
|
-
|
|
127
|
-
def test_invalid_container_path_raises_error(self):
|
|
128
|
-
"""Test that invalid container paths raise ValueError."""
|
|
129
|
-
invalid_paths = [
|
|
130
|
-
PurePosixPath("/tmp/file.txt"),
|
|
131
|
-
PurePosixPath("/home/user/file.txt"),
|
|
132
|
-
PurePosixPath("/workspace_other/file.txt"),
|
|
133
|
-
]
|
|
134
|
-
|
|
135
|
-
for invalid_path in invalid_paths:
|
|
136
|
-
with self.subTest(path=invalid_path):
|
|
137
|
-
with self.assertRaises(ValueError) as context:
|
|
138
|
-
container_to_host_path(invalid_path, ctx=self.mock_ctx)
|
|
139
|
-
|
|
140
|
-
self.assertIn("Container path must be a subdir", str(context.exception))
|
|
141
|
-
self.assertIn(str(invalid_path), str(context.exception))
|
|
142
|
-
|
|
143
|
-
@patch('aixtools.server.path.get_workspace_path')
|
|
144
|
-
def test_context_passed_to_get_workspace_path(self, mock_get_workspace):
|
|
145
|
-
"""Test that context is properly passed to get_workspace_path."""
|
|
146
|
-
mock_get_workspace.return_value = Path("/data/workspaces/user/session")
|
|
147
|
-
|
|
148
|
-
container_path = PurePosixPath("/workspace/file.txt")
|
|
149
|
-
container_to_host_path(container_path, ctx=self.mock_ctx)
|
|
150
|
-
|
|
151
|
-
mock_get_workspace.assert_called_once_with(ctx=self.mock_ctx)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
class TestHostToContainerPath(unittest.TestCase):
|
|
155
|
-
"""Test cases for host_to_container_path function."""
|
|
156
|
-
|
|
157
|
-
def setUp(self):
|
|
158
|
-
"""Set up test fixtures."""
|
|
159
|
-
self.mock_ctx = ("test_user", "test_session")
|
|
160
|
-
|
|
161
|
-
@patch('aixtools.server.path.get_workspace_path')
|
|
162
|
-
def test_valid_host_path_conversion(self, mock_get_workspace):
|
|
163
|
-
"""Test valid host path conversion."""
|
|
164
|
-
mock_get_workspace.return_value = Path("/data/workspaces/user/session")
|
|
165
|
-
|
|
166
|
-
host_path = Path("/data/workspaces/user/session/file.txt")
|
|
167
|
-
result = host_to_container_path(host_path, ctx=self.mock_ctx)
|
|
168
|
-
|
|
169
|
-
expected = PurePosixPath("/workspace/file.txt")
|
|
170
|
-
self.assertEqual(result, expected)
|
|
171
|
-
|
|
172
|
-
@patch('aixtools.server.path.get_workspace_path')
|
|
173
|
-
def test_host_root_path_conversion(self, mock_get_workspace):
|
|
174
|
-
"""Test host root path conversion."""
|
|
175
|
-
mock_get_workspace.return_value = Path("/data/workspaces/user/session")
|
|
176
|
-
|
|
177
|
-
host_path = Path("/data/workspaces/user/session")
|
|
178
|
-
result = host_to_container_path(host_path, ctx=self.mock_ctx)
|
|
179
|
-
|
|
180
|
-
expected = PurePosixPath("/workspace")
|
|
181
|
-
self.assertEqual(result, expected)
|
|
182
|
-
|
|
183
|
-
@patch('aixtools.server.path.get_workspace_path')
|
|
184
|
-
def test_nested_host_path_conversion(self, mock_get_workspace):
|
|
185
|
-
"""Test nested host path conversion."""
|
|
186
|
-
mock_get_workspace.return_value = Path("/data/workspaces/user/session")
|
|
187
|
-
|
|
188
|
-
host_path = Path("/data/workspaces/user/session/subdir/nested/file.txt")
|
|
189
|
-
result = host_to_container_path(host_path, ctx=self.mock_ctx)
|
|
190
|
-
|
|
191
|
-
expected = PurePosixPath("/workspace/subdir/nested/file.txt")
|
|
192
|
-
self.assertEqual(result, expected)
|
|
193
|
-
|
|
194
|
-
@patch('aixtools.server.path.get_workspace_path')
|
|
195
|
-
def test_invalid_host_path_raises_error(self, mock_get_workspace):
|
|
196
|
-
"""Test that invalid host paths raise ValueError."""
|
|
197
|
-
mock_get_workspace.return_value = Path("/data/workspaces/user/session")
|
|
198
|
-
|
|
199
|
-
invalid_paths = [
|
|
200
|
-
Path("/tmp/file.txt"),
|
|
201
|
-
Path("/home/user/file.txt"),
|
|
202
|
-
Path("/data/other/file.txt"),
|
|
203
|
-
]
|
|
204
|
-
|
|
205
|
-
for invalid_path in invalid_paths:
|
|
206
|
-
with self.subTest(path=invalid_path):
|
|
207
|
-
with self.assertRaises(ValueError) as context:
|
|
208
|
-
host_to_container_path(invalid_path, ctx=self.mock_ctx)
|
|
209
|
-
|
|
210
|
-
self.assertIn("Host path must be a subdir", str(context.exception))
|
|
211
|
-
self.assertIn(str(invalid_path), str(context.exception))
|
|
212
|
-
|
|
213
|
-
@patch('aixtools.server.path.get_workspace_path')
|
|
214
|
-
def test_context_passed_to_get_workspace_path(self, mock_get_workspace):
|
|
215
|
-
"""Test that context is properly passed to get_workspace_path."""
|
|
216
|
-
mock_get_workspace.return_value = Path("/data/workspaces/user/session")
|
|
217
|
-
|
|
218
|
-
host_path = Path("/data/workspaces/user/session/file.txt")
|
|
219
|
-
host_to_container_path(host_path, ctx=self.mock_ctx)
|
|
220
|
-
|
|
221
|
-
mock_get_workspace.assert_called_once_with(ctx=self.mock_ctx)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if __name__ == '__main__':
|
|
225
|
-
unittest.main()
|
tests/unit/server/test_utils.py
DELETED
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
"""Unit tests for aixtools.server.utils module."""
|
|
2
|
-
|
|
3
|
-
import asyncio
|
|
4
|
-
import unittest
|
|
5
|
-
from unittest.mock import AsyncMock, Mock, patch
|
|
6
|
-
|
|
7
|
-
from aixtools.server.utils import (
|
|
8
|
-
get_session_id_from_request,
|
|
9
|
-
get_session_id_str,
|
|
10
|
-
get_session_id_tuple,
|
|
11
|
-
get_user_id_from_request,
|
|
12
|
-
run_in_thread,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class TestGetSessionIdFromRequest(unittest.TestCase):
|
|
17
|
-
"""Test cases for get_session_id_from_request function."""
|
|
18
|
-
|
|
19
|
-
@patch('aixtools.server.utils.dependencies')
|
|
20
|
-
def test_get_session_id_with_context_none(self, mock_dependencies):
|
|
21
|
-
"""Test getting session ID when context is None."""
|
|
22
|
-
mock_request = Mock()
|
|
23
|
-
mock_request.headers.get.return_value = "test-session-123"
|
|
24
|
-
mock_dependencies.get_http_request.return_value = mock_request
|
|
25
|
-
|
|
26
|
-
result = get_session_id_from_request(None)
|
|
27
|
-
|
|
28
|
-
self.assertEqual(result, "test-session-123")
|
|
29
|
-
mock_dependencies.get_http_request.assert_called_once()
|
|
30
|
-
mock_request.headers.get.assert_called_once_with("session-id")
|
|
31
|
-
|
|
32
|
-
def test_get_session_id_with_context_provided(self):
|
|
33
|
-
"""Test getting session ID when context is provided."""
|
|
34
|
-
mock_ctx = Mock()
|
|
35
|
-
mock_request = Mock()
|
|
36
|
-
mock_request.headers.get.return_value = "ctx-session-456"
|
|
37
|
-
mock_ctx.get_http_request.return_value = mock_request
|
|
38
|
-
|
|
39
|
-
result = get_session_id_from_request(mock_ctx)
|
|
40
|
-
|
|
41
|
-
self.assertEqual(result, "ctx-session-456")
|
|
42
|
-
mock_ctx.get_http_request.assert_called_once()
|
|
43
|
-
mock_request.headers.get.assert_called_once_with("session-id")
|
|
44
|
-
|
|
45
|
-
@patch('aixtools.server.utils.dependencies')
|
|
46
|
-
def test_get_session_id_header_not_found(self, mock_dependencies):
|
|
47
|
-
"""Test getting session ID when header is not found."""
|
|
48
|
-
mock_request = Mock()
|
|
49
|
-
mock_request.headers.get.return_value = None
|
|
50
|
-
mock_dependencies.get_http_request.return_value = mock_request
|
|
51
|
-
|
|
52
|
-
result = get_session_id_from_request(None)
|
|
53
|
-
|
|
54
|
-
self.assertIsNone(result)
|
|
55
|
-
|
|
56
|
-
@patch('aixtools.server.utils.dependencies')
|
|
57
|
-
def test_get_session_id_value_error(self, mock_dependencies):
|
|
58
|
-
"""Test getting session ID when ValueError is raised."""
|
|
59
|
-
mock_dependencies.get_http_request.side_effect = ValueError("Request error")
|
|
60
|
-
|
|
61
|
-
result = get_session_id_from_request(None)
|
|
62
|
-
|
|
63
|
-
self.assertIsNone(result)
|
|
64
|
-
|
|
65
|
-
@patch('aixtools.server.utils.dependencies')
|
|
66
|
-
def test_get_session_id_runtime_error(self, mock_dependencies):
|
|
67
|
-
"""Test getting session ID when RuntimeError is raised."""
|
|
68
|
-
mock_dependencies.get_http_request.side_effect = RuntimeError("Runtime error")
|
|
69
|
-
|
|
70
|
-
result = get_session_id_from_request(None)
|
|
71
|
-
|
|
72
|
-
self.assertIsNone(result)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
class TestGetUserIdFromRequest(unittest.TestCase):
|
|
76
|
-
"""Test cases for get_user_id_from_request function."""
|
|
77
|
-
|
|
78
|
-
@patch('aixtools.server.utils.dependencies')
|
|
79
|
-
def test_get_user_id_with_context_none(self, mock_dependencies):
|
|
80
|
-
"""Test getting user ID when context is None."""
|
|
81
|
-
mock_request = Mock()
|
|
82
|
-
mock_request.headers.get.return_value = "TEST-USER-123"
|
|
83
|
-
mock_dependencies.get_http_request.return_value = mock_request
|
|
84
|
-
|
|
85
|
-
result = get_user_id_from_request(None)
|
|
86
|
-
|
|
87
|
-
self.assertEqual(result, "test-user-123") # Should be lowercase
|
|
88
|
-
mock_dependencies.get_http_request.assert_called_once()
|
|
89
|
-
mock_request.headers.get.assert_called_once_with("user-id")
|
|
90
|
-
|
|
91
|
-
def test_get_user_id_with_context_provided(self):
|
|
92
|
-
"""Test getting user ID when context is provided."""
|
|
93
|
-
mock_ctx = Mock()
|
|
94
|
-
mock_request = Mock()
|
|
95
|
-
mock_request.headers.get.return_value = "CTX-USER-456"
|
|
96
|
-
mock_ctx.get_http_request.return_value = mock_request
|
|
97
|
-
|
|
98
|
-
result = get_user_id_from_request(mock_ctx)
|
|
99
|
-
|
|
100
|
-
self.assertEqual(result, "ctx-user-456") # Should be lowercase
|
|
101
|
-
mock_ctx.get_http_request.assert_called_once()
|
|
102
|
-
mock_request.headers.get.assert_called_once_with("user-id")
|
|
103
|
-
|
|
104
|
-
@patch('aixtools.server.utils.dependencies')
|
|
105
|
-
def test_get_user_id_header_not_found(self, mock_dependencies):
|
|
106
|
-
"""Test getting user ID when header is not found."""
|
|
107
|
-
mock_request = Mock()
|
|
108
|
-
mock_request.headers.get.return_value = None
|
|
109
|
-
mock_dependencies.get_http_request.return_value = mock_request
|
|
110
|
-
|
|
111
|
-
result = get_user_id_from_request(None)
|
|
112
|
-
|
|
113
|
-
self.assertIsNone(result)
|
|
114
|
-
|
|
115
|
-
@patch('aixtools.server.utils.dependencies')
|
|
116
|
-
def test_get_user_id_empty_string(self, mock_dependencies):
|
|
117
|
-
"""Test getting user ID when header is empty string."""
|
|
118
|
-
mock_request = Mock()
|
|
119
|
-
mock_request.headers.get.return_value = ""
|
|
120
|
-
mock_dependencies.get_http_request.return_value = mock_request
|
|
121
|
-
|
|
122
|
-
result = get_user_id_from_request(None)
|
|
123
|
-
|
|
124
|
-
self.assertIsNone(result)
|
|
125
|
-
|
|
126
|
-
@patch('aixtools.server.utils.dependencies')
|
|
127
|
-
def test_get_user_id_value_error(self, mock_dependencies):
|
|
128
|
-
"""Test getting user ID when ValueError is raised."""
|
|
129
|
-
mock_dependencies.get_http_request.side_effect = ValueError("Request error")
|
|
130
|
-
|
|
131
|
-
result = get_user_id_from_request(None)
|
|
132
|
-
|
|
133
|
-
self.assertIsNone(result)
|
|
134
|
-
|
|
135
|
-
@patch('aixtools.server.utils.dependencies')
|
|
136
|
-
def test_get_user_id_runtime_error(self, mock_dependencies):
|
|
137
|
-
"""Test getting user ID when RuntimeError is raised."""
|
|
138
|
-
mock_dependencies.get_http_request.side_effect = RuntimeError("Runtime error")
|
|
139
|
-
|
|
140
|
-
result = get_user_id_from_request(None)
|
|
141
|
-
|
|
142
|
-
self.assertIsNone(result)
|
|
143
|
-
|
|
144
|
-
@patch('aixtools.server.utils.dependencies')
|
|
145
|
-
def test_get_user_id_attribute_error(self, mock_dependencies):
|
|
146
|
-
"""Test getting user ID when AttributeError is raised."""
|
|
147
|
-
mock_dependencies.get_http_request.side_effect = AttributeError("Attribute error")
|
|
148
|
-
|
|
149
|
-
result = get_user_id_from_request(None)
|
|
150
|
-
|
|
151
|
-
self.assertIsNone(result)
|
|
152
|
-
|
|
153
|
-
@patch('aixtools.server.utils.dependencies')
|
|
154
|
-
def test_get_user_id_case_variations(self, mock_dependencies):
|
|
155
|
-
"""Test that user ID is always returned in lowercase."""
|
|
156
|
-
test_cases = [
|
|
157
|
-
("UPPERCASE", "uppercase"),
|
|
158
|
-
("MixedCase", "mixedcase"),
|
|
159
|
-
("lowercase", "lowercase"),
|
|
160
|
-
("CamelCase", "camelcase"),
|
|
161
|
-
]
|
|
162
|
-
|
|
163
|
-
for input_user_id, expected_output in test_cases:
|
|
164
|
-
with self.subTest(input_user_id=input_user_id):
|
|
165
|
-
mock_request = Mock()
|
|
166
|
-
mock_request.headers.get.return_value = input_user_id
|
|
167
|
-
mock_dependencies.get_http_request.return_value = mock_request
|
|
168
|
-
|
|
169
|
-
result = get_user_id_from_request(None)
|
|
170
|
-
|
|
171
|
-
self.assertEqual(result, expected_output)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
class TestGetSessionIdTuple(unittest.TestCase):
|
|
175
|
-
"""Test cases for get_session_id_tuple function."""
|
|
176
|
-
|
|
177
|
-
@patch('aixtools.server.utils.get_session_id_from_request')
|
|
178
|
-
@patch('aixtools.server.utils.get_user_id_from_request')
|
|
179
|
-
@patch('aixtools.server.utils.session_id_var')
|
|
180
|
-
@patch('aixtools.server.utils.user_id_var')
|
|
181
|
-
def test_get_session_id_tuple_with_headers(self, mock_user_var, mock_session_var,
|
|
182
|
-
mock_get_user, mock_get_session):
|
|
183
|
-
"""Test getting session ID tuple when headers are available."""
|
|
184
|
-
mock_get_user.return_value = "header-user"
|
|
185
|
-
mock_get_session.return_value = "header-session"
|
|
186
|
-
|
|
187
|
-
result = get_session_id_tuple(None)
|
|
188
|
-
|
|
189
|
-
self.assertEqual(result, ("header-user", "header-session"))
|
|
190
|
-
mock_get_user.assert_called_once_with(None)
|
|
191
|
-
mock_get_session.assert_called_once_with(None)
|
|
192
|
-
|
|
193
|
-
@patch('aixtools.server.utils.get_session_id_from_request')
|
|
194
|
-
@patch('aixtools.server.utils.get_user_id_from_request')
|
|
195
|
-
@patch('aixtools.server.utils.session_id_var')
|
|
196
|
-
@patch('aixtools.server.utils.user_id_var')
|
|
197
|
-
def test_get_session_id_tuple_with_fallback(self, mock_user_var, mock_session_var,
|
|
198
|
-
mock_get_user, mock_get_session):
|
|
199
|
-
"""Test getting session ID tuple with fallback to context variables."""
|
|
200
|
-
mock_get_user.return_value = None
|
|
201
|
-
mock_get_session.return_value = None
|
|
202
|
-
mock_user_var.get.return_value = "context-user"
|
|
203
|
-
mock_session_var.get.return_value = "context-session"
|
|
204
|
-
|
|
205
|
-
result = get_session_id_tuple(None)
|
|
206
|
-
|
|
207
|
-
self.assertEqual(result, ("context-user", "context-session"))
|
|
208
|
-
mock_user_var.get.assert_called_once_with("default_user")
|
|
209
|
-
mock_session_var.get.assert_called_once_with("default_session")
|
|
210
|
-
|
|
211
|
-
@patch('aixtools.server.utils.get_session_id_from_request')
|
|
212
|
-
@patch('aixtools.server.utils.get_user_id_from_request')
|
|
213
|
-
@patch('aixtools.server.utils.session_id_var')
|
|
214
|
-
@patch('aixtools.server.utils.user_id_var')
|
|
215
|
-
def test_get_session_id_tuple_mixed_sources(self, mock_user_var, mock_session_var,
|
|
216
|
-
mock_get_user, mock_get_session):
|
|
217
|
-
"""Test getting session ID tuple with mixed sources."""
|
|
218
|
-
mock_get_user.return_value = "header-user"
|
|
219
|
-
mock_get_session.return_value = None
|
|
220
|
-
mock_session_var.get.return_value = "context-session"
|
|
221
|
-
|
|
222
|
-
result = get_session_id_tuple(None)
|
|
223
|
-
|
|
224
|
-
self.assertEqual(result, ("header-user", "context-session"))
|
|
225
|
-
|
|
226
|
-
def test_get_session_id_tuple_with_context(self):
|
|
227
|
-
"""Test getting session ID tuple with provided context."""
|
|
228
|
-
mock_ctx = Mock()
|
|
229
|
-
|
|
230
|
-
with patch('aixtools.server.utils.get_user_id_from_request') as mock_get_user, \
|
|
231
|
-
patch('aixtools.server.utils.get_session_id_from_request') as mock_get_session:
|
|
232
|
-
|
|
233
|
-
mock_get_user.return_value = "ctx-user"
|
|
234
|
-
mock_get_session.return_value = "ctx-session"
|
|
235
|
-
|
|
236
|
-
result = get_session_id_tuple(mock_ctx)
|
|
237
|
-
|
|
238
|
-
self.assertEqual(result, ("ctx-user", "ctx-session"))
|
|
239
|
-
mock_get_user.assert_called_once_with(mock_ctx)
|
|
240
|
-
mock_get_session.assert_called_once_with(mock_ctx)
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
class TestGetSessionIdStr(unittest.TestCase):
|
|
244
|
-
"""Test cases for get_session_id_str function."""
|
|
245
|
-
|
|
246
|
-
@patch('aixtools.server.utils.get_session_id_tuple')
|
|
247
|
-
def test_get_session_id_str(self, mock_get_tuple):
|
|
248
|
-
"""Test getting session ID string."""
|
|
249
|
-
mock_get_tuple.return_value = ("test-user", "test-session")
|
|
250
|
-
|
|
251
|
-
result = get_session_id_str(None)
|
|
252
|
-
|
|
253
|
-
self.assertEqual(result, "test-user:test-session")
|
|
254
|
-
mock_get_tuple.assert_called_once_with(None)
|
|
255
|
-
|
|
256
|
-
@patch('aixtools.server.utils.get_session_id_tuple')
|
|
257
|
-
def test_get_session_id_str_with_context(self, mock_get_tuple):
|
|
258
|
-
"""Test getting session ID string with context."""
|
|
259
|
-
mock_ctx = Mock()
|
|
260
|
-
mock_get_tuple.return_value = ("ctx-user", "ctx-session")
|
|
261
|
-
|
|
262
|
-
result = get_session_id_str(mock_ctx)
|
|
263
|
-
|
|
264
|
-
self.assertEqual(result, "ctx-user:ctx-session")
|
|
265
|
-
mock_get_tuple.assert_called_once_with(mock_ctx)
|
|
266
|
-
|
|
267
|
-
@patch('aixtools.server.utils.get_session_id_tuple')
|
|
268
|
-
def test_get_session_id_str_special_characters(self, mock_get_tuple):
|
|
269
|
-
"""Test getting session ID string with special characters."""
|
|
270
|
-
mock_get_tuple.return_value = ("user@domain.com", "session-123-abc")
|
|
271
|
-
|
|
272
|
-
result = get_session_id_str(None)
|
|
273
|
-
|
|
274
|
-
self.assertEqual(result, "user@domain.com:session-123-abc")
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
class TestRunInThread(unittest.IsolatedAsyncioTestCase):
|
|
278
|
-
"""Test cases for run_in_thread decorator."""
|
|
279
|
-
|
|
280
|
-
async def test_run_in_thread_basic_function(self):
|
|
281
|
-
"""Test run_in_thread decorator with basic function."""
|
|
282
|
-
@run_in_thread
|
|
283
|
-
def sync_function(x, y):
|
|
284
|
-
return x + y
|
|
285
|
-
|
|
286
|
-
result = await sync_function(5, 3) # type: ignore
|
|
287
|
-
|
|
288
|
-
self.assertEqual(result, 8)
|
|
289
|
-
|
|
290
|
-
async def test_run_in_thread_with_kwargs(self):
|
|
291
|
-
"""Test run_in_thread decorator with keyword arguments."""
|
|
292
|
-
@run_in_thread
|
|
293
|
-
def sync_function(x, y, multiplier=1):
|
|
294
|
-
return (x + y) * multiplier
|
|
295
|
-
|
|
296
|
-
result = await sync_function(5, 3, multiplier=2) # type: ignore
|
|
297
|
-
|
|
298
|
-
self.assertEqual(result, 16)
|
|
299
|
-
|
|
300
|
-
async def test_run_in_thread_with_exception(self):
|
|
301
|
-
"""Test run_in_thread decorator when function raises exception."""
|
|
302
|
-
@run_in_thread
|
|
303
|
-
def failing_function():
|
|
304
|
-
raise ValueError("Test error")
|
|
305
|
-
|
|
306
|
-
with self.assertRaises(ValueError) as context:
|
|
307
|
-
await failing_function() # type: ignore
|
|
308
|
-
|
|
309
|
-
self.assertEqual(str(context.exception), "Test error")
|
|
310
|
-
|
|
311
|
-
async def test_run_in_thread_preserves_function_metadata(self):
|
|
312
|
-
"""Test that run_in_thread preserves function metadata."""
|
|
313
|
-
@run_in_thread
|
|
314
|
-
def documented_function(x):
|
|
315
|
-
"""This is a test function."""
|
|
316
|
-
return x * 2
|
|
317
|
-
|
|
318
|
-
self.assertEqual(documented_function.__name__, "documented_function")
|
|
319
|
-
self.assertEqual(documented_function.__doc__, "This is a test function.")
|
|
320
|
-
|
|
321
|
-
async def test_run_in_thread_with_no_args(self):
|
|
322
|
-
"""Test run_in_thread decorator with function that takes no arguments."""
|
|
323
|
-
@run_in_thread
|
|
324
|
-
def no_args_function():
|
|
325
|
-
return "success"
|
|
326
|
-
|
|
327
|
-
result = await no_args_function() # type: ignore
|
|
328
|
-
|
|
329
|
-
self.assertEqual(result, "success")
|
|
330
|
-
|
|
331
|
-
async def test_run_in_thread_with_complex_return_type(self):
|
|
332
|
-
"""Test run_in_thread decorator with complex return type."""
|
|
333
|
-
@run_in_thread
|
|
334
|
-
def complex_function():
|
|
335
|
-
return {"key": "value", "list": [1, 2, 3], "nested": {"inner": True}}
|
|
336
|
-
|
|
337
|
-
result = await complex_function() # type: ignore
|
|
338
|
-
|
|
339
|
-
expected = {"key": "value", "list": [1, 2, 3], "nested": {"inner": True}}
|
|
340
|
-
self.assertEqual(result, expected)
|
|
341
|
-
|
|
342
|
-
@patch('asyncio.to_thread')
|
|
343
|
-
async def test_run_in_thread_calls_asyncio_to_thread(self, mock_to_thread):
|
|
344
|
-
"""Test that run_in_thread actually calls asyncio.to_thread."""
|
|
345
|
-
mock_to_thread.return_value = "mocked_result"
|
|
346
|
-
|
|
347
|
-
@run_in_thread
|
|
348
|
-
def test_function(arg1, arg2, kwarg1=None):
|
|
349
|
-
return f"{arg1}-{arg2}-{kwarg1}"
|
|
350
|
-
|
|
351
|
-
result = await test_function("a", "b", kwarg1="c") # type: ignore
|
|
352
|
-
|
|
353
|
-
self.assertEqual(result, "mocked_result")
|
|
354
|
-
mock_to_thread.assert_called_once()
|
|
355
|
-
# Verify the original function and arguments were passed
|
|
356
|
-
args, kwargs = mock_to_thread.call_args
|
|
357
|
-
self.assertEqual(args[1:], ("a", "b")) # Skip the function itself
|
|
358
|
-
self.assertEqual(kwargs, {"kwarg1": "c"})
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if __name__ == '__main__':
|
|
362
|
-
unittest.main()
|
tests/unit/utils/__init__.py
DELETED
|
File without changes
|