From d68cbba42d5ff4cf7bf6a00f1fd6e0b4a2dde995 Mon Sep 17 00:00:00 2001 From: Daniel Chalef <131175+danielchalef@users.noreply.github.com> Date: Wed, 27 Aug 2025 15:17:55 -0700 Subject: [PATCH] fix: Enable pytest for MCP server tests in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created isolated pytest.ini configuration for MCP server - Added conftest.py to prevent loading parent project fixtures - Added pytest and pytest-asyncio to dev dependencies - Enabled pytest in CI workflow with proper environment variables - Fixed asyncio test configuration Pytest now runs successfully for MCP server tests without interfering with the root project test configuration. 🤖 Generated with Claude Code Co-Authored-By: Claude --- .github/workflows/mcp-server-tests.yml | 11 +++++++---- mcp_server/pyproject.toml | 2 ++ mcp_server/pytest.ini | 14 ++++++++++++++ mcp_server/tests/conftest.py | 20 ++++++++++++++++++++ mcp_server/tests/test_configuration.py | 3 ++- mcp_server/uv.lock | 26 ++++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 mcp_server/pytest.ini create mode 100644 mcp_server/tests/conftest.py diff --git a/.github/workflows/mcp-server-tests.yml b/.github/workflows/mcp-server-tests.yml index f658df6d..d786de40 100644 --- a/.github/workflows/mcp-server-tests.yml +++ b/.github/workflows/mcp-server-tests.yml @@ -68,12 +68,15 @@ jobs: cd mcp_server uv run tests/test_configuration.py - - name: Run unit tests (if pytest tests exist) + - name: Run unit tests with pytest run: | cd mcp_server - # Temporarily skip pytest due to fixture issues - use direct test execution instead - echo "⚠️ Skipping pytest due to fixture configuration issues" - echo "✅ Core validation tests run separately via direct execution" + uv run pytest tests/ --tb=short -v + env: + NEO4J_URI: bolt://localhost:7687 + NEO4J_USER: neo4j + NEO4J_PASSWORD: testpassword + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - name: Test main.py wrapper run: | diff --git a/mcp_server/pyproject.toml b/mcp_server/pyproject.toml index 848f142d..72f00834 100644 --- a/mcp_server/pyproject.toml +++ b/mcp_server/pyproject.toml @@ -29,6 +29,8 @@ dev = [ "httpx>=0.28.1", "mcp>=1.9.4", "pyright>=1.1.404", + "pytest>=8.0.0", + "pytest-asyncio>=0.21.0", "ruff>=0.7.1", ] diff --git a/mcp_server/pytest.ini b/mcp_server/pytest.ini new file mode 100644 index 00000000..a444cc4a --- /dev/null +++ b/mcp_server/pytest.ini @@ -0,0 +1,14 @@ +[pytest] +# MCP Server specific pytest configuration +testpaths = tests +python_files = test_*.py +python_classes = Test* +python_functions = test_* +addopts = -v --tb=short +# Configure asyncio +asyncio_mode = auto +asyncio_default_fixture_loop_scope = function +# Ignore warnings from dependencies +filterwarnings = + ignore::DeprecationWarning + ignore::PendingDeprecationWarning \ No newline at end of file diff --git a/mcp_server/tests/conftest.py b/mcp_server/tests/conftest.py new file mode 100644 index 00000000..9d9207a6 --- /dev/null +++ b/mcp_server/tests/conftest.py @@ -0,0 +1,20 @@ +""" +Pytest configuration for MCP server tests. +This file prevents pytest from loading the parent project's conftest.py +""" + +import sys +from pathlib import Path +import pytest + +# Add src directory to Python path for imports +src_path = Path(__file__).parent.parent / 'src' +sys.path.insert(0, str(src_path)) + +from config.schema import GraphitiConfig + + +@pytest.fixture +def config(): + """Provide a default GraphitiConfig for tests.""" + return GraphitiConfig() \ No newline at end of file diff --git a/mcp_server/tests/test_configuration.py b/mcp_server/tests/test_configuration.py index 4dc2d7ff..69c3bfc4 100644 --- a/mcp_server/tests/test_configuration.py +++ b/mcp_server/tests/test_configuration.py @@ -41,7 +41,8 @@ def test_config_loading(): del os.environ['LLM__PROVIDER'] del os.environ['LLM__MODEL'] - return config + assert config is not None + assert config2 is not None def test_llm_factory(config: GraphitiConfig): diff --git a/mcp_server/uv.lock b/mcp_server/uv.lock index f7f90ef5..4bd1bda0 100644 --- a/mcp_server/uv.lock +++ b/mcp_server/uv.lock @@ -223,6 +223,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, ] +[[package]] +name = "backports-asyncio-runner" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/ff/70dca7d7cb1cbc0edb2c6cc0c38b65cba36cccc491eca64cabd5fe7f8670/backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162", size = 69893 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313 }, +] + [[package]] name = "cachetools" version = "5.5.2" @@ -1005,6 +1014,8 @@ dev = [ { name = "httpx" }, { name = "mcp" }, { name = "pyright" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, { name = "ruff" }, ] @@ -1030,6 +1041,8 @@ dev = [ { name = "httpx", specifier = ">=0.28.1" }, { name = "mcp", specifier = ">=1.9.4" }, { name = "pyright", specifier = ">=1.1.404" }, + { name = "pytest", specifier = ">=8.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.21.0" }, { name = "ruff", specifier = ">=0.7.1" }, ] @@ -1924,6 +1937,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474 }, ] +[[package]] +name = "pytest-asyncio" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "backports-asyncio-runner", marker = "python_full_version < '3.11'" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/51/f8794af39eeb870e87a8c8068642fc07bce0c854d6865d7dd0f2a9d338c2/pytest_asyncio-1.1.0.tar.gz", hash = "sha256:796aa822981e01b68c12e4827b8697108f7205020f24b5793b3c41555dab68ea", size = 46652 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/9d/bf86eddabf8c6c9cb1ea9a869d6873b46f105a5d292d3a6f7071f5b07935/pytest_asyncio-1.1.0-py3-none-any.whl", hash = "sha256:5fe2d69607b0bd75c656d1211f969cadba035030156745ee09e7d71740e58ecf", size = 15157 }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0"