aixtools 0.1.10__py3-none-any.whl → 0.2.0__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/agents/agent.py +26 -7
- aixtools/agents/print_nodes.py +54 -0
- aixtools/agents/prompt.py +2 -2
- aixtools/compliance/private_data.py +1 -1
- aixtools/evals/discovery.py +174 -0
- aixtools/evals/evals.py +74 -0
- aixtools/evals/run_evals.py +110 -0
- aixtools/logging/log_objects.py +24 -23
- aixtools/mcp/client.py +148 -2
- aixtools/server/__init__.py +0 -6
- aixtools/server/path.py +88 -31
- aixtools/testing/aix_test_model.py +9 -1
- aixtools/tools/doctor/mcp_tool_doctor.py +79 -0
- aixtools/tools/doctor/tool_doctor.py +4 -0
- aixtools/tools/doctor/tool_recommendation.py +5 -0
- aixtools/utils/config.py +0 -1
- {aixtools-0.1.10.dist-info → aixtools-0.2.0.dist-info}/METADATA +186 -30
- {aixtools-0.1.10.dist-info → aixtools-0.2.0.dist-info}/RECORD +23 -55
- aixtools-0.2.0.dist-info/entry_points.txt +4 -0
- aixtools-0.2.0.dist-info/top_level.txt +1 -0
- aixtools/server/workspace_privacy.py +0 -65
- aixtools-0.1.10.dist-info/entry_points.txt +0 -2
- 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/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
- {tests → aixtools/evals}/__init__.py +0 -0
- {aixtools-0.1.10.dist-info → aixtools-0.2.0.dist-info}/WHEEL +0 -0
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
|
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()
|