chore: import upstream snapshot with attribution
Deploy Docs / deploy-docs (push) Failing after 1s
Conformance Tests / client-conformance (push) Failing after 3s
Conformance Tests / server-conformance (push) Failing after 1s
GitHub Actions Security Analysis / zizmor (push) Failing after 1s
CI / checks (push) Failing after 59m20s
CI / all-green (push) Waiting to run
Deploy Docs / deploy-docs (push) Failing after 1s
Conformance Tests / client-conformance (push) Failing after 3s
Conformance Tests / server-conformance (push) Failing after 1s
GitHub Actions Security Analysis / zizmor (push) Failing after 1s
CI / checks (push) Failing after 59m20s
CI / all-green (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import importlib.metadata
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from mcp.cli.cli import _build_uv_command, _get_npx_command, _parse_file_path # type: ignore[reportPrivateUsage]
|
||||
|
||||
|
||||
def _set_mcp_version(monkeypatch: pytest.MonkeyPatch, version: str) -> None:
|
||||
real_version = importlib.metadata.version
|
||||
|
||||
def fake_version(distribution_name: str) -> str:
|
||||
return version if distribution_name == "mcp" else real_version(distribution_name)
|
||||
|
||||
monkeypatch.setattr(importlib.metadata, "version", fake_version)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"spec, expected_obj",
|
||||
[
|
||||
("server.py", None),
|
||||
("foo.py:srv_obj", "srv_obj"),
|
||||
],
|
||||
)
|
||||
def test_parse_file_path_accepts_valid_specs(tmp_path: Path, spec: str, expected_obj: str | None):
|
||||
"""Should accept valid file specs."""
|
||||
file = tmp_path / spec.split(":")[0]
|
||||
file.write_text("x = 1")
|
||||
path, obj = _parse_file_path(f"{file}:{expected_obj}" if ":" in spec else str(file))
|
||||
assert path == file.resolve()
|
||||
assert obj == expected_obj
|
||||
|
||||
|
||||
def test_parse_file_path_missing(tmp_path: Path):
|
||||
"""Should system exit if a file is missing."""
|
||||
with pytest.raises(SystemExit):
|
||||
_parse_file_path(str(tmp_path / "missing.py"))
|
||||
|
||||
|
||||
def test_parse_file_exit_on_dir(tmp_path: Path):
|
||||
"""Should system exit if a directory is passed"""
|
||||
dir_path = tmp_path / "dir"
|
||||
dir_path.mkdir()
|
||||
with pytest.raises(SystemExit):
|
||||
_parse_file_path(str(dir_path))
|
||||
|
||||
|
||||
def test_build_uv_command_pins_the_running_mcp_version(monkeypatch: pytest.MonkeyPatch):
|
||||
"""The spawned environment installs the same SDK version that is running, not the latest stable."""
|
||||
_set_mcp_version(monkeypatch, "1.2.3")
|
||||
cmd = _build_uv_command("foo.py")
|
||||
assert cmd == ["uv", "run", "--with", "mcp==1.2.3", "mcp", "run", "foo.py"]
|
||||
|
||||
|
||||
def test_build_uv_command_leaves_source_builds_unpinned(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Source-build versions are not on PyPI, so the requirement stays unpinned."""
|
||||
_set_mcp_version(monkeypatch, "2.0.0a2.dev3+g0123abc")
|
||||
cmd = _build_uv_command("foo.py")
|
||||
assert cmd == ["uv", "run", "--with", "mcp", "mcp", "run", "foo.py"]
|
||||
|
||||
|
||||
def test_build_uv_command_adds_editable_and_packages(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Should include --with-editable and every --with pkg in correct order."""
|
||||
_set_mcp_version(monkeypatch, "1.2.3")
|
||||
test_path = Path("/pkg")
|
||||
cmd = _build_uv_command(
|
||||
"foo.py",
|
||||
with_editable=test_path,
|
||||
with_packages=["package1", "package2"],
|
||||
)
|
||||
assert cmd == [
|
||||
"uv",
|
||||
"run",
|
||||
"--with",
|
||||
"mcp==1.2.3",
|
||||
"--with-editable",
|
||||
str(test_path), # Use str() to match what the function does
|
||||
"--with",
|
||||
"package1",
|
||||
"--with",
|
||||
"package2",
|
||||
"mcp",
|
||||
"run",
|
||||
"foo.py",
|
||||
]
|
||||
|
||||
|
||||
def test_get_npx_unix_like(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Should return "npx" on unix-like systems."""
|
||||
monkeypatch.setattr(sys, "platform", "linux")
|
||||
assert _get_npx_command() == "npx"
|
||||
|
||||
|
||||
def test_get_npx_windows(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Should return one of the npx candidates on Windows."""
|
||||
candidates = ["npx.cmd", "npx.exe", "npx"]
|
||||
|
||||
def fake_run(cmd: list[str], **kw: Any) -> subprocess.CompletedProcess[bytes]:
|
||||
if cmd[0] in candidates:
|
||||
return subprocess.CompletedProcess(cmd, 0)
|
||||
else: # pragma: no cover
|
||||
raise subprocess.CalledProcessError(1, cmd[0])
|
||||
|
||||
monkeypatch.setattr(sys, "platform", "win32")
|
||||
monkeypatch.setattr(subprocess, "run", fake_run)
|
||||
assert _get_npx_command() in candidates
|
||||
|
||||
|
||||
def test_get_npx_returns_none_when_npx_missing(monkeypatch: pytest.MonkeyPatch):
|
||||
"""Should give None if every candidate fails."""
|
||||
monkeypatch.setattr(sys, "platform", "win32", raising=False)
|
||||
|
||||
def always_fail(*args: Any, **kwargs: Any) -> subprocess.CompletedProcess[bytes]:
|
||||
raise subprocess.CalledProcessError(1, args[0])
|
||||
|
||||
monkeypatch.setattr(subprocess, "run", always_fail)
|
||||
assert _get_npx_command() is None
|
||||
Reference in New Issue
Block a user