Skip to content

Commit 2c1fb83

Browse files
committed
tests: add tests for label values tool handler
Signed-off-by: TJ Hoplock <[email protected]>
1 parent 7b4c642 commit 2c1fb83

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
@@ -1158,3 +1158,121 @@ func TestListAlertsToolHandler(t *testing.T) {
11581158
})
11591159
}
11601160
}
1161+
1162+
func TestLabelValuesToolHandler(t *testing.T) {
1163+
testCases := []struct {
1164+
name string
1165+
request mcp.CallToolRequest
1166+
mockLabelValuesFunc func(ctx context.Context, label string, matches []string, startTime time.Time, endTime time.Time, opts ...promv1.Option) (model.LabelValues, promv1.Warnings, error)
1167+
validateResult func(t *testing.T, result *mcp.CallToolResult, err error)
1168+
}{
1169+
{
1170+
name: "success",
1171+
request: mcp.CallToolRequest{
1172+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1173+
Params: mcp.CallToolParams{
1174+
Name: "label_values",
1175+
Arguments: map[string]any{
1176+
"label": "__name__",
1177+
"start_time": "1756142748",
1178+
"end_time": "1756143048",
1179+
},
1180+
},
1181+
},
1182+
mockLabelValuesFunc: func(ctx context.Context, label string, matches []string, startTime time.Time, endTime time.Time, opts ...promv1.Option) (model.LabelValues, promv1.Warnings, error) {
1183+
require.Equal(t, "__name__", label)
1184+
return model.LabelValues{}, nil, nil
1185+
},
1186+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1187+
require.NoError(t, err)
1188+
require.False(t, result.IsError)
1189+
},
1190+
},
1191+
{
1192+
name: "missing label",
1193+
request: mcp.CallToolRequest{
1194+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1195+
Params: mcp.CallToolParams{
1196+
Name: "label_values",
1197+
Arguments: map[string]any{},
1198+
},
1199+
},
1200+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1201+
require.NoError(t, err)
1202+
require.True(t, result.IsError)
1203+
require.Contains(t, toolCallResultAsString(result), "label must be a string")
1204+
},
1205+
},
1206+
{
1207+
name: "API error",
1208+
request: mcp.CallToolRequest{
1209+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1210+
Params: mcp.CallToolParams{
1211+
Name: "label_values",
1212+
Arguments: map[string]any{"label": "up"},
1213+
},
1214+
},
1215+
mockLabelValuesFunc: func(ctx context.Context, label string, matches []string, startTime time.Time, endTime time.Time, opts ...promv1.Option) (model.LabelValues, promv1.Warnings, error) {
1216+
return nil, nil, errors.New("prometheus exploded")
1217+
},
1218+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1219+
require.NoError(t, err)
1220+
require.True(t, result.IsError)
1221+
require.Contains(t, toolCallResultAsString(result), "prometheus exploded")
1222+
},
1223+
},
1224+
{
1225+
name: "invalid start_time",
1226+
request: mcp.CallToolRequest{
1227+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1228+
Params: mcp.CallToolParams{
1229+
Name: "label_values",
1230+
Arguments: map[string]any{"label": "up", "start_time": "not-a-real-timestamp"},
1231+
},
1232+
},
1233+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1234+
require.NoError(t, err)
1235+
require.True(t, result.IsError)
1236+
require.Contains(t, toolCallResultAsString(result), "failed to parse start_time")
1237+
},
1238+
},
1239+
{
1240+
name: "invalid end_time",
1241+
request: mcp.CallToolRequest{
1242+
Request: mcp.Request{Method: string(mcp.MethodToolsCall)},
1243+
Params: mcp.CallToolParams{
1244+
Name: "label_values",
1245+
Arguments: map[string]any{"label": "up", "end_time": "not-a-real-timestamp"},
1246+
},
1247+
},
1248+
validateResult: func(t *testing.T, result *mcp.CallToolResult, err error) {
1249+
require.NoError(t, err)
1250+
require.True(t, result.IsError)
1251+
require.Contains(t, toolCallResultAsString(result), "failed to parse end_time")
1252+
},
1253+
},
1254+
}
1255+
1256+
mockAPI := &MockPrometheusAPI{}
1257+
mockServer := mcptest.NewUnstartedServer(t)
1258+
mockServer.AddTool(labelValuesTool, labelValuesToolHandler)
1259+
1260+
ctx := context.WithValue(context.Background(), apiClientKey{}, mockAPI)
1261+
err := mockServer.Start(ctx)
1262+
require.NoError(t, err)
1263+
defer mockServer.Close()
1264+
1265+
mcpClient := mockServer.Client()
1266+
defer mcpClient.Close()
1267+
1268+
for _, tc := range testCases {
1269+
t.Run(tc.name, func(t *testing.T) {
1270+
mockAPI.LabelValuesFunc = tc.mockLabelValuesFunc
1271+
1272+
res, err := mcpClient.CallTool(ctx, tc.request)
1273+
require.NoError(t, err)
1274+
1275+
tc.validateResult(t, res, err)
1276+
})
1277+
}
1278+
}

0 commit comments

Comments
 (0)