forked from github/github-mcp-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfields_telemetry_test.go
More file actions
123 lines (103 loc) · 3.69 KB
/
Copy pathfields_telemetry_test.go
File metadata and controls
123 lines (103 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package github
import (
"context"
"log/slog"
"sync"
"testing"
"time"
"github.com/github/github-mcp-server/pkg/observability"
"github.com/github/github-mcp-server/pkg/observability/metrics"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// recordingMetrics is a metrics.Metrics implementation that captures emitted
// metrics so tests can assert on telemetry. It is safe for concurrent use.
type recordingMetrics struct {
mu sync.Mutex
increments []recordedMetric
counters []recordedMetric
}
type recordedMetric struct {
key string
tags map[string]string
value int64
}
func (m *recordingMetrics) Increment(key string, tags map[string]string) {
m.mu.Lock()
defer m.mu.Unlock()
m.increments = append(m.increments, recordedMetric{key: key, tags: tags, value: 1})
}
func (m *recordingMetrics) Counter(key string, tags map[string]string, value int64) {
m.mu.Lock()
defer m.mu.Unlock()
m.counters = append(m.counters, recordedMetric{key: key, tags: tags, value: value})
}
func (m *recordingMetrics) Distribution(_ string, _ map[string]string, _ float64) {}
func (m *recordingMetrics) DistributionMs(_ string, _ map[string]string, _ time.Duration) {}
func (m *recordingMetrics) WithTags(_ map[string]string) metrics.Metrics { return m }
// counter returns the recorded counter for the given key, or false if absent.
func (m *recordingMetrics) counter(key string) (recordedMetric, bool) {
m.mu.Lock()
defer m.mu.Unlock()
for _, c := range m.counters {
if c.key == key {
return c, true
}
}
return recordedMetric{}, false
}
// increment returns the recorded increment for the given key, or false if absent.
func (m *recordingMetrics) increment(key string) (recordedMetric, bool) {
m.mu.Lock()
defer m.mu.Unlock()
for _, c := range m.increments {
if c.key == key {
return c, true
}
}
return recordedMetric{}, false
}
// depsWithRecordingMetrics returns BaseDeps wired with a recording metrics sink
// plus the sink for assertions.
func depsWithRecordingMetrics(t *testing.T, base BaseDeps) (BaseDeps, *recordingMetrics) {
t.Helper()
rec := &recordingMetrics{}
exporters, err := observability.NewExporters(slog.New(slog.DiscardHandler), rec)
require.NoError(t, err)
base.Obsv = exporters
return base, rec
}
func Test_recordFieldsUsage_Filtered(t *testing.T) {
deps, rec := depsWithRecordingMetrics(t, BaseDeps{})
recordFieldsUsage(context.Background(), deps, "search_code", true, 100, 30)
call, ok := rec.increment(metricFieldsToolCall)
require.True(t, ok)
assert.Equal(t, "search_code", call.tags["tool"])
assert.Equal(t, "true", call.tags["filtered"])
full, ok := rec.counter(metricFieldsBytesFull)
require.True(t, ok)
assert.Equal(t, int64(100), full.value)
assert.Equal(t, "search_code", full.tags["tool"])
assert.NotContains(t, full.tags, "filtered")
sent, ok := rec.counter(metricFieldsBytesSent)
require.True(t, ok)
assert.Equal(t, int64(30), sent.value)
}
func Test_recordFieldsUsage_NotFiltered(t *testing.T) {
deps, rec := depsWithRecordingMetrics(t, BaseDeps{})
recordFieldsUsage(context.Background(), deps, "search_code", false, 100, 100)
call, ok := rec.increment(metricFieldsToolCall)
require.True(t, ok)
assert.Equal(t, "false", call.tags["filtered"])
// No byte counters are emitted when the response was not filtered.
_, ok = rec.counter(metricFieldsBytesFull)
assert.False(t, ok)
_, ok = rec.counter(metricFieldsBytesSent)
assert.False(t, ok)
}
func Test_recordFieldsUsage_NilExporterDoesNotPanic(t *testing.T) {
// BaseDeps with no Obsv falls back to a noop sink rather than panicking.
assert.NotPanics(t, func() {
recordFieldsUsage(context.Background(), BaseDeps{}, "search_code", true, 100, 30)
})
}