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.

Files changed (46) hide show
  1. aixtools/_version.py +2 -2
  2. aixtools/mcp/client.py +102 -1
  3. aixtools/testing/aix_test_model.py +2 -0
  4. {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/METADATA +2 -1
  5. {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/RECORD +8 -45
  6. aixtools-0.1.11.dist-info/top_level.txt +1 -0
  7. aixtools-0.1.10.dist-info/top_level.txt +0 -5
  8. docker/mcp-base/Dockerfile +0 -33
  9. docker/mcp-base/zscaler.crt +0 -28
  10. notebooks/example_faulty_mcp_server.ipynb +0 -74
  11. notebooks/example_mcp_server_stdio.ipynb +0 -76
  12. notebooks/example_raw_mcp_client.ipynb +0 -84
  13. notebooks/example_tool_doctor.ipynb +0 -65
  14. scripts/config.sh +0 -28
  15. scripts/lint.sh +0 -32
  16. scripts/log_view.sh +0 -18
  17. scripts/run_example_mcp_server.sh +0 -14
  18. scripts/run_faulty_mcp_server.sh +0 -13
  19. scripts/run_server.sh +0 -29
  20. scripts/test.sh +0 -30
  21. tests/__init__.py +0 -0
  22. tests/unit/__init__.py +0 -0
  23. tests/unit/a2a/__init__.py +0 -0
  24. tests/unit/a2a/google_sdk/__init__.py +0 -0
  25. tests/unit/a2a/google_sdk/pydantic_ai_adapter/__init__.py +0 -0
  26. tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_agent_executor.py +0 -188
  27. tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_storage.py +0 -156
  28. tests/unit/a2a/google_sdk/test_card.py +0 -114
  29. tests/unit/a2a/google_sdk/test_remote_agent_connection.py +0 -413
  30. tests/unit/a2a/google_sdk/test_utils.py +0 -208
  31. tests/unit/agents/__init__.py +0 -0
  32. tests/unit/agents/test_prompt.py +0 -363
  33. tests/unit/compliance/test_private_data.py +0 -329
  34. tests/unit/google/__init__.py +0 -1
  35. tests/unit/google/test_client.py +0 -233
  36. tests/unit/mcp/__init__.py +0 -0
  37. tests/unit/mcp/test_client.py +0 -242
  38. tests/unit/server/__init__.py +0 -0
  39. tests/unit/server/test_path.py +0 -225
  40. tests/unit/server/test_utils.py +0 -362
  41. tests/unit/utils/__init__.py +0 -0
  42. tests/unit/utils/test_files.py +0 -146
  43. tests/unit/vault/__init__.py +0 -0
  44. tests/unit/vault/test_vault.py +0 -246
  45. {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/WHEEL +0 -0
  46. {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/entry_points.txt +0 -0
@@ -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()
@@ -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()
File without changes