github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/mongo/mongometrics/dialmetrics_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENSE file for details. 3 4 package mongometrics_test 5 6 import ( 7 "errors" 8 "net" 9 "reflect" 10 "time" 11 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 "github.com/prometheus/client_golang/prometheus" 15 dto "github.com/prometheus/client_model/go" 16 gc "gopkg.in/check.v1" 17 18 "github.com/juju/juju/mongo/mongometrics" 19 ) 20 21 type DialCollectorSuite struct { 22 testing.IsolationSuite 23 collector *mongometrics.DialCollector 24 } 25 26 var _ = gc.Suite(&DialCollectorSuite{}) 27 28 func (s *DialCollectorSuite) SetUpTest(c *gc.C) { 29 s.IsolationSuite.SetUpTest(c) 30 s.collector = mongometrics.NewDialCollector() 31 } 32 33 func (s *DialCollectorSuite) TestDescribe(c *gc.C) { 34 ch := make(chan *prometheus.Desc) 35 go func() { 36 defer close(ch) 37 s.collector.Describe(ch) 38 }() 39 var descs []*prometheus.Desc 40 for desc := range ch { 41 descs = append(descs, desc) 42 } 43 c.Assert(descs, gc.HasLen, 2) 44 c.Assert(descs[0].String(), gc.Matches, `.*fqName: "juju_mongo_dials_total".*`) 45 c.Assert(descs[1].String(), gc.Matches, `.*fqName: "juju_mongo_dial_duration_seconds".*`) 46 } 47 48 func (s *DialCollectorSuite) TestCollect(c *gc.C) { 49 s.collector.PostDialServer("foo", time.Second, nil) 50 s.collector.PostDialServer("foo", 2*time.Second, nil) 51 s.collector.PostDialServer("foo", 3*time.Second, nil) 52 s.collector.PostDialServer("bar", time.Millisecond, errors.New("bewm")) 53 s.collector.PostDialServer("baz", time.Minute, &net.OpError{ 54 Op: "read", 55 Err: errors.New("bewm"), 56 }) 57 s.collector.PostDialServer("qux", time.Hour, netError{ 58 error: errors.New("bewm"), 59 timeout: true, 60 temporary: true, 61 }) 62 63 ch := make(chan prometheus.Metric) 64 go func() { 65 defer close(ch) 66 s.collector.Collect(ch) 67 }() 68 69 var dtoMetrics [8]dto.Metric 70 var metrics []prometheus.Metric 71 for metric := range ch { 72 metrics = append(metrics, metric) 73 } 74 c.Assert(metrics, gc.HasLen, len(dtoMetrics)) 75 76 for i, metric := range metrics { 77 err := metric.Write(&dtoMetrics[i]) 78 c.Assert(err, jc.ErrorIsNil) 79 } 80 81 float64ptr := func(v float64) *float64 { 82 return &v 83 } 84 uint64ptr := func(v uint64) *uint64 { 85 return &v 86 } 87 labelpair := func(n, v string) *dto.LabelPair { 88 return &dto.LabelPair{Name: &n, Value: &v} 89 } 90 expected := []dto.Metric{{ 91 Counter: &dto.Counter{Value: float64ptr(3)}, 92 Label: []*dto.LabelPair{ 93 labelpair("failed", ""), 94 labelpair("server", "foo"), 95 labelpair("timeout", ""), 96 }, 97 }, { 98 Counter: &dto.Counter{Value: float64ptr(1)}, 99 Label: []*dto.LabelPair{ 100 labelpair("failed", "failed"), 101 labelpair("server", "bar"), 102 labelpair("timeout", ""), 103 }, 104 }, { 105 Counter: &dto.Counter{Value: float64ptr(1)}, 106 Label: []*dto.LabelPair{ 107 labelpair("failed", "read"), 108 labelpair("server", "baz"), 109 labelpair("timeout", ""), 110 }, 111 }, { 112 Counter: &dto.Counter{Value: float64ptr(1)}, 113 Label: []*dto.LabelPair{ 114 labelpair("failed", "failed"), 115 labelpair("server", "qux"), 116 labelpair("timeout", "timed out"), 117 }, 118 }, { 119 Label: []*dto.LabelPair{ 120 labelpair("failed", ""), 121 labelpair("server", "foo"), 122 labelpair("timeout", ""), 123 }, 124 Summary: &dto.Summary{ 125 SampleCount: uint64ptr(3), 126 SampleSum: float64ptr(6), 127 Quantile: []*dto.Quantile{{ 128 Quantile: float64ptr(0.5), 129 Value: float64ptr(2), 130 }, { 131 Quantile: float64ptr(0.9), 132 Value: float64ptr(3), 133 }, { 134 Quantile: float64ptr(0.99), 135 Value: float64ptr(3), 136 }}, 137 }, 138 }, { 139 Label: []*dto.LabelPair{ 140 labelpair("failed", "failed"), 141 labelpair("server", "bar"), 142 labelpair("timeout", ""), 143 }, 144 Summary: &dto.Summary{ 145 SampleCount: uint64ptr(1), 146 SampleSum: float64ptr(0.001), 147 Quantile: []*dto.Quantile{{ 148 Quantile: float64ptr(0.5), 149 Value: float64ptr(0.001), 150 }, { 151 Quantile: float64ptr(0.9), 152 Value: float64ptr(0.001), 153 }, { 154 Quantile: float64ptr(0.99), 155 Value: float64ptr(0.001), 156 }}, 157 }, 158 }, { 159 Label: []*dto.LabelPair{ 160 labelpair("failed", "read"), 161 labelpair("server", "baz"), 162 labelpair("timeout", ""), 163 }, 164 Summary: &dto.Summary{ 165 SampleCount: uint64ptr(1), 166 SampleSum: float64ptr(60), 167 Quantile: []*dto.Quantile{{ 168 Quantile: float64ptr(0.5), 169 Value: float64ptr(60), 170 }, { 171 Quantile: float64ptr(0.9), 172 Value: float64ptr(60), 173 }, { 174 Quantile: float64ptr(0.99), 175 Value: float64ptr(60), 176 }}, 177 }, 178 }, { 179 Label: []*dto.LabelPair{ 180 labelpair("failed", "failed"), 181 labelpair("server", "qux"), 182 labelpair("timeout", "timed out"), 183 }, 184 Summary: &dto.Summary{ 185 SampleCount: uint64ptr(1), 186 SampleSum: float64ptr(3600), 187 Quantile: []*dto.Quantile{{ 188 Quantile: float64ptr(0.5), 189 Value: float64ptr(3600), 190 }, { 191 Quantile: float64ptr(0.9), 192 Value: float64ptr(3600), 193 }, { 194 Quantile: float64ptr(0.99), 195 Value: float64ptr(3600), 196 }}, 197 }, 198 }} 199 for i := range dtoMetrics { 200 var found bool 201 for j := range expected { 202 if !metricsEqual(&dtoMetrics[i], &expected[j]) { 203 continue 204 } 205 expected = append(expected[:j], expected[j+1:]...) 206 found = true 207 break 208 } 209 if !found { 210 c.Errorf("metric %+v not expected", &dtoMetrics[i]) 211 } 212 } 213 } 214 215 func metricsEqual(m1 *dto.Metric, m2 *dto.Metric) bool { 216 if !reflect.DeepEqual(m1.Label, m2.Label) { 217 return false 218 } 219 if !reflect.DeepEqual(m1.Gauge, m2.Gauge) { 220 return false 221 } 222 if m1.Counter != nil || m2.Counter != nil { 223 if m1.Counter == nil || m2.Counter == nil { 224 return false 225 } 226 if m1.Counter.GetValue() != m2.Counter.GetValue() { 227 return false 228 } 229 } 230 if m1.Gauge != nil || m2.Gauge != nil { 231 if m1.Gauge == nil || m2.Gauge == nil { 232 return false 233 } 234 if m1.Gauge.GetValue() != m2.Gauge.GetValue() { 235 return false 236 } 237 } 238 if m1.Summary != nil || m2.Summary != nil { 239 if m1.Summary == nil || m2.Summary == nil { 240 return false 241 } 242 if m1.Summary.GetSampleSum() != m2.Summary.GetSampleSum() { 243 return false 244 } 245 if m1.Summary.GetSampleCount() != m2.Summary.GetSampleCount() { 246 return false 247 } 248 if !reflect.DeepEqual(m1.Summary.GetQuantile(), m2.Summary.GetQuantile()) { 249 return false 250 } 251 } 252 if m1.Histogram != nil || m2.Histogram != nil { 253 if m1.Histogram == nil || m2.Histogram == nil { 254 return false 255 } 256 if m1.Histogram.GetSampleSum() != m2.Histogram.GetSampleSum() { 257 return false 258 } 259 if m1.Histogram.GetSampleCount() != m2.Histogram.GetSampleCount() { 260 return false 261 } 262 if !reflect.DeepEqual(m1.Histogram.GetBucket(), m2.Histogram.GetBucket()) { 263 return false 264 } 265 } 266 267 return true 268 } 269 270 type netError struct { 271 error 272 timeout bool 273 temporary bool 274 } 275 276 func (e netError) Timeout() bool { 277 return e.timeout 278 } 279 280 func (e netError) Temporary() bool { 281 return e.temporary 282 }