Spaces:
Running
Running
| import pytest | |
| from fastmcp.cli.run import ( | |
| import_server, | |
| is_url, | |
| parse_file_path, | |
| ) | |
| class TestUrlDetection: | |
| """Test URL detection functionality.""" | |
| def test_is_url_valid_http(self): | |
| """Test detection of valid HTTP URLs.""" | |
| assert is_url("http://example.com") | |
| assert is_url("http://localhost:8080") | |
| assert is_url("http://127.0.0.1:3000/path") | |
| def test_is_url_valid_https(self): | |
| """Test detection of valid HTTPS URLs.""" | |
| assert is_url("https://example.com") | |
| assert is_url("https://api.example.com/mcp") | |
| assert is_url("https://localhost:8443") | |
| def test_is_url_invalid(self): | |
| """Test detection of non-URLs.""" | |
| assert not is_url("server.py") | |
| assert not is_url("/path/to/server.py") | |
| assert not is_url("server.py:app") | |
| assert not is_url("ftp://example.com") # Not http/https | |
| assert not is_url("file:///path/to/file") | |
| class TestFilePathParsing: | |
| """Test file path parsing functionality.""" | |
| def test_parse_file_path_simple(self, tmp_path): | |
| """Test parsing simple file path without object.""" | |
| test_file = tmp_path / "server.py" | |
| test_file.write_text("# test server") | |
| file_path, server_object = parse_file_path(str(test_file)) | |
| assert file_path == test_file.resolve() | |
| assert server_object is None | |
| def test_parse_file_path_with_object(self, tmp_path): | |
| """Test parsing file path with object specification.""" | |
| test_file = tmp_path / "server.py" | |
| test_file.write_text("# test server") | |
| file_path, server_object = parse_file_path(f"{test_file}:app") | |
| assert file_path == test_file.resolve() | |
| assert server_object == "app" | |
| def test_parse_file_path_complex_object(self, tmp_path): | |
| """Test parsing file path with complex object specification.""" | |
| test_file = tmp_path / "server.py" | |
| test_file.write_text("# test server") | |
| # The current implementation splits on the last colon, so file:module:app | |
| # becomes file_path="file:module" and server_object="app" | |
| # We need to create a file with a colon in the name for this test | |
| complex_file = tmp_path / "server:module.py" | |
| complex_file.write_text("# test server") | |
| file_path, server_object = parse_file_path(f"{complex_file}:app") | |
| assert file_path == complex_file.resolve() | |
| assert server_object == "app" | |
| def test_parse_file_path_nonexistent(self): | |
| """Test parsing nonexistent file path exits.""" | |
| with pytest.raises(SystemExit) as exc_info: | |
| parse_file_path("nonexistent.py") | |
| assert exc_info.value.code == 1 | |
| def test_parse_file_path_directory(self, tmp_path): | |
| """Test parsing directory path exits.""" | |
| with pytest.raises(SystemExit) as exc_info: | |
| parse_file_path(str(tmp_path)) | |
| assert exc_info.value.code == 1 | |
| class TestServerImport: | |
| """Test server import functionality using real files.""" | |
| async def test_import_server_basic_mcp(self, tmp_path): | |
| """Test importing server with basic FastMCP server.""" | |
| test_file = tmp_path / "server.py" | |
| test_file.write_text(""" | |
| import fastmcp | |
| mcp = fastmcp.FastMCP("TestServer") | |
| @mcp.tool | |
| def greet(name: str) -> str: | |
| return f"Hello, {name}!" | |
| """) | |
| server = import_server(test_file) | |
| assert server.name == "TestServer" | |
| tools = await server.get_tools() | |
| assert "greet" in tools | |
| async def test_import_server_with_main_block(self, tmp_path): | |
| """Test importing server with if __name__ == '__main__' block.""" | |
| test_file = tmp_path / "server.py" | |
| test_file.write_text(""" | |
| import fastmcp | |
| app = fastmcp.FastMCP("MainServer") | |
| @app.tool | |
| def calculate(x: int, y: int) -> int: | |
| return x + y | |
| if __name__ == "__main__": | |
| app.run() | |
| """) | |
| server = import_server(test_file) | |
| assert server.name == "MainServer" | |
| tools = await server.get_tools() | |
| assert "calculate" in tools | |
| def test_import_server_standard_names(self, tmp_path): | |
| """Test automatic detection of standard names (mcp, server, app).""" | |
| # Test with 'mcp' name | |
| mcp_file = tmp_path / "mcp_server.py" | |
| mcp_file.write_text(""" | |
| import fastmcp | |
| mcp = fastmcp.FastMCP("MCPServer") | |
| """) | |
| server = import_server(mcp_file) | |
| assert server.name == "MCPServer" | |
| # Test with 'server' name | |
| server_file = tmp_path / "server_server.py" | |
| server_file.write_text(""" | |
| import fastmcp | |
| server = fastmcp.FastMCP("ServerServer") | |
| """) | |
| server = import_server(server_file) | |
| assert server.name == "ServerServer" | |
| # Test with 'app' name | |
| app_file = tmp_path / "app_server.py" | |
| app_file.write_text(""" | |
| import fastmcp | |
| app = fastmcp.FastMCP("AppServer") | |
| """) | |
| server = import_server(app_file) | |
| assert server.name == "AppServer" | |
| async def test_import_server_nonstandard_name(self, tmp_path): | |
| """Test importing server with non-standard object name.""" | |
| test_file = tmp_path / "server.py" | |
| test_file.write_text(""" | |
| import fastmcp | |
| my_custom_server = fastmcp.FastMCP("CustomServer") | |
| @my_custom_server.tool | |
| def custom_tool() -> str: | |
| return "custom" | |
| """) | |
| server = import_server(test_file, "my_custom_server") | |
| assert server.name == "CustomServer" | |
| tools = await server.get_tools() | |
| assert "custom_tool" in tools | |
| def test_import_server_no_standard_names_fails(self, tmp_path): | |
| """Test importing server when no standard names exist fails.""" | |
| test_file = tmp_path / "server.py" | |
| test_file.write_text(""" | |
| import fastmcp | |
| other_name = fastmcp.FastMCP("OtherServer") | |
| """) | |
| with pytest.raises(SystemExit) as exc_info: | |
| import_server(test_file) | |
| assert exc_info.value.code == 1 | |
| def test_import_server_nonexistent_object_fails(self, tmp_path): | |
| """Test importing nonexistent server object fails.""" | |
| test_file = tmp_path / "server.py" | |
| test_file.write_text(""" | |
| import fastmcp | |
| mcp = fastmcp.FastMCP("TestServer") | |
| """) | |
| with pytest.raises(SystemExit) as exc_info: | |
| import_server(test_file, "nonexistent") | |
| assert exc_info.value.code == 1 | |