@@ -22,6 +22,7 @@ import (
22
22
"net"
23
23
"os"
24
24
"path"
25
+ "strings"
25
26
"sync"
26
27
"testing"
27
28
"time"
@@ -35,6 +36,9 @@ import (
35
36
"github.com/stretchr/testify/require"
36
37
37
38
"github.com/container-storage-interface/spec/lib/go/csi"
39
+
40
+ "github.com/kubernetes-csi/csi-lib-utils/metrics"
41
+ "k8s.io/component-base/metrics/testutil"
38
42
)
39
43
40
44
func tmpDir (t * testing.T ) string {
@@ -84,7 +88,7 @@ func TestConnect(t *testing.T) {
84
88
addr , stopServer := startServer (t , tmp , nil , nil )
85
89
defer stopServer ()
86
90
87
- conn , err := Connect (addr )
91
+ conn , err := Connect (addr , metrics . NewCSIMetricsManager ( "fake.csi.driver.io" ) )
88
92
if assert .NoError (t , err , "connect via absolute path" ) &&
89
93
assert .NotNil (t , conn , "got a connection" ) {
90
94
assert .Equal (t , connectivity .Ready , conn .GetState (), "connection ready" )
@@ -99,7 +103,7 @@ func TestConnectUnix(t *testing.T) {
99
103
addr , stopServer := startServer (t , tmp , nil , nil )
100
104
defer stopServer ()
101
105
102
- conn , err := Connect ("unix:///" + addr )
106
+ conn , err := Connect ("unix:///" + addr , metrics . NewCSIMetricsManager ( "fake.csi.driver.io" ) )
103
107
if assert .NoError (t , err , "connect with unix:/// prefix" ) &&
104
108
assert .NotNil (t , conn , "got a connection" ) {
105
109
assert .Equal (t , connectivity .Ready , conn .GetState (), "connection ready" )
@@ -139,7 +143,7 @@ func TestWaitForServer(t *testing.T) {
139
143
startTimeServer = time .Now ()
140
144
_ , stopServer = startServer (t , tmp , nil , nil )
141
145
}()
142
- conn , err := Connect (path .Join (tmp , serverSock ))
146
+ conn , err := Connect (path .Join (tmp , serverSock ), metrics . NewCSIMetricsManager ( "fake.csi.driver.io" ) )
143
147
if assert .NoError (t , err , "connect via absolute path" ) {
144
148
endTime := time .Now ()
145
149
assert .NotNil (t , conn , "got a connection" )
@@ -158,7 +162,7 @@ func TestTimout(t *testing.T) {
158
162
159
163
startTime := time .Now ()
160
164
timeout := 5 * time .Second
161
- conn , err := connect (path .Join (tmp , "no-such.sock" ), []grpc.DialOption {grpc .WithTimeout (timeout )}, nil )
165
+ conn , err := connect (path .Join (tmp , "no-such.sock" ), metrics . NewCSIMetricsManager ( "fake.csi.driver.io" ), []grpc.DialOption {grpc .WithTimeout (timeout )}, nil )
162
166
endTime := time .Now ()
163
167
if assert .Error (t , err , "connection should fail" ) {
164
168
assert .InEpsilon (t , timeout , endTime .Sub (startTime ), 1 , "connection timeout" )
@@ -177,7 +181,7 @@ func TestReconnect(t *testing.T) {
177
181
}()
178
182
179
183
// Allow reconnection (the default).
180
- conn , err := Connect (addr )
184
+ conn , err := Connect (addr , metrics . NewCSIMetricsManager ( "fake.csi.driver.io" ) )
181
185
if assert .NoError (t , err , "connect via absolute path" ) &&
182
186
assert .NotNil (t , conn , "got a connection" ) {
183
187
defer conn .Close ()
@@ -222,7 +226,7 @@ func TestDisconnect(t *testing.T) {
222
226
}()
223
227
224
228
reconnectCount := 0
225
- conn , err := Connect (addr , OnConnectionLoss (func () bool {
229
+ conn , err := Connect (addr , metrics . NewCSIMetricsManager ( "fake.csi.driver.io" ), OnConnectionLoss (func () bool {
226
230
reconnectCount ++
227
231
// Don't reconnect.
228
232
return false
@@ -273,7 +277,7 @@ func TestExplicitReconnect(t *testing.T) {
273
277
}()
274
278
275
279
reconnectCount := 0
276
- conn , err := Connect (addr , OnConnectionLoss (func () bool {
280
+ conn , err := Connect (addr , metrics . NewCSIMetricsManager ( "fake.csi.driver.io" ), OnConnectionLoss (func () bool {
277
281
reconnectCount ++
278
282
// Reconnect.
279
283
return true
@@ -314,3 +318,81 @@ func TestExplicitReconnect(t *testing.T) {
314
318
assert .Equal (t , 1 , reconnectCount , "connection loss callback should be called once" )
315
319
}
316
320
}
321
+
322
+ func TestConnectMetrics (t * testing.T ) {
323
+ tmp := tmpDir (t )
324
+ defer os .RemoveAll (tmp )
325
+ addr , stopServer := startServer (t , tmp , nil , nil )
326
+ defer stopServer ()
327
+
328
+ cmm := metrics .NewCSIMetricsManager ("fake.csi.driver.io" )
329
+ conn , err := Connect (addr , cmm )
330
+ if assert .NoError (t , err , "connect via absolute path" ) &&
331
+ assert .NotNil (t , conn , "got a connection" ) {
332
+ defer conn .Close ()
333
+ assert .Equal (t , connectivity .Ready , conn .GetState (), "connection ready" )
334
+
335
+ if err := conn .Invoke (context .Background (), "/csi.v1.Controller/ControllerGetCapabilities" , nil , nil ); assert .Error (t , err ) {
336
+ errStatus , _ := status .FromError (err )
337
+ assert .Equal (t , codes .Unimplemented , errStatus .Code (), "not implemented" )
338
+ }
339
+ }
340
+
341
+ expectedMetrics := `# HELP csi_sidecar_operations_seconds [ALPHA] Container Storage Interface operation duration with gRPC error code status total
342
+ # TYPE csi_sidecar_operations_seconds histogram
343
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="0.1"} 1
344
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="0.25"} 1
345
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="0.5"} 1
346
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="1"} 1
347
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="2.5"} 1
348
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="5"} 1
349
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="10"} 1
350
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="15"} 1
351
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="25"} 1
352
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="50"} 1
353
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="120"} 1
354
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="300"} 1
355
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="600"} 1
356
+ csi_sidecar_operations_seconds_bucket{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities",le="+Inf"} 1
357
+ csi_sidecar_operations_seconds_sum{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities"} 0
358
+ csi_sidecar_operations_seconds_count{driver_name="fake.csi.driver.io",grpc_status_code="Unimplemented",method_name="/csi.v1.Controller/ControllerGetCapabilities"} 1
359
+ `
360
+
361
+ if err := testutil .GatherAndCompare (
362
+ cmm .GetRegistry (), strings .NewReader (expectedMetrics )); err != nil {
363
+ // Ignore mismatches on csi_sidecar_operations_seconds_sum metric because execution time will vary from test to test.
364
+ err = verifyMetricsError (t , err , "csi_sidecar_operations_seconds_sum" )
365
+ if err != nil {
366
+ t .Errorf ("Expected metrics not found -- %v" , err )
367
+ }
368
+ }
369
+ }
370
+
371
+ func verifyMetricsError (t * testing.T , err error , metricToIgnore string ) error {
372
+ errStringArr := strings .Split (err .Error (), "got:" )
373
+
374
+ if len (errStringArr ) != 2 {
375
+ return err
376
+ }
377
+
378
+ want := errStringArr [0 ]
379
+ got := strings .TrimSpace (errStringArr [1 ])
380
+
381
+ if want == "" || got == "" {
382
+ return err
383
+ }
384
+
385
+ wantArr := strings .Split (err .Error (), "want:" )
386
+ if len (wantArr ) != 2 {
387
+ return err
388
+ }
389
+
390
+ want = strings .TrimSpace (wantArr [1 ])
391
+
392
+ if matchErr := metrics .VerifyMetricsMatch (want , got , metricToIgnore ); matchErr != nil {
393
+ t .Errorf ("%v" , matchErr )
394
+ return err
395
+ }
396
+
397
+ return nil
398
+ }
0 commit comments