Merge pull request #183 from olaservo/ruby-smoke-tests
Cover the Ruby examples in the smoke tests
This commit is contained in:
commit
3196b11aae
4 changed files with 59 additions and 9 deletions
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
|
|
@ -41,5 +41,12 @@ jobs:
|
||||||
with:
|
with:
|
||||||
go-version: "1.25"
|
go-version: "1.25"
|
||||||
|
|
||||||
|
# 3.4 is the current stable series. 3.3 is supported until March 2027; 3.2
|
||||||
|
# reached end of life in March 2026.
|
||||||
|
- name: Set up Ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: "3.4"
|
||||||
|
|
||||||
- name: Run smoke tests
|
- name: Run smoke tests
|
||||||
run: ./tests/smoke-test.sh
|
run: ./tests/smoke-test.sh
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ This directory contains smoke tests for the MCP quickstart examples. These tests
|
||||||
|
|
||||||
The smoke tests verify:
|
The smoke tests verify:
|
||||||
|
|
||||||
- **Servers**: Each weather server (Python, TypeScript, Rust, Go) can start, respond to MCP protocol requests, and honour the output schemas it advertises
|
- **Servers**: Each weather server (Python, TypeScript, Rust, Go, Ruby) can start, respond to MCP protocol requests, and honour the output schemas it advertises
|
||||||
- **Clients**: The Python and TypeScript MCP clients can connect to a mock server and list tools
|
- **Clients**: The Python, TypeScript and Ruby MCP clients can connect to a mock server and list tools
|
||||||
|
|
||||||
The Go and Rust clients are not covered here: on `main` both abort when no `.env` file is present, so they cannot be driven without credentials. Making them start credential-free is a change in their own directories, so their coverage lands with those changes rather than here. The Ruby examples are not covered either — the `mcp` gem cannot negotiate protocol revision `2026-07-28`.
|
The Go and Rust clients are not covered here: on `main` both abort when no `.env` file is present, so they cannot be driven without credentials. Making them start credential-free is a change in their own directories, so their coverage lands with those changes rather than here.
|
||||||
|
|
||||||
## Structured content
|
## Structured content
|
||||||
|
|
||||||
|
|
@ -37,6 +37,8 @@ Tool calls reach the live NWS API. When it is unreachable the tools return an er
|
||||||
- **Rust** stable
|
- **Rust** stable
|
||||||
- **Cargo** (for Rust builds)
|
- **Cargo** (for Rust builds)
|
||||||
- **Go** 1.25+
|
- **Go** 1.25+
|
||||||
|
- **Ruby** 3.4+ (3.2 and 3.3 satisfy the gems, but 3.2 is past end of life)
|
||||||
|
- **Bundler** (ships with Ruby 3.x)
|
||||||
|
|
||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
|
|
@ -111,6 +113,9 @@ nvm install 24
|
||||||
|
|
||||||
# Rust
|
# Rust
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
|
|
||||||
|
# Ruby (via rbenv)
|
||||||
|
rbenv install 3.4
|
||||||
```
|
```
|
||||||
|
|
||||||
## Adding New Tests
|
## Adding New Tests
|
||||||
|
|
|
||||||
|
|
@ -84,11 +84,24 @@ test_weather_server_go() {
|
||||||
node "${TEST_CLIENT}" "${server_bin}"
|
node "${TEST_CLIENT}" "${server_bin}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Test: Ruby weather server
|
||||||
|
test_weather_server_ruby() {
|
||||||
|
check_dependency ruby || return 1
|
||||||
|
check_dependency bundle || return 1
|
||||||
|
local server_dir="${PROJECT_ROOT}/weather-server-ruby"
|
||||||
|
ensure_bundled "${server_dir}" || return 1
|
||||||
|
(cd "${server_dir}" && node "${TEST_CLIENT}" bundle exec ruby weather.rb)
|
||||||
|
}
|
||||||
|
|
||||||
|
# The client tests drive the no-API-key path, where each client prints a notice
|
||||||
|
# and exits. Empty rather than unset: dotenv skips a name already present in
|
||||||
|
# ENV, so a key in the environment or a local .env would start the chat loop.
|
||||||
|
|
||||||
# Test: Python MCP client
|
# Test: Python MCP client
|
||||||
test_mcp_client_python() {
|
test_mcp_client_python() {
|
||||||
check_dependency uv || return 1
|
check_dependency uv || return 1
|
||||||
local client_dir="${PROJECT_ROOT}/mcp-client-python"
|
local client_dir="${PROJECT_ROOT}/mcp-client-python"
|
||||||
uv --directory "${client_dir}" run python "${client_dir}/client.py" "${MOCK_SERVER}" >/dev/null 2>&1
|
ANTHROPIC_API_KEY= uv --directory "${client_dir}" run python "${client_dir}/client.py" "${MOCK_SERVER}" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Test: TypeScript MCP client
|
# Test: TypeScript MCP client
|
||||||
|
|
@ -97,22 +110,34 @@ test_mcp_client_typescript() {
|
||||||
check_dependency npm || return 1
|
check_dependency npm || return 1
|
||||||
local client_dir="${PROJECT_ROOT}/mcp-client-typescript"
|
local client_dir="${PROJECT_ROOT}/mcp-client-typescript"
|
||||||
ensure_built "${client_dir}" || return 1
|
ensure_built "${client_dir}" || return 1
|
||||||
node "${client_dir}/build/index.js" "${MOCK_SERVER}" >/dev/null 2>&1
|
ANTHROPIC_API_KEY= node "${client_dir}/build/index.js" "${MOCK_SERVER}" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test: Ruby MCP client
|
||||||
|
test_mcp_client_ruby() {
|
||||||
|
check_dependency ruby || return 1
|
||||||
|
check_dependency bundle || return 1
|
||||||
|
local client_dir="${PROJECT_ROOT}/mcp-client-ruby"
|
||||||
|
ensure_bundled "${client_dir}" || return 1
|
||||||
|
(cd "${client_dir}" && ANTHROPIC_API_KEY= bundle exec ruby client.rb "${MOCK_SERVER}") >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run all tests
|
# Run all tests
|
||||||
#
|
#
|
||||||
# All four servers are covered. The Go and Rust clients are not: on main both
|
# The Go and Rust clients are not covered: on main both abort when no .env file
|
||||||
# abort when no .env file is present, so they cannot be driven without
|
# is present, so they cannot be driven without credentials. Making them start
|
||||||
# credentials. Making them start credential-free is a change in their own
|
# credential-free is a change in their own directories, so their coverage lands
|
||||||
# directories, so their coverage lands with those changes rather than here.
|
# with those changes rather than here.
|
||||||
|
|
||||||
print_header "Running smoke tests"
|
print_header "Running smoke tests"
|
||||||
run_test "weather-server-python" test_weather_server_python
|
run_test "weather-server-python" test_weather_server_python
|
||||||
run_test "weather-server-typescript" test_weather_server_typescript
|
run_test "weather-server-typescript" test_weather_server_typescript
|
||||||
run_test "weather-server-rust" test_weather_server_rust
|
run_test "weather-server-rust" test_weather_server_rust
|
||||||
run_test "weather-server-go" test_weather_server_go
|
run_test "weather-server-go" test_weather_server_go
|
||||||
|
run_test "weather-server-ruby" test_weather_server_ruby
|
||||||
run_test "mcp-client-python" test_mcp_client_python
|
run_test "mcp-client-python" test_mcp_client_python
|
||||||
run_test "mcp-client-typescript" test_mcp_client_typescript
|
run_test "mcp-client-typescript" test_mcp_client_typescript
|
||||||
|
run_test "mcp-client-ruby" test_mcp_client_ruby
|
||||||
|
|
||||||
# Print summary
|
# Print summary
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
||||||
|
|
@ -138,3 +138,16 @@ ensure_built() {
|
||||||
run_build "go build in ${dir}" go build -o "server$(exe_suffix)" . || return 1
|
run_build "go build in ${dir}" go build -o "server$(exe_suffix)" . || return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Ensure a Ruby project directory has its gems installed.
|
||||||
|
#
|
||||||
|
# Unlike ensure_built there is no artefact to test for -- a Ruby example has no
|
||||||
|
# build step and Gemfile.lock is gitignored -- so ask Bundler directly.
|
||||||
|
ensure_bundled() {
|
||||||
|
local dir=$1
|
||||||
|
cd "${dir}" || return 1
|
||||||
|
|
||||||
|
if ! bundle check >/dev/null 2>&1; then
|
||||||
|
run_build "bundle install in ${dir}" bundle install || return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue