@@ -8,11 +8,29 @@ import (
8
8
9
9
"github.com/go-chi/chi/v5"
10
10
"github.com/prometheus/client_golang/prometheus"
11
+ dto "github.com/prometheus/client_model/go"
12
+ "github.com/stretchr/testify/assert"
11
13
"github.com/stretchr/testify/require"
12
14
13
15
"github.com/coder/coder/v2/coderd/tracing"
16
+ "github.com/coder/coder/v2/testutil"
17
+ "github.com/coder/websocket"
14
18
)
15
19
20
+ func getMetricLabels (metrics []* dto.MetricFamily ) map [string ]map [string ]string {
21
+ metricLabels := map [string ]map [string ]string {}
22
+ for _ , metricFamily := range metrics {
23
+ metricName := metricFamily .GetName ()
24
+ metricLabels [metricName ] = map [string ]string {}
25
+ for _ , metric := range metricFamily .GetMetric () {
26
+ for _ , labelPair := range metric .GetLabel () {
27
+ metricLabels [metricName ][labelPair .GetName ()] = labelPair .GetValue ()
28
+ }
29
+ }
30
+ }
31
+ return metricLabels
32
+ }
33
+
16
34
func TestPrometheus (t * testing.T ) {
17
35
t .Parallel ()
18
36
t .Run ("All" , func (t * testing.T ) {
@@ -30,71 +48,74 @@ func TestPrometheus(t *testing.T) {
30
48
})
31
49
}
32
50
33
- func TestGetRoutePattern (t * testing.T ) {
51
+ func TestPrometheus_Concurrent (t * testing.T ) {
34
52
t .Parallel ()
53
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitShort )
54
+ defer cancel ()
55
+
35
56
reg := prometheus .NewRegistry ()
36
57
promMW := Prometheus (reg )
37
- // Create a test router with some routes
58
+
59
+ // Create a test handler to simulate a WebSocket connection
60
+ testHandler := http .HandlerFunc (func (rw http.ResponseWriter , r * http.Request ) {
61
+ conn , err := websocket .Accept (rw , r , nil )
62
+ if ! assert .NoError (t , err , "failed to accept websocket" ) {
63
+ return
64
+ }
65
+ defer conn .Close (websocket .StatusGoingAway , "" )
66
+ })
67
+
68
+ wrappedHandler := promMW (testHandler )
69
+
70
+ r := chi .NewRouter ()
71
+ r .Use (tracing .StatusWriterMiddleware , promMW )
72
+ r .Get ("/api/v2/build/{build}/logs" , func (rw http.ResponseWriter , r * http.Request ) {
73
+ wrappedHandler .ServeHTTP (rw , r )
74
+ })
75
+
76
+ srv := httptest .NewServer (r )
77
+ defer srv .Close ()
78
+ // nolint: bodyclose
79
+ conn , _ , err := websocket .Dial (ctx , srv .URL + "/api/v2/build/1/logs" , nil )
80
+ require .NoError (t , err , "failed to dial WebSocket" )
81
+ defer conn .Close (websocket .StatusNormalClosure , "" )
82
+
83
+ metrics , err := reg .Gather ()
84
+ require .NoError (t , err )
85
+ require .Greater (t , len (metrics ), 0 )
86
+ metricLabels := getMetricLabels (metrics )
87
+
88
+ concurrentWebsockets , ok := metricLabels ["coderd_api_concurrent_websockets" ]
89
+ require .True (t , ok , "coderd_api_concurrent_websockets metric not found" )
90
+ require .Equal (t , "/api/v2/build/{build}/logs" , concurrentWebsockets ["path" ])
91
+ }
92
+
93
+ func TestGetRoutePattern_UserRoute (t * testing.T ) {
94
+ t .Parallel ()
95
+ reg := prometheus .NewRegistry ()
96
+ promMW := Prometheus (reg )
97
+
38
98
r := chi .NewRouter ()
39
- r .With (promMW ).Get ("/api/v2/workspaces/{workspace}" , func (w http.ResponseWriter , r * http.Request ) {})
40
99
r .With (promMW ).Get ("/api/v2/users/{user}" , func (w http.ResponseWriter , r * http.Request ) {})
41
- r .With (promMW ).Get ("/static/*" , func (w http.ResponseWriter , r * http.Request ) {})
42
-
43
- tests := []struct {
44
- name string
45
- method string
46
- path string
47
- expected string
48
- }{
49
- {
50
- name : "PatternAlreadyAvailable" ,
51
- method : "GET" ,
52
- path : "/api/v2/workspaces/test" ,
53
- expected : "/api/v2/workspaces/{workspace}" ,
54
- },
55
- {
56
- name : "UserRoute" ,
57
- method : "GET" ,
58
- path : "/api/v2/users/john" ,
59
- expected : "/api/v2/users/{user}" ,
60
- },
61
- {
62
- name : "StaticRoute" ,
63
- method : "GET" ,
64
- path : "/static/css/style.css" ,
65
- expected : "/static/*" ,
66
- },
67
- {
68
- name : "NoMatchingRoute" ,
69
- method : "GET" ,
70
- path : "/nonexistent" ,
71
- expected : "" ,
72
- },
73
- {
74
- name : "FrontendRoute" ,
75
- method : "GET" ,
76
- path : "/" ,
77
- expected : "" ,
78
- },
79
- }
80
100
81
- for _ , tt := range tests {
82
- tt := tt
83
- t .Run (tt .name , func (t * testing.T ) {
84
- t .Parallel ()
101
+ req := httptest .NewRequest ("GET" , "/api/v2/users/john" , nil )
85
102
86
- req := httptest . NewRequest ( tt . method , tt . path , nil )
103
+ sw := & tracing. StatusWriter { ResponseWriter : httptest . NewRecorder ()}
87
104
88
- sw := & tracing. StatusWriter { ResponseWriter : httptest . NewRecorder ()}
105
+ r . ServeHTTP ( sw , req )
89
106
90
- r .ServeHTTP (sw , req )
107
+ metrics , err := reg .Gather ()
108
+ require .NoError (t , err )
109
+ require .Greater (t , len (metrics ), 0 )
110
+ metricLabels := getMetricLabels (metrics )
91
111
92
- metrics , err := reg .Gather ()
93
- require .NoError (t , err )
94
- require .Greater (t , len (metrics ), 0 )
112
+ reqProcessed , ok := metricLabels ["coderd_api_requests_processed_total" ]
113
+ require .True (t , ok , "coderd_api_requests_processed_total metric not found" )
114
+ require .Equal (t , "/api/v2/users/{user}" , reqProcessed ["path" ])
115
+ require .Equal (t , "GET" , reqProcessed ["method" ])
95
116
96
- // Verify the result
97
- // require.Equal (t, tt.expected, pattern, "unexpected route pattern ")
98
- } )
99
- }
117
+ concurrentRequests , ok := metricLabels [ "coderd_api_concurrent_requests" ]
118
+ require .True (t , ok , "coderd_api_concurrent_requests metric not found " )
119
+ require . Equal ( t , "/api/v2/users/{user}" , concurrentRequests [ "path" ] )
120
+ require . Equal ( t , "GET" , concurrentRequests [ "method" ])
100
121
}
0 commit comments