Skip to content

Commit f56729d

Browse files
committed
Create BATS tests for limactl-mcp
Signed-off-by: Jan Dubois <[email protected]>
1 parent 6ef4970 commit f56729d

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

hack/bats/tests/mcp.bats

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# SPDX-FileCopyrightText: Copyright The Lima Authors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
load "../helpers/load"
5+
6+
NAME=bats
7+
8+
# TODO The reusable Lima instance setup is copied from preserve-env.bats
9+
# TODO and should be factored out into helper functions.
10+
local_setup_file() {
11+
if [[ -n "${LIMA_BATS_REUSE_INSTANCE:-}" ]]; then
12+
run limactl list --format '{{.Status}}' "$NAME"
13+
[[ $status == 0 ]] && [[ $output == "Running" ]] && return
14+
fi
15+
limactl unprotect "$NAME" || :
16+
limactl delete --force "$NAME" || :
17+
# Make sure that the host agent doesn't inherit file handles 3 or 4.
18+
# Otherwise bats will not finish until the host agent exits.
19+
limactl start --yes --name "$NAME" template://default 3>&- 4>&-
20+
}
21+
22+
local_teardown_file() {
23+
if [[ -z "${LIMA_BATS_REUSE_INSTANCE:-}" ]]; then
24+
limactl delete --force "$NAME"
25+
fi
26+
}
27+
28+
local_setup() {
29+
coproc MCP { limactl mcp serve "$NAME"; }
30+
PID=$!
31+
ID=0
32+
33+
mcp initialize '{"protocolVersion":"2025-03-26"}'
34+
35+
run -0 limactl yq .serverInfo.name <<<"$output"
36+
assert_output lima
37+
}
38+
39+
local_teardown() {
40+
kill "${PID:?}" 2>&1 >/dev/null || :
41+
}
42+
43+
mcp() {
44+
local method=$1
45+
local params=${2:-}
46+
47+
local request
48+
printf -v request '{"jsonrpc":"2.0","id":%d,"method":"%s"}' "$((++ID))" "$method"
49+
if [[ -n $params ]]; then
50+
request=$(limactl yq --output-format json --indent 0 ".params=${params}" <<<"$request")
51+
fi
52+
echo "$request" >&"${MCP[1]}"
53+
54+
# read response from MCP server with 1s timeout
55+
local json
56+
read -t 1 -r json <&"${MCP[0]}"
57+
58+
# verify that the response matches the request; also validates the output is valid JSON
59+
run -0 limactl yq .id <<<"$json"
60+
assert_output "$ID"
61+
62+
# set $output to .result
63+
run -0 limactl yq .result <<<"$json"
64+
}
65+
66+
tools_call() {
67+
local name=$1
68+
local args=${2:-}
69+
70+
local params
71+
printf -v params '{"name":"%s"}' "$name"
72+
if [[ -n $args ]]; then
73+
params=$(limactl yq --output-format json --indent 0 ".arguments=${args}" <<<"$params")
74+
fi
75+
mcp tools/call "$params"
76+
}
77+
78+
@test 'list tools' {
79+
mcp tools/list
80+
run -0 limactl yq '.tools[].name' <<<"$output"
81+
assert_line glob
82+
assert_line list_directory
83+
assert_line read_file
84+
assert_line run_shell_command
85+
assert_line search_file_content
86+
assert_line write_file
87+
}
88+
89+
@test 'run shell command' {
90+
run -0 limactl shell "$NAME" cat /etc/os-release
91+
expected=$output
92+
93+
tools_call run_shell_command '{"directory":"/etc","command":["cat","os-release"]}'
94+
json=$output
95+
96+
run -0 limactl yq '.content[0].type' <<<"$json"
97+
assert_output text
98+
99+
# The text property is a string encoding of an embedded JSON object
100+
run -0 limactl yq '.content[0].text' <<<"$json"
101+
text=$output
102+
103+
run -0 limactl yq '.exit_code' <<<"$text"
104+
assert_output 0
105+
106+
run -0 limactl yq '.stdout' <<<"$text"
107+
assert_output "$expected"
108+
}

0 commit comments

Comments
 (0)