Testing 1.0.2rc1 GHA #652
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Tests | |
| permissions: | |
| contents: read | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| env: | |
| # Default test credentials for Couchbase | |
| CB_USERNAME: Administrator | |
| CB_PASSWORD: password | |
| CB_MCP_TEST_BUCKET: travel-sample | |
| jobs: | |
| # ============================================ | |
| # Unit Tests - Fast, no Couchbase, no transport matrix | |
| # ============================================ | |
| unit-tests: | |
| name: Unit tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 | |
| with: | |
| version: "latest" | |
| - name: Set up Python (latest) | |
| run: uv python install 3.13 | |
| - name: Install dependencies | |
| run: uv sync --extra dev | |
| - name: Run unit tests | |
| env: | |
| PYTHONPATH: src | |
| run: uv run pytest tests/unit -v --tb=short | |
| # ============================================ | |
| # Integration Tests - All Transport Modes | |
| # ============================================ | |
| integration-tests: | |
| name: Integration (${{ matrix.transport }} / cb-${{ matrix.cb_version }} / ${{ matrix.server_binary }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| transport: ["stdio", "http"] | |
| cb_version: ["8.0.0", "7.6.11"] | |
| server_binary: ["source", "docker", "pypi"] | |
| exclude: | |
| - transport: stdio | |
| server_binary: docker | |
| - transport: stdio | |
| server_binary: pypi | |
| services: | |
| couchbase: | |
| image: couchbase:enterprise-${{ matrix.cb_version }} | |
| ports: | |
| - 8091:8091 | |
| - 8092:8092 | |
| - 8093:8093 | |
| - 8094:8094 | |
| - 8095:8095 | |
| - 8096:8096 | |
| - 9102:9102 | |
| - 11210:11210 | |
| - 11207:11207 | |
| options: >- | |
| --health-cmd "curl -s http://localhost:8091/pools || exit 1" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 30 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 | |
| with: | |
| version: "latest" | |
| - name: Set up Python (latest) | |
| run: uv python install 3.13 | |
| - name: Install dependencies | |
| run: uv sync --extra dev | |
| - name: Wait for Couchbase to be ready | |
| run: | | |
| echo "Waiting for Couchbase to be fully ready..." | |
| for i in {1..60}; do | |
| if curl -s http://localhost:8091/pools > /dev/null 2>&1; then | |
| echo "Couchbase REST API is responding" | |
| break | |
| fi | |
| echo "Waiting for Couchbase... ($i/60)" | |
| sleep 2 | |
| done | |
| - name: Initialize Couchbase cluster | |
| run: | | |
| echo "Initializing Couchbase cluster..." | |
| # Initialize node | |
| curl -s -X POST http://localhost:8091/nodes/self/controller/settings \ | |
| -d 'path=/opt/couchbase/var/lib/couchbase/data' \ | |
| -d 'index_path=/opt/couchbase/var/lib/couchbase/data' | |
| # Set up services | |
| curl -s -X POST http://localhost:8091/node/controller/setupServices \ | |
| -d 'services=kv,n1ql,index,fts' | |
| # Set memory quotas | |
| curl -s -X POST http://localhost:8091/pools/default \ | |
| -d 'memoryQuota=512' \ | |
| -d 'indexMemoryQuota=256' \ | |
| -d 'ftsMemoryQuota=256' | |
| # Set credentials | |
| curl -s -X POST http://localhost:8091/settings/web \ | |
| -d "password=${{ env.CB_PASSWORD }}" \ | |
| -d "username=${{ env.CB_USERNAME }}" \ | |
| -d 'port=SAME' | |
| echo "Cluster initialization complete" | |
| - name: Load travel-sample bucket | |
| run: | | |
| echo "Loading travel-sample bucket..." | |
| # Wait for cluster to be fully initialized | |
| sleep 5 | |
| # Load the travel-sample sample bucket (includes inventory scope with airline, route, hotel, airport collections) | |
| curl -s -X POST http://localhost:8091/sampleBuckets/install \ | |
| -u "${{ env.CB_USERNAME }}:${{ env.CB_PASSWORD }}" \ | |
| -H "Content-Type: application/json" \ | |
| -d '["travel-sample"]' | |
| # Wait for bucket to be ready (sample buckets take longer to load) | |
| echo "Waiting for travel-sample bucket to be ready..." | |
| for i in {1..60}; do | |
| if curl -s -u "${{ env.CB_USERNAME }}:${{ env.CB_PASSWORD }}" \ | |
| http://localhost:8091/pools/default/buckets/travel-sample 2>/dev/null | grep -q '"status":"healthy"'; then | |
| echo "Bucket is healthy" | |
| break | |
| fi | |
| echo "Waiting for bucket... ($i/60)" | |
| sleep 3 | |
| done | |
| # Additional wait for data to be fully loaded | |
| echo "Waiting for sample data to be fully loaded..." | |
| sleep 10 | |
| - name: Set indexer storage mode | |
| run: | | |
| echo "Setting indexer storage mode..." | |
| # Wait for indexer service to be ready | |
| sleep 5 | |
| # Set storage mode to plasma (Couchbase 7.1+) | |
| # Use cluster settings API which is more reliable | |
| curl -s -X POST http://localhost:8091/settings/indexes \ | |
| -u "${{ env.CB_USERNAME }}:${{ env.CB_PASSWORD }}" \ | |
| -d 'storageMode=plasma' \ | |
| || echo "Storage mode may already be set or indexer not ready" | |
| # Wait for storage mode to be applied | |
| echo "Waiting for storage mode to be applied..." | |
| sleep 5 | |
| - name: Setup test data (indexes and queries) | |
| env: | |
| CB_CONNECTION_STRING: couchbase://localhost | |
| CB_USERNAME: ${{ env.CB_USERNAME }} | |
| CB_PASSWORD: ${{ env.CB_PASSWORD }} | |
| CB_MCP_TEST_BUCKET: ${{ env.CB_MCP_TEST_BUCKET }} | |
| PYTHONPATH: src | |
| run: | | |
| echo "Running setup_test_data.py to create indexes and populate test data..." | |
| uv run python scripts/setup_test_data.py | |
| # ============================================ | |
| # STDIO Transport Tests | |
| # ============================================ | |
| - name: Run STDIO integration tests | |
| if: matrix.transport == 'stdio' | |
| env: | |
| CB_CONNECTION_STRING: couchbase://localhost | |
| CB_MCP_TRANSPORT: stdio | |
| CB_MCP_TEST_SCOPE: inventory | |
| CB_MCP_TEST_COLLECTION: airline | |
| PYTHONPATH: src | |
| run: | | |
| echo "Running tests with STDIO transport..." | |
| uv run pytest tests/integration -v --tb=short | |
| # ============================================ | |
| # HTTP Transport Tests - Binary build steps | |
| # ============================================ | |
| - name: Build Docker image | |
| if: matrix.transport == 'http' && matrix.server_binary == 'docker' | |
| run: docker build -t mcp-server-test:latest . | |
| - name: Build and install PyPI wheel | |
| if: matrix.transport == 'http' && matrix.server_binary == 'pypi' | |
| run: | | |
| uv build | |
| python3 -m venv /tmp/pypi-test-venv | |
| /tmp/pypi-test-venv/bin/pip install --quiet dist/couchbase_mcp_server-*.whl | |
| # ============================================ | |
| # HTTP Transport Tests - Start server | |
| # ============================================ | |
| - name: Start MCP server (HTTP) | |
| if: matrix.transport == 'http' | |
| env: | |
| CB_MCP_PORT: 8000 | |
| CB_MCP_READ_ONLY_MODE: "false" | |
| PYTHONPATH: src | |
| run: | | |
| echo "Starting MCP server (${{ matrix.server_binary }}) with HTTP transport..." | |
| if [[ "${{ matrix.server_binary }}" == "source" ]]; then | |
| CB_CONNECTION_STRING=couchbase://localhost \ | |
| CB_MCP_TRANSPORT=http \ | |
| CB_MCP_HOST=127.0.0.1 \ | |
| CB_MCP_PORT=$CB_MCP_PORT \ | |
| CB_MCP_READ_ONLY_MODE=$CB_MCP_READ_ONLY_MODE \ | |
| PYTHONPATH=$PYTHONPATH \ | |
| uv run python -m mcp_server & | |
| echo "SERVER_PID=$!" >> $GITHUB_ENV | |
| elif [[ "${{ matrix.server_binary }}" == "docker" ]]; then | |
| docker run -d --network host \ | |
| --name mcp-server-http \ | |
| -e CB_CONNECTION_STRING=couchbase://127.0.0.1 \ | |
| -e CB_USERNAME=$CB_USERNAME \ | |
| -e CB_PASSWORD=$CB_PASSWORD \ | |
| -e CB_MCP_TRANSPORT=http \ | |
| -e CB_MCP_HOST=0.0.0.0 \ | |
| -e CB_MCP_PORT=$CB_MCP_PORT \ | |
| -e CB_MCP_READ_ONLY_MODE=$CB_MCP_READ_ONLY_MODE \ | |
| mcp-server-test:latest | |
| elif [[ "${{ matrix.server_binary }}" == "pypi" ]]; then | |
| CB_CONNECTION_STRING=couchbase://localhost \ | |
| CB_MCP_TRANSPORT=http \ | |
| CB_MCP_HOST=127.0.0.1 \ | |
| CB_MCP_PORT=$CB_MCP_PORT \ | |
| CB_MCP_READ_ONLY_MODE=$CB_MCP_READ_ONLY_MODE \ | |
| /tmp/pypi-test-venv/bin/couchbase-mcp-server & | |
| echo "SERVER_PID=$!" >> $GITHUB_ENV | |
| fi | |
| echo "Waiting for HTTP server to be ready..." | |
| for i in {1..30}; do | |
| code=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8000/mcp 2>/dev/null || echo "000") | |
| if [[ -n "$code" && "$code" != "000" ]]; then | |
| echo "HTTP server is ready (HTTP $code after ${i}s)" | |
| break | |
| fi | |
| echo "Waiting for HTTP server... ($i/30)" | |
| sleep 1 | |
| done | |
| # Uvicorn can accept connections before FastMCP's session manager | |
| # finishes initializing — give it a moment to fully settle. | |
| sleep 3 | |
| - name: Run HTTP transport tests | |
| if: matrix.transport == 'http' | |
| env: | |
| CB_CONNECTION_STRING: couchbase://localhost | |
| CB_MCP_TRANSPORT: http | |
| MCP_SERVER_URL: http://127.0.0.1:8000/mcp | |
| CB_MCP_TEST_SCOPE: inventory | |
| CB_MCP_TEST_COLLECTION: airline | |
| PYTHONPATH: src | |
| run: | | |
| echo "Running tests with HTTP transport (${{ matrix.server_binary }})..." | |
| uv run pytest tests/integration -v --tb=short | |
| - name: Stop HTTP server | |
| if: matrix.transport == 'http' && always() | |
| run: | | |
| if [[ "${{ matrix.server_binary }}" == "docker" ]]; then | |
| docker rm -f mcp-server-http 2>/dev/null || true | |
| elif [ -n "${SERVER_PID:-}" ]; then | |
| kill $SERVER_PID 2>/dev/null || true | |
| fi | |
| # ============================================ | |
| # Test Summary | |
| # ============================================ | |
| test-summary: | |
| name: Test Summary | |
| permissions: {} | |
| runs-on: ubuntu-latest | |
| needs: [unit-tests, integration-tests] | |
| if: always() | |
| steps: | |
| - name: Check test results | |
| run: | | |
| echo "=== Test Results Summary ===" | |
| echo "Unit Tests: ${{ needs.unit-tests.result }}" | |
| echo "Integration Tests: ${{ needs.integration-tests.result }}" | |
| echo "" | |
| if [ "${{ needs.unit-tests.result }}" == "failure" ] || \ | |
| [ "${{ needs.integration-tests.result }}" == "failure" ]; then | |
| echo "❌ Some tests failed" | |
| exit 1 | |
| elif [ "${{ needs.unit-tests.result }}" == "cancelled" ] || \ | |
| [ "${{ needs.integration-tests.result }}" == "cancelled" ]; then | |
| echo "⚠️ Tests were cancelled" | |
| exit 1 | |
| else | |
| echo "✅ All tests passed!" | |
| fi |