Skip to content

Commit 973a82a

Browse files
committed
test: add tests for series tool handler
Signed-off-by: TJ Hoplock <[email protected]>
1 parent 2c1fb83 commit 973a82a

File tree

1 file changed

+118
-0
lines changed

1 file changed

+118
-0
lines changed

pkg/mcp/tools_test.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,3 +1276,121 @@ func TestLabelValuesToolHandler(t *testing.T) {
12761276
})
12771277
}
12781278
}
1279+
1280+
func TestSeriesToolHandler(t *testing.T) {
1281+
testCases := []struct {
1282+
name string
1283+
request mcp.CallToolRequest
1284+
mockSeriesFunc func(ctx context.Context, matches []string, startTime time.Time, endTime time.Time, opts ...promv1.Option) ([]model.LabelSet, promv1.Warnings, error)
1285+
validateResult func(t *testing.T, result *mcp.CallToolResult, err error)
1286+
}{
1287+
{
1288+
name: "success",
1289+
request: mcp.CallToolRequest{
1290+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1291+
Params: mcp.CallToolParams{
1292+
Name: "series",
1293+
Arguments: map[string]any{
1294+
"matches": []string{"up"},
1295+
"start_time": "1756142748",
1296+
"end_time": "1756143048",
1297+
},
1298+
},
1299+
},
1300+
mockSeriesFunc: func(ctx context.Context, matches []string, startTime time.Time, endTime time.Time, opts ...promv1.Option) ([]model.LabelSet, promv1.Warnings, error) {
1301+
require.Equal(t, []string{"up"}, matches)
1302+
return []model.LabelSet{}, nil, nil
1303+
},
1304+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1305+
require.NoError(t, err)
1306+
require.False(t, result.IsError)
1307+
},
1308+
},
1309+
{
1310+
name: "missing matches",
1311+
request: mcp.CallToolRequest{
1312+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1313+
Params: mcp.CallToolParams{
1314+
Name: "series",
1315+
Arguments: map[string]any{},
1316+
},
1317+
},
1318+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1319+
require.NoError(t, err)
1320+
require.True(t, result.IsError)
1321+
require.Contains(t, toolCallResultAsString(result), "matches must be an array")
1322+
},
1323+
},
1324+
{
1325+
name: "API error",
1326+
request: mcp.CallToolRequest{
1327+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1328+
Params: mcp.CallToolParams{
1329+
Name: "series",
1330+
Arguments: map[string]any{"matches": []string{"up"}},
1331+
},
1332+
},
1333+
mockSeriesFunc: func(ctx context.Context, matches []string, startTime time.Time, endTime time.Time, opts ...promv1.Option) ([]model.LabelSet, promv1.Warnings, error) {
1334+
return nil, nil, errors.New("prometheus exploded")
1335+
},
1336+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1337+
require.NoError(t, err)
1338+
require.True(t, result.IsError)
1339+
require.Contains(t, toolCallResultAsString(result), "prometheus exploded")
1340+
},
1341+
},
1342+
{
1343+
name: "invalid start_time",
1344+
request: mcp.CallToolRequest{
1345+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1346+
Params: mcp.CallToolParams{
1347+
Name: "series",
1348+
Arguments: map[string]any{"matches": []string{"up"}, "start_time": "not-a-real-timestamp"},
1349+
},
1350+
},
1351+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1352+
require.NoError(t, err)
1353+
require.True(t, result.IsError)
1354+
require.Contains(t, toolCallResultAsString(result), "failed to parse start_time")
1355+
},
1356+
},
1357+
{
1358+
name: "invalid end_time",
1359+
request: mcp.CallToolRequest{
1360+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1361+
Params: mcp.CallToolParams{
1362+
Name: "series",
1363+
Arguments: map[string]any{"matches": []string{"up"}, "end_time": "not-a-real-timestamp"},
1364+
},
1365+
},
1366+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1367+
require.NoError(t, err)
1368+
require.True(t, result.IsError)
1369+
require.Contains(t, toolCallResultAsString(result), "failed to parse end_time")
1370+
},
1371+
},
1372+
}
1373+
1374+
mockAPI := &MockPrometheusAPI{}
1375+
mockServer := mcptest.NewUnstartedServer(t)
1376+
mockServer.AddTool(seriesTool, seriesToolHandler)
1377+
1378+
ctx := context.WithValue(context.Background(), apiClientKey{}, mockAPI)
1379+
err := mockServer.Start(ctx)
1380+
require.NoError(t, err)
1381+
defer mockServer.Close()
1382+
1383+
mcpClient := mockServer.Client()
1384+
defer mcpClient.Close()
1385+
1386+
for _, tc := range testCases {
1387+
t.Run(tc.name, func(t *testing.T) {
1388+
mockAPI.SeriesFunc = tc.mockSeriesFunc
1389+
1390+
res, err := mcpClient.CallTool(ctx, tc.request)
1391+
require.NoError(t, err)
1392+
1393+
tc.validateResult(t, res, err)
1394+
})
1395+
}
1396+
}

0 commit comments

Comments
 (0)