1
2
3
4
5
6
7
8
9
10
11
12
13
14 package cloudsqlconn
15
16 import (
17 "context"
18 "sync"
19 "testing"
20 "time"
21
22 "cloud.google.com/go/cloudsqlconn/internal/mock"
23 "go.opencensus.io/stats/view"
24 )
25
26 type spyMetricsExporter struct {
27 mu sync.Mutex
28 data []*view.Data
29 }
30
31 func (e *spyMetricsExporter) ExportView(vd *view.Data) {
32 e.mu.Lock()
33 defer e.mu.Unlock()
34 e.data = append(e.data, vd)
35 }
36
37 type metric struct {
38 name string
39 data view.AggregationData
40 }
41
42 func (e *spyMetricsExporter) Data() []metric {
43 e.mu.Lock()
44 defer e.mu.Unlock()
45 var res []metric
46 for _, d := range e.data {
47 for _, r := range d.Rows {
48 res = append(res, metric{name: d.View.Name, data: r.Data})
49 }
50 }
51 return res
52 }
53
54
55
56 func wantLastValueMetric(t *testing.T, wantName string, ms []metric) {
57 t.Helper()
58 gotNames := make(map[string]view.AggregationData)
59 for _, m := range ms {
60 gotNames[m.name] = m.data
61 _, ok := m.data.(*view.LastValueData)
62 if m.name == wantName && ok {
63 return
64 }
65 }
66 t.Fatalf("metric name want = %v with LastValueData, all metrics = %#v", wantName, gotNames)
67 }
68
69
70
71 func wantDistributionMetric(t *testing.T, wantName string, ms []metric) {
72 t.Helper()
73 gotNames := make(map[string]view.AggregationData)
74 for _, m := range ms {
75 gotNames[m.name] = m.data
76 _, ok := m.data.(*view.DistributionData)
77 if m.name == wantName && ok {
78 return
79 }
80 }
81 t.Fatalf("metric name want = %v with DistributionData, all metrics = %#v", wantName, gotNames)
82 }
83
84
85
86 func wantCountMetric(t *testing.T, wantName string, ms []metric) {
87 t.Helper()
88 gotNames := make(map[string]view.AggregationData)
89 for _, m := range ms {
90 gotNames[m.name] = m.data
91 _, ok := m.data.(*view.CountData)
92 if m.name == wantName && ok {
93 return
94 }
95 }
96 t.Fatalf("metric name want = %v with CountData, all metrics = %#v", wantName, gotNames)
97 }
98
99 func TestDialerWithMetrics(t *testing.T) {
100 spy := &spyMetricsExporter{}
101 view.RegisterExporter(spy)
102 defer view.UnregisterExporter(spy)
103 view.SetReportingPeriod(time.Millisecond)
104
105 inst := mock.NewFakeCSQLInstance("my-project", "my-region", "my-instance")
106 svc, cleanup, err := mock.NewSQLAdminService(
107 context.Background(),
108 mock.InstanceGetSuccess(inst, 1),
109 mock.CreateEphemeralSuccess(inst, 1),
110 )
111 if err != nil {
112 t.Fatalf("failed to init SQLAdminService: %v", err)
113 }
114 stop := mock.StartServerProxy(t, inst)
115 defer func() {
116 stop()
117 if err := cleanup(); err != nil {
118 t.Fatalf("%v", err)
119 }
120 }()
121
122 d, err := NewDialer(context.Background(),
123 WithDefaultDialOptions(WithPublicIP()),
124 WithTokenSource(mock.EmptyTokenSource{}),
125 )
126 if err != nil {
127 t.Fatalf("expected NewDialer to succeed, but got error: %v", err)
128 }
129 d.sqladmin = svc
130
131
132 conn, err := d.Dial(context.Background(), "my-project:my-region:my-instance")
133 if err != nil {
134 t.Fatalf("expected Dial to succeed, but got error: %v", err)
135 }
136 defer conn.Close()
137
138 _, err = d.Dial(context.Background(), "my-project:my-region:notaninstance")
139 if err == nil {
140 t.Fatal("expected Dial to fail, but got no error")
141 }
142
143 time.Sleep(10 * time.Millisecond)
144
145
146 wantLastValueMetric(t, "cloudsqlconn/open_connections", spy.Data())
147 wantDistributionMetric(t, "cloudsqlconn/dial_latency", spy.Data())
148 wantCountMetric(t, "cloudsqlconn/refresh_success_count", spy.Data())
149
150
151 wantCountMetric(t, "cloudsqlconn/dial_failure_count", spy.Data())
152 wantCountMetric(t, "cloudsqlconn/refresh_failure_count", spy.Data())
153 }
154
View as plain text