Skip to content

Testing 1.0.2rc1 GHA #652

Testing 1.0.2rc1 GHA

Testing 1.0.2rc1 GHA #652

Workflow file for this run

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