kubectl-mcp-server 1.19.2__py3-none-any.whl → 1.21.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.
- {kubectl_mcp_server-1.19.2.dist-info → kubectl_mcp_server-1.21.0.dist-info}/METADATA +26 -18
- {kubectl_mcp_server-1.19.2.dist-info → kubectl_mcp_server-1.21.0.dist-info}/RECORD +13 -9
- kubectl_mcp_tool/__init__.py +1 -1
- kubectl_mcp_tool/mcp_server.py +5 -1
- kubectl_mcp_tool/tools/__init__.py +4 -0
- kubectl_mcp_tool/tools/kind.py +1723 -0
- kubectl_mcp_tool/tools/vind.py +744 -0
- tests/test_kind.py +1206 -0
- tests/test_vind.py +512 -0
- {kubectl_mcp_server-1.19.2.dist-info → kubectl_mcp_server-1.21.0.dist-info}/WHEEL +0 -0
- {kubectl_mcp_server-1.19.2.dist-info → kubectl_mcp_server-1.21.0.dist-info}/entry_points.txt +0 -0
- {kubectl_mcp_server-1.19.2.dist-info → kubectl_mcp_server-1.21.0.dist-info}/licenses/LICENSE +0 -0
- {kubectl_mcp_server-1.19.2.dist-info → kubectl_mcp_server-1.21.0.dist-info}/top_level.txt +0 -0
tests/test_vind.py
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for vind (vCluster in Docker) tools.
|
|
3
|
+
|
|
4
|
+
This module tests the vCluster management toolset.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
import json
|
|
9
|
+
from unittest.mock import patch, MagicMock
|
|
10
|
+
import subprocess
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestVindHelpers:
|
|
14
|
+
"""Tests for vind helper functions."""
|
|
15
|
+
|
|
16
|
+
@pytest.mark.unit
|
|
17
|
+
def test_vind_module_imports(self):
|
|
18
|
+
"""Test that vind module can be imported."""
|
|
19
|
+
from kubectl_mcp_tool.tools.vind import (
|
|
20
|
+
register_vind_tools,
|
|
21
|
+
_vcluster_available,
|
|
22
|
+
_get_vcluster_version,
|
|
23
|
+
_run_vcluster,
|
|
24
|
+
vind_detect,
|
|
25
|
+
vind_list_clusters,
|
|
26
|
+
vind_status,
|
|
27
|
+
vind_get_kubeconfig,
|
|
28
|
+
vind_logs,
|
|
29
|
+
vind_create_cluster,
|
|
30
|
+
vind_delete_cluster,
|
|
31
|
+
vind_pause,
|
|
32
|
+
vind_resume,
|
|
33
|
+
vind_connect,
|
|
34
|
+
vind_disconnect,
|
|
35
|
+
vind_upgrade,
|
|
36
|
+
vind_describe,
|
|
37
|
+
vind_platform_start,
|
|
38
|
+
)
|
|
39
|
+
assert callable(register_vind_tools)
|
|
40
|
+
assert callable(_vcluster_available)
|
|
41
|
+
assert callable(_get_vcluster_version)
|
|
42
|
+
assert callable(_run_vcluster)
|
|
43
|
+
assert callable(vind_detect)
|
|
44
|
+
assert callable(vind_list_clusters)
|
|
45
|
+
assert callable(vind_status)
|
|
46
|
+
assert callable(vind_get_kubeconfig)
|
|
47
|
+
assert callable(vind_logs)
|
|
48
|
+
assert callable(vind_create_cluster)
|
|
49
|
+
assert callable(vind_delete_cluster)
|
|
50
|
+
assert callable(vind_pause)
|
|
51
|
+
assert callable(vind_resume)
|
|
52
|
+
assert callable(vind_connect)
|
|
53
|
+
assert callable(vind_disconnect)
|
|
54
|
+
assert callable(vind_upgrade)
|
|
55
|
+
assert callable(vind_describe)
|
|
56
|
+
assert callable(vind_platform_start)
|
|
57
|
+
|
|
58
|
+
@pytest.mark.unit
|
|
59
|
+
def test_vcluster_available_when_installed(self):
|
|
60
|
+
"""Test _vcluster_available returns True when CLI is installed."""
|
|
61
|
+
from kubectl_mcp_tool.tools.vind import _vcluster_available
|
|
62
|
+
|
|
63
|
+
with patch("subprocess.run") as mock_run:
|
|
64
|
+
mock_run.return_value = MagicMock(returncode=0)
|
|
65
|
+
result = _vcluster_available()
|
|
66
|
+
assert result is True
|
|
67
|
+
|
|
68
|
+
@pytest.mark.unit
|
|
69
|
+
def test_vcluster_available_when_not_installed(self):
|
|
70
|
+
"""Test _vcluster_available returns False when CLI is not installed."""
|
|
71
|
+
from kubectl_mcp_tool.tools.vind import _vcluster_available
|
|
72
|
+
|
|
73
|
+
with patch("subprocess.run") as mock_run:
|
|
74
|
+
mock_run.side_effect = FileNotFoundError()
|
|
75
|
+
result = _vcluster_available()
|
|
76
|
+
assert result is False
|
|
77
|
+
|
|
78
|
+
@pytest.mark.unit
|
|
79
|
+
def test_get_vcluster_version(self):
|
|
80
|
+
"""Test _get_vcluster_version extracts version correctly."""
|
|
81
|
+
from kubectl_mcp_tool.tools.vind import _get_vcluster_version
|
|
82
|
+
|
|
83
|
+
with patch("subprocess.run") as mock_run:
|
|
84
|
+
mock_run.return_value = MagicMock(
|
|
85
|
+
returncode=0,
|
|
86
|
+
stdout="vcluster version v0.19.0"
|
|
87
|
+
)
|
|
88
|
+
result = _get_vcluster_version()
|
|
89
|
+
assert result == "v0.19.0"
|
|
90
|
+
|
|
91
|
+
@pytest.mark.unit
|
|
92
|
+
def test_get_vcluster_version_not_installed(self):
|
|
93
|
+
"""Test _get_vcluster_version returns None when not installed."""
|
|
94
|
+
from kubectl_mcp_tool.tools.vind import _get_vcluster_version
|
|
95
|
+
|
|
96
|
+
with patch("subprocess.run") as mock_run:
|
|
97
|
+
mock_run.side_effect = FileNotFoundError()
|
|
98
|
+
result = _get_vcluster_version()
|
|
99
|
+
assert result is None
|
|
100
|
+
|
|
101
|
+
@pytest.mark.unit
|
|
102
|
+
def test_run_vcluster_not_available(self):
|
|
103
|
+
"""Test _run_vcluster returns error when CLI not available."""
|
|
104
|
+
from kubectl_mcp_tool.tools.vind import _run_vcluster
|
|
105
|
+
|
|
106
|
+
with patch("subprocess.run") as mock_run:
|
|
107
|
+
mock_run.side_effect = FileNotFoundError()
|
|
108
|
+
result = _run_vcluster(["list"])
|
|
109
|
+
assert result["success"] is False
|
|
110
|
+
assert "not available" in result["error"]
|
|
111
|
+
|
|
112
|
+
@pytest.mark.unit
|
|
113
|
+
def test_run_vcluster_success(self):
|
|
114
|
+
"""Test _run_vcluster returns success on successful command."""
|
|
115
|
+
from kubectl_mcp_tool.tools.vind import _run_vcluster
|
|
116
|
+
|
|
117
|
+
with patch("subprocess.run") as mock_run:
|
|
118
|
+
# First call for availability check
|
|
119
|
+
mock_run.return_value = MagicMock(
|
|
120
|
+
returncode=0,
|
|
121
|
+
stdout="test output",
|
|
122
|
+
stderr=""
|
|
123
|
+
)
|
|
124
|
+
result = _run_vcluster(["list"])
|
|
125
|
+
assert result["success"] is True
|
|
126
|
+
assert result["output"] == "test output"
|
|
127
|
+
|
|
128
|
+
@pytest.mark.unit
|
|
129
|
+
def test_run_vcluster_timeout(self):
|
|
130
|
+
"""Test _run_vcluster handles timeout."""
|
|
131
|
+
from kubectl_mcp_tool.tools.vind import _run_vcluster
|
|
132
|
+
|
|
133
|
+
with patch("subprocess.run") as mock_run:
|
|
134
|
+
# First call succeeds (availability check), second times out
|
|
135
|
+
mock_run.side_effect = [
|
|
136
|
+
MagicMock(returncode=0), # availability check
|
|
137
|
+
subprocess.TimeoutExpired(cmd="vcluster", timeout=120)
|
|
138
|
+
]
|
|
139
|
+
result = _run_vcluster(["create", "test"])
|
|
140
|
+
assert result["success"] is False
|
|
141
|
+
assert "timed out" in result["error"]
|
|
142
|
+
|
|
143
|
+
@pytest.mark.unit
|
|
144
|
+
def test_run_vcluster_with_json_output(self):
|
|
145
|
+
"""Test _run_vcluster parses JSON output."""
|
|
146
|
+
from kubectl_mcp_tool.tools.vind import _run_vcluster
|
|
147
|
+
|
|
148
|
+
with patch("subprocess.run") as mock_run:
|
|
149
|
+
mock_run.return_value = MagicMock(
|
|
150
|
+
returncode=0,
|
|
151
|
+
stdout='[{"Name": "test", "Status": "Running"}]',
|
|
152
|
+
stderr=""
|
|
153
|
+
)
|
|
154
|
+
result = _run_vcluster(["list"], json_output=True)
|
|
155
|
+
assert result["success"] is True
|
|
156
|
+
assert result["data"] == [{"Name": "test", "Status": "Running"}]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class TestVindDetect:
|
|
160
|
+
"""Tests for vind_detect function."""
|
|
161
|
+
|
|
162
|
+
@pytest.mark.unit
|
|
163
|
+
def test_vind_detect_installed(self):
|
|
164
|
+
"""Test vind_detect when vcluster is installed."""
|
|
165
|
+
from kubectl_mcp_tool.tools.vind import vind_detect
|
|
166
|
+
|
|
167
|
+
with patch("subprocess.run") as mock_run:
|
|
168
|
+
mock_run.return_value = MagicMock(
|
|
169
|
+
returncode=0,
|
|
170
|
+
stdout="vcluster version v0.19.0"
|
|
171
|
+
)
|
|
172
|
+
result = vind_detect()
|
|
173
|
+
assert result["installed"] is True
|
|
174
|
+
assert result["cli_available"] is True
|
|
175
|
+
assert result["version"] == "v0.19.0"
|
|
176
|
+
assert result["install_instructions"] is None
|
|
177
|
+
|
|
178
|
+
@pytest.mark.unit
|
|
179
|
+
def test_vind_detect_not_installed(self):
|
|
180
|
+
"""Test vind_detect when vcluster is not installed."""
|
|
181
|
+
from kubectl_mcp_tool.tools.vind import vind_detect
|
|
182
|
+
|
|
183
|
+
with patch("subprocess.run") as mock_run:
|
|
184
|
+
mock_run.side_effect = FileNotFoundError()
|
|
185
|
+
result = vind_detect()
|
|
186
|
+
assert result["installed"] is False
|
|
187
|
+
assert result["cli_available"] is False
|
|
188
|
+
assert result["version"] is None
|
|
189
|
+
assert result["install_instructions"] is not None
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class TestVindListClusters:
|
|
193
|
+
"""Tests for vind_list_clusters function."""
|
|
194
|
+
|
|
195
|
+
@pytest.mark.unit
|
|
196
|
+
def test_vind_list_clusters_success(self):
|
|
197
|
+
"""Test vind_list_clusters returns cluster list."""
|
|
198
|
+
from kubectl_mcp_tool.tools.vind import vind_list_clusters
|
|
199
|
+
|
|
200
|
+
mock_clusters = [
|
|
201
|
+
{
|
|
202
|
+
"Name": "dev-cluster",
|
|
203
|
+
"Namespace": "vcluster-dev",
|
|
204
|
+
"Status": "Running",
|
|
205
|
+
"Version": "v1.29.0",
|
|
206
|
+
"Connected": True,
|
|
207
|
+
"Created": "2024-01-01T00:00:00Z",
|
|
208
|
+
"Age": "1d"
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
with patch("kubectl_mcp_tool.tools.vind._vcluster_available", return_value=True):
|
|
213
|
+
with patch("kubectl_mcp_tool.tools.vind.subprocess.run") as mock_run:
|
|
214
|
+
mock_run.return_value = MagicMock(
|
|
215
|
+
returncode=0,
|
|
216
|
+
stdout=json.dumps(mock_clusters),
|
|
217
|
+
stderr=""
|
|
218
|
+
)
|
|
219
|
+
result = vind_list_clusters()
|
|
220
|
+
assert result["success"] is True
|
|
221
|
+
assert result["total"] == 1
|
|
222
|
+
assert len(result["clusters"]) == 1
|
|
223
|
+
assert result["clusters"][0]["name"] == "dev-cluster"
|
|
224
|
+
|
|
225
|
+
@pytest.mark.unit
|
|
226
|
+
def test_vind_list_clusters_empty(self):
|
|
227
|
+
"""Test vind_list_clusters returns empty list."""
|
|
228
|
+
from kubectl_mcp_tool.tools.vind import vind_list_clusters
|
|
229
|
+
|
|
230
|
+
with patch("kubectl_mcp_tool.tools.vind._vcluster_available", return_value=True):
|
|
231
|
+
with patch("kubectl_mcp_tool.tools.vind.subprocess.run") as mock_run:
|
|
232
|
+
mock_run.return_value = MagicMock(
|
|
233
|
+
returncode=0,
|
|
234
|
+
stdout="[]",
|
|
235
|
+
stderr=""
|
|
236
|
+
)
|
|
237
|
+
result = vind_list_clusters()
|
|
238
|
+
assert result["success"] is True
|
|
239
|
+
assert result["total"] == 0
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class TestVindCreateCluster:
|
|
243
|
+
"""Tests for vind_create_cluster function."""
|
|
244
|
+
|
|
245
|
+
@pytest.mark.unit
|
|
246
|
+
def test_vind_create_cluster_basic(self):
|
|
247
|
+
"""Test vind_create_cluster with basic options."""
|
|
248
|
+
from kubectl_mcp_tool.tools.vind import vind_create_cluster
|
|
249
|
+
|
|
250
|
+
with patch("subprocess.run") as mock_run:
|
|
251
|
+
mock_run.return_value = MagicMock(
|
|
252
|
+
returncode=0,
|
|
253
|
+
stdout="vCluster 'test' created successfully",
|
|
254
|
+
stderr=""
|
|
255
|
+
)
|
|
256
|
+
result = vind_create_cluster(name="test")
|
|
257
|
+
assert result["success"] is True
|
|
258
|
+
assert "created" in result["message"].lower()
|
|
259
|
+
|
|
260
|
+
@pytest.mark.unit
|
|
261
|
+
def test_vind_create_cluster_with_options(self):
|
|
262
|
+
"""Test vind_create_cluster with all options."""
|
|
263
|
+
from kubectl_mcp_tool.tools.vind import vind_create_cluster
|
|
264
|
+
|
|
265
|
+
with patch("subprocess.run") as mock_run:
|
|
266
|
+
mock_run.return_value = MagicMock(
|
|
267
|
+
returncode=0,
|
|
268
|
+
stdout="vCluster 'prod' created successfully",
|
|
269
|
+
stderr=""
|
|
270
|
+
)
|
|
271
|
+
result = vind_create_cluster(
|
|
272
|
+
name="prod",
|
|
273
|
+
namespace="production",
|
|
274
|
+
kubernetes_version="v1.29.0",
|
|
275
|
+
set_values=["sync.toHost.pods.enabled=true"],
|
|
276
|
+
connect=True
|
|
277
|
+
)
|
|
278
|
+
assert result["success"] is True
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class TestVindPauseResume:
|
|
282
|
+
"""Tests for vind_pause and vind_resume functions."""
|
|
283
|
+
|
|
284
|
+
@pytest.mark.unit
|
|
285
|
+
def test_vind_pause_success(self):
|
|
286
|
+
"""Test vind_pause pauses cluster."""
|
|
287
|
+
from kubectl_mcp_tool.tools.vind import vind_pause
|
|
288
|
+
|
|
289
|
+
with patch("subprocess.run") as mock_run:
|
|
290
|
+
mock_run.return_value = MagicMock(
|
|
291
|
+
returncode=0,
|
|
292
|
+
stdout="vCluster 'test' paused",
|
|
293
|
+
stderr=""
|
|
294
|
+
)
|
|
295
|
+
result = vind_pause(name="test")
|
|
296
|
+
assert result["success"] is True
|
|
297
|
+
assert "paused" in result["message"].lower()
|
|
298
|
+
|
|
299
|
+
@pytest.mark.unit
|
|
300
|
+
def test_vind_resume_success(self):
|
|
301
|
+
"""Test vind_resume resumes cluster."""
|
|
302
|
+
from kubectl_mcp_tool.tools.vind import vind_resume
|
|
303
|
+
|
|
304
|
+
with patch("subprocess.run") as mock_run:
|
|
305
|
+
mock_run.return_value = MagicMock(
|
|
306
|
+
returncode=0,
|
|
307
|
+
stdout="vCluster 'test' resumed",
|
|
308
|
+
stderr=""
|
|
309
|
+
)
|
|
310
|
+
result = vind_resume(name="test")
|
|
311
|
+
assert result["success"] is True
|
|
312
|
+
assert "resumed" in result["message"].lower()
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
class TestVindConnect:
|
|
316
|
+
"""Tests for vind_connect and vind_disconnect functions."""
|
|
317
|
+
|
|
318
|
+
@pytest.mark.unit
|
|
319
|
+
def test_vind_connect_success(self):
|
|
320
|
+
"""Test vind_connect connects to cluster."""
|
|
321
|
+
from kubectl_mcp_tool.tools.vind import vind_connect
|
|
322
|
+
|
|
323
|
+
with patch("subprocess.run") as mock_run:
|
|
324
|
+
mock_run.return_value = MagicMock(
|
|
325
|
+
returncode=0,
|
|
326
|
+
stdout="Connected to vCluster 'test'",
|
|
327
|
+
stderr=""
|
|
328
|
+
)
|
|
329
|
+
result = vind_connect(name="test")
|
|
330
|
+
assert result["success"] is True
|
|
331
|
+
assert "connected" in result["message"].lower()
|
|
332
|
+
|
|
333
|
+
@pytest.mark.unit
|
|
334
|
+
def test_vind_disconnect_success(self):
|
|
335
|
+
"""Test vind_disconnect disconnects from cluster."""
|
|
336
|
+
from kubectl_mcp_tool.tools.vind import vind_disconnect
|
|
337
|
+
|
|
338
|
+
with patch("subprocess.run") as mock_run:
|
|
339
|
+
mock_run.return_value = MagicMock(
|
|
340
|
+
returncode=0,
|
|
341
|
+
stdout="Disconnected",
|
|
342
|
+
stderr=""
|
|
343
|
+
)
|
|
344
|
+
result = vind_disconnect("", "")
|
|
345
|
+
assert result["success"] is True
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class TestVindToolsRegistration:
|
|
349
|
+
"""Tests for vind tools registration."""
|
|
350
|
+
|
|
351
|
+
@pytest.mark.unit
|
|
352
|
+
def test_vind_tools_import(self):
|
|
353
|
+
"""Test that vind tools can be imported."""
|
|
354
|
+
from kubectl_mcp_tool.tools.vind import register_vind_tools
|
|
355
|
+
assert callable(register_vind_tools)
|
|
356
|
+
|
|
357
|
+
@pytest.mark.unit
|
|
358
|
+
@pytest.mark.asyncio
|
|
359
|
+
async def test_vind_tools_register(self, mock_all_kubernetes_apis):
|
|
360
|
+
"""Test that vind tools register correctly."""
|
|
361
|
+
from kubectl_mcp_tool.mcp_server import MCPServer
|
|
362
|
+
|
|
363
|
+
with patch("kubectl_mcp_tool.mcp_server.MCPServer._check_dependencies", return_value=True):
|
|
364
|
+
server = MCPServer(name="test")
|
|
365
|
+
|
|
366
|
+
tools = await server.server.list_tools()
|
|
367
|
+
tool_names = {t.name for t in tools}
|
|
368
|
+
|
|
369
|
+
vind_tools = [
|
|
370
|
+
"vind_detect_tool",
|
|
371
|
+
"vind_list_clusters_tool",
|
|
372
|
+
"vind_status_tool",
|
|
373
|
+
"vind_get_kubeconfig_tool",
|
|
374
|
+
"vind_logs_tool",
|
|
375
|
+
"vind_create_cluster_tool",
|
|
376
|
+
"vind_delete_cluster_tool",
|
|
377
|
+
"vind_pause_tool",
|
|
378
|
+
"vind_resume_tool",
|
|
379
|
+
"vind_connect_tool",
|
|
380
|
+
"vind_disconnect_tool",
|
|
381
|
+
"vind_upgrade_tool",
|
|
382
|
+
"vind_describe_tool",
|
|
383
|
+
"vind_platform_start_tool",
|
|
384
|
+
]
|
|
385
|
+
for tool in vind_tools:
|
|
386
|
+
assert tool in tool_names, f"vind tool '{tool}' not registered"
|
|
387
|
+
|
|
388
|
+
@pytest.mark.unit
|
|
389
|
+
@pytest.mark.asyncio
|
|
390
|
+
async def test_vind_tool_count(self, mock_all_kubernetes_apis):
|
|
391
|
+
"""Test that correct number of vind tools are registered."""
|
|
392
|
+
from kubectl_mcp_tool.mcp_server import MCPServer
|
|
393
|
+
|
|
394
|
+
with patch("kubectl_mcp_tool.mcp_server.MCPServer._check_dependencies", return_value=True):
|
|
395
|
+
server = MCPServer(name="test")
|
|
396
|
+
|
|
397
|
+
tools = await server.server.list_tools()
|
|
398
|
+
tool_names = {t.name for t in tools}
|
|
399
|
+
vind_tools = [name for name in tool_names if name.startswith("vind_")]
|
|
400
|
+
assert len(vind_tools) == 14, f"Expected 14 vind tools, got {len(vind_tools)}: {vind_tools}"
|
|
401
|
+
|
|
402
|
+
@pytest.mark.unit
|
|
403
|
+
def test_vind_non_destructive_mode(self, mock_all_kubernetes_apis):
|
|
404
|
+
"""Test that vind write operations are blocked in non-destructive mode."""
|
|
405
|
+
from kubectl_mcp_tool.mcp_server import MCPServer
|
|
406
|
+
|
|
407
|
+
with patch("kubectl_mcp_tool.mcp_server.MCPServer._check_dependencies", return_value=True):
|
|
408
|
+
server = MCPServer(name="test", disable_destructive=True)
|
|
409
|
+
|
|
410
|
+
assert server.non_destructive is True
|
|
411
|
+
|
|
412
|
+
@pytest.mark.unit
|
|
413
|
+
@pytest.mark.asyncio
|
|
414
|
+
async def test_vind_tools_have_descriptions(self, mock_all_kubernetes_apis):
|
|
415
|
+
"""Test that all vind tools have descriptions."""
|
|
416
|
+
from kubectl_mcp_tool.mcp_server import MCPServer
|
|
417
|
+
|
|
418
|
+
with patch("kubectl_mcp_tool.mcp_server.MCPServer._check_dependencies", return_value=True):
|
|
419
|
+
server = MCPServer(name="test")
|
|
420
|
+
|
|
421
|
+
tools = await server.server.list_tools()
|
|
422
|
+
vind_tools = [t for t in tools if t.name.startswith("vind_")]
|
|
423
|
+
tools_without_description = [
|
|
424
|
+
t.name for t in vind_tools
|
|
425
|
+
if not t.description or len(t.description.strip()) == 0
|
|
426
|
+
]
|
|
427
|
+
assert not tools_without_description, f"vind tools without descriptions: {tools_without_description}"
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
class TestVindNonDestructiveBlocking:
|
|
431
|
+
"""Tests for non-destructive mode blocking of vind write operations."""
|
|
432
|
+
|
|
433
|
+
@pytest.mark.unit
|
|
434
|
+
@pytest.mark.asyncio
|
|
435
|
+
async def test_create_blocked_in_non_destructive(self, mock_all_kubernetes_apis):
|
|
436
|
+
"""Test that vind_create_cluster_tool is blocked in non-destructive mode."""
|
|
437
|
+
from kubectl_mcp_tool.tools.vind import register_vind_tools
|
|
438
|
+
|
|
439
|
+
try:
|
|
440
|
+
from fastmcp import FastMCP
|
|
441
|
+
except ImportError:
|
|
442
|
+
from mcp.server.fastmcp import FastMCP
|
|
443
|
+
|
|
444
|
+
mcp = FastMCP(name="test")
|
|
445
|
+
register_vind_tools(mcp, non_destructive=True)
|
|
446
|
+
|
|
447
|
+
tool = await mcp.get_tool("vind_create_cluster_tool")
|
|
448
|
+
result = tool.fn(name="test")
|
|
449
|
+
result_dict = json.loads(result)
|
|
450
|
+
assert result_dict["success"] is False
|
|
451
|
+
assert "non-destructive" in result_dict["error"].lower()
|
|
452
|
+
|
|
453
|
+
@pytest.mark.unit
|
|
454
|
+
@pytest.mark.asyncio
|
|
455
|
+
async def test_delete_blocked_in_non_destructive(self, mock_all_kubernetes_apis):
|
|
456
|
+
"""Test that vind_delete_cluster_tool is blocked in non-destructive mode."""
|
|
457
|
+
from kubectl_mcp_tool.tools.vind import register_vind_tools
|
|
458
|
+
|
|
459
|
+
try:
|
|
460
|
+
from fastmcp import FastMCP
|
|
461
|
+
except ImportError:
|
|
462
|
+
from mcp.server.fastmcp import FastMCP
|
|
463
|
+
|
|
464
|
+
mcp = FastMCP(name="test")
|
|
465
|
+
register_vind_tools(mcp, non_destructive=True)
|
|
466
|
+
|
|
467
|
+
tool = await mcp.get_tool("vind_delete_cluster_tool")
|
|
468
|
+
result = tool.fn(name="test")
|
|
469
|
+
result_dict = json.loads(result)
|
|
470
|
+
assert result_dict["success"] is False
|
|
471
|
+
assert "non-destructive" in result_dict["error"].lower()
|
|
472
|
+
|
|
473
|
+
@pytest.mark.unit
|
|
474
|
+
@pytest.mark.asyncio
|
|
475
|
+
async def test_pause_blocked_in_non_destructive(self, mock_all_kubernetes_apis):
|
|
476
|
+
"""Test that vind_pause_tool is blocked in non-destructive mode."""
|
|
477
|
+
from kubectl_mcp_tool.tools.vind import register_vind_tools
|
|
478
|
+
|
|
479
|
+
try:
|
|
480
|
+
from fastmcp import FastMCP
|
|
481
|
+
except ImportError:
|
|
482
|
+
from mcp.server.fastmcp import FastMCP
|
|
483
|
+
|
|
484
|
+
mcp = FastMCP(name="test")
|
|
485
|
+
register_vind_tools(mcp, non_destructive=True)
|
|
486
|
+
|
|
487
|
+
tool = await mcp.get_tool("vind_pause_tool")
|
|
488
|
+
result = tool.fn(name="test")
|
|
489
|
+
result_dict = json.loads(result)
|
|
490
|
+
assert result_dict["success"] is False
|
|
491
|
+
assert "non-destructive" in result_dict["error"].lower()
|
|
492
|
+
|
|
493
|
+
@pytest.mark.unit
|
|
494
|
+
@pytest.mark.asyncio
|
|
495
|
+
async def test_read_operations_allowed_in_non_destructive(self, mock_all_kubernetes_apis):
|
|
496
|
+
"""Test that read operations work in non-destructive mode."""
|
|
497
|
+
from kubectl_mcp_tool.tools.vind import register_vind_tools
|
|
498
|
+
|
|
499
|
+
try:
|
|
500
|
+
from fastmcp import FastMCP
|
|
501
|
+
except ImportError:
|
|
502
|
+
from mcp.server.fastmcp import FastMCP
|
|
503
|
+
|
|
504
|
+
mcp = FastMCP(name="test")
|
|
505
|
+
register_vind_tools(mcp, non_destructive=True)
|
|
506
|
+
|
|
507
|
+
tool = await mcp.get_tool("vind_detect_tool")
|
|
508
|
+
with patch("subprocess.run") as mock_run:
|
|
509
|
+
mock_run.side_effect = FileNotFoundError()
|
|
510
|
+
result = tool.fn()
|
|
511
|
+
result_dict = json.loads(result)
|
|
512
|
+
assert "installed" in result_dict
|
|
File without changes
|
{kubectl_mcp_server-1.19.2.dist-info → kubectl_mcp_server-1.21.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{kubectl_mcp_server-1.19.2.dist-info → kubectl_mcp_server-1.21.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|