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