|
1 | | -//go:build unit |
2 | | -// +build unit |
3 | | - |
4 | 1 | package mcpgrafana |
5 | 2 |
|
6 | 3 | import ( |
7 | 4 | "context" |
8 | 5 | "net/http" |
9 | 6 | "net/http/httptest" |
10 | 7 | "net/url" |
| 8 | + "strings" |
11 | 9 | "testing" |
12 | 10 |
|
13 | 11 | "github.com/go-openapi/runtime/client" |
@@ -645,6 +643,37 @@ func TestToolTracingInstrumentation(t *testing.T) { |
645 | 643 | }) |
646 | 644 | } |
647 | 645 |
|
| 646 | +func TestTextMimeConsumerOverride(t *testing.T) { |
| 647 | + // Verify that NewGrafanaClient overrides text/plain and text/html consumers |
| 648 | + // with JSON consumers so that responses with incorrect content-type headers |
| 649 | + // (e.g. from Grafana v12 or reverse proxies) are still parsed correctly. |
| 650 | + // See: https://github.com/grafana/mcp-grafana/issues/635 |
| 651 | + ctx := WithGrafanaConfig(context.Background(), GrafanaConfig{}) |
| 652 | + c := NewGrafanaClient(ctx, "http://localhost:3000", "test-api-key", nil) |
| 653 | + require.NotNil(t, c) |
| 654 | + |
| 655 | + rt, ok := c.Transport.(*client.Runtime) |
| 656 | + require.True(t, ok, "expected Transport to be *client.Runtime") |
| 657 | + |
| 658 | + // The text/plain and text/html consumers should no longer be the default |
| 659 | + // TextConsumer. Verify by checking they can consume a JSON object into a |
| 660 | + // map (TextConsumer would fail on this). |
| 661 | + for _, mime := range []string{"text/plain", "text/html"} { |
| 662 | + consumer, exists := rt.Consumers[mime] |
| 663 | + require.True(t, exists, "consumer for %s should exist", mime) |
| 664 | + require.NotNil(t, consumer, "consumer for %s should not be nil", mime) |
| 665 | + |
| 666 | + // JSONConsumer can unmarshal into a map; TextConsumer cannot. |
| 667 | + var result map[string]interface{} |
| 668 | + err := consumer.Consume( |
| 669 | + strings.NewReader(`{"status":"ok"}`), |
| 670 | + &result, |
| 671 | + ) |
| 672 | + assert.NoError(t, err, "consumer for %s should parse JSON", mime) |
| 673 | + assert.Equal(t, "ok", result["status"], "consumer for %s should return parsed value", mime) |
| 674 | + } |
| 675 | +} |
| 676 | + |
648 | 677 | func TestHTTPTracingConfiguration(t *testing.T) { |
649 | 678 | t.Run("HTTP tracing always enabled for context propagation", func(t *testing.T) { |
650 | 679 | // Create context (HTTP tracing always enabled) |
@@ -732,7 +761,6 @@ func assertHasAttribute(t *testing.T, attributes []attribute.KeyValue, key strin |
732 | 761 | t.Errorf("Expected attribute %s with value %s not found", key, expectedValue) |
733 | 762 | } |
734 | 763 |
|
735 | | - |
736 | 764 | func TestExtraHeadersFromEnv(t *testing.T) { |
737 | 765 | t.Run("empty env returns nil", func(t *testing.T) { |
738 | 766 | t.Setenv("GRAFANA_EXTRA_HEADERS", "") |
@@ -1042,7 +1070,7 @@ func TestFetchPublicURL(t *testing.T) { |
1042 | 1070 | }) |
1043 | 1071 |
|
1044 | 1072 | extraHeaders := map[string]string{ |
1045 | | - "X-Custom-Auth": "proxy-token-123", |
| 1073 | + "X-Custom-Auth": "proxy-token-123", |
1046 | 1074 | "X-Forwarded-For": "10.0.0.1", |
1047 | 1075 | } |
1048 | 1076 | fetchPublicURL(context.Background(), ts.URL, "", nil, nil, extraHeaders) |
|
0 commit comments