Skip to content

Commit ae89a86

Browse files
committed
test: Add tests with registration
#15 Branch: Run-15 Signed-off-by: Gabe Goodhart <ghart@us.ibm.com>
1 parent 5257533 commit ae89a86

1 file changed

Lines changed: 209 additions & 1 deletion

File tree

tests/commands/server/test_run.py

Lines changed: 209 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"""
99

1010
# Standard
11-
from unittest.mock import patch
11+
from unittest.mock import MagicMock, patch
1212

1313
# First-Party
1414
from cforge.commands.server.run import run
@@ -268,3 +268,211 @@ def test_run_with_all_options(self) -> None:
268268
assert "Authorization=AUTH_TOKEN" in args
269269
assert "--stateless" in args
270270
assert "--jsonResponse" in args
271+
272+
def test_run_with_registration_enabled(self) -> None:
273+
"""Test run command with auto-registration enabled (default)."""
274+
with (
275+
patch("mcpgateway.translate.main") as mock_translate,
276+
patch("multiprocessing.Process") as mock_process,
277+
patch("cforge.commands.server.run.requests") as mock_requests,
278+
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
279+
):
280+
281+
# Mock returning a 200 on health
282+
mock_get_res = MagicMock()
283+
mock_get_res.status_code = 200
284+
mock_requests.get = MagicMock(return_value=mock_get_res)
285+
286+
mock_request.return_value = {"id": "test-server-id", "name": "test-server"}
287+
288+
invoke_typer_command(run, stdio="uvx mcp-server-git", port=9000, register=True)
289+
290+
# Verify registration was attempted
291+
mock_request.assert_called_once()
292+
call_args = mock_request.call_args
293+
assert call_args[0][0] == "POST"
294+
assert call_args[0][1] == "/gateways"
295+
296+
# Verify registration data
297+
json_data = call_args[1]["json_data"]
298+
assert "name" in json_data
299+
assert "url" in json_data
300+
assert "http://127.0.0.1:9000/sse" in json_data["url"]
301+
assert json_data["transport"] == "SSE"
302+
303+
# Verify translate_main was called via Process
304+
mock_process.assert_called_once()
305+
proc_call_args = mock_process.call_args[1]
306+
assert proc_call_args.get("target") is mock_translate
307+
308+
def test_run_with_registration_disabled(self) -> None:
309+
"""Test run command with registration explicitly disabled."""
310+
with patch("mcpgateway.translate.main") as mock_translate, patch("multiprocessing.Process") as mock_process, patch("cforge.commands.server.run.make_authenticated_request") as mock_request:
311+
312+
invoke_typer_command(run, stdio="uvx mcp-server-git", port=9000, register=False)
313+
314+
# Verify registration was NOT attempted
315+
mock_request.assert_not_called()
316+
317+
# Verify translate_main was still called via Process
318+
mock_process.assert_called_once()
319+
call_args = mock_process.call_args[1]
320+
assert call_args.get("target") is mock_translate
321+
322+
def test_run_with_temporary_registration(self) -> None:
323+
"""Test run command with temporary registration (auto-cleanup)."""
324+
with (
325+
patch("mcpgateway.translate.main") as mock_translate,
326+
patch("multiprocessing.Process") as mock_process,
327+
patch("cforge.commands.server.run.requests") as mock_requests,
328+
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
329+
patch("cforge.commands.server.run.atexit") as mock_atexit,
330+
):
331+
332+
# Mock returning a 200 on health
333+
mock_get_res = MagicMock()
334+
mock_get_res.status_code = 200
335+
mock_requests.get = MagicMock(return_value=mock_get_res)
336+
337+
mock_request.return_value = {"id": "temp-server-id", "name": "temp-server"}
338+
339+
invoke_typer_command(run, stdio="uvx mcp-server-git", port=9000, temporary=True)
340+
341+
# Verify registration was attempted
342+
assert mock_request.call_count >= 1
343+
first_call = mock_request.call_args_list[0]
344+
assert first_call[0][0] == "POST"
345+
assert first_call[0][1] == "/gateways"
346+
347+
# Verify cleanup handlers were registered
348+
mock_atexit.register.assert_called_once()
349+
350+
# Verify translate_main was called via Process
351+
mock_process.assert_called_once()
352+
call_args = mock_process.call_args[1]
353+
assert call_args.get("target") is mock_translate
354+
355+
def test_run_with_custom_server_name_and_description(self) -> None:
356+
"""Test run command with custom server name and description."""
357+
with (
358+
patch("mcpgateway.translate.main") as mock_translate,
359+
patch("multiprocessing.Process") as mock_process,
360+
patch("cforge.commands.server.run.requests") as mock_requests,
361+
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
362+
):
363+
364+
# Mock returning a 200 on health
365+
mock_get_res = MagicMock()
366+
mock_get_res.status_code = 200
367+
mock_requests.get = MagicMock(return_value=mock_get_res)
368+
369+
mock_request.return_value = {"id": "custom-server-id"}
370+
371+
invoke_typer_command(
372+
run,
373+
stdio="uvx mcp-server-git",
374+
port=9000,
375+
server_name="my-custom-server",
376+
server_description="A custom MCP server for testing",
377+
register=True,
378+
)
379+
380+
# Verify registration data includes custom name and description
381+
call_args = mock_request.call_args
382+
json_data = call_args[1]["json_data"]
383+
assert json_data["name"] == "my-custom-server"
384+
assert json_data["description"] == "A custom MCP server for testing"
385+
386+
# Verify translate_main was called via Process
387+
mock_process.assert_called_once()
388+
proc_call_args = mock_process.call_args[1]
389+
assert proc_call_args.get("target") is mock_translate
390+
391+
def test_run_with_registration_failure(self) -> None:
392+
"""Test run command handles registration failure gracefully."""
393+
with (
394+
patch("mcpgateway.translate.main") as mock_translate,
395+
patch("multiprocessing.Process") as mock_process,
396+
patch("cforge.commands.server.run.requests") as mock_requests,
397+
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
398+
patch("cforge.commands.server.run.get_console") as mock_console,
399+
):
400+
401+
# Mock returning a 200 on health
402+
mock_get_res = MagicMock()
403+
mock_get_res.status_code = 200
404+
mock_requests.get = MagicMock(return_value=mock_get_res)
405+
406+
# Simulate registration failure
407+
mock_request.side_effect = Exception("Registration failed")
408+
mock_console_instance = MagicMock()
409+
mock_console.return_value = mock_console_instance
410+
411+
invoke_typer_command(run, stdio="uvx mcp-server-git", port=9000, register=True)
412+
413+
# Verify warning was printed
414+
assert any("Warning" in str(call) for call in mock_console_instance.print.call_args_list)
415+
416+
# Verify translate_main was still called via Process (server runs despite registration failure)
417+
mock_process.assert_called_once()
418+
call_args = mock_process.call_args[1]
419+
assert call_args.get("target") is mock_translate
420+
421+
def test_run_registration_auto_generates_name_from_stdio(self) -> None:
422+
"""Test that server name is auto-generated from stdio command."""
423+
with (
424+
patch("mcpgateway.translate.main") as mock_translate,
425+
patch("multiprocessing.Process") as mock_process,
426+
patch("cforge.commands.server.run.requests") as mock_requests,
427+
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
428+
):
429+
430+
# Mock returning a 200 on health
431+
mock_get_res = MagicMock()
432+
mock_get_res.status_code = 200
433+
mock_requests.get = MagicMock(return_value=mock_get_res)
434+
435+
mock_request.return_value = {"id": "auto-named-server"}
436+
437+
invoke_typer_command(run, stdio="uvx mcp-server-git", port=9000, register=True)
438+
439+
# Verify name was auto-generated
440+
call_args = mock_request.call_args
441+
json_data = call_args[1]["json_data"]
442+
assert "mcp-server-git" in json_data["name"] or "9000" in json_data["name"]
443+
444+
# Verify translate_main was called via Process
445+
mock_process.assert_called_once()
446+
proc_call_args = mock_process.call_args[1]
447+
assert proc_call_args.get("target") is mock_translate
448+
449+
def test_run_registration_with_grpc_source(self) -> None:
450+
"""Test registration with gRPC source instead of stdio."""
451+
with (
452+
patch("mcpgateway.translate.main") as mock_translate,
453+
patch("multiprocessing.Process") as mock_process,
454+
patch("cforge.commands.server.run.requests") as mock_requests,
455+
patch("cforge.commands.server.run.make_authenticated_request") as mock_request,
456+
):
457+
458+
# Mock returning a 200 on health
459+
mock_get_res = MagicMock()
460+
mock_get_res.status_code = 200
461+
mock_requests.get = MagicMock(return_value=mock_get_res)
462+
463+
mock_request.return_value = {"id": "grpc-server-id"}
464+
465+
invoke_typer_command(run, grpc="localhost:50051", port=9000, register=True)
466+
467+
# Verify registration was attempted
468+
mock_request.assert_called_once()
469+
call_args = mock_request.call_args
470+
json_data = call_args[1]["json_data"]
471+
472+
# Verify name includes grpc reference
473+
assert "grpc" in json_data["name"].lower()
474+
475+
# Verify translate_main was called via Process
476+
mock_process.assert_called_once()
477+
call_args = mock_process.call_args[1]
478+
assert call_args.get("target") is mock_translate

0 commit comments

Comments
 (0)