github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/mongo/mongometrics/txnmetrics_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENSE file for details. 3 4 package mongometrics_test 5 6 import ( 7 "errors" 8 "time" 9 10 "github.com/juju/mgo/v3/bson" 11 "github.com/juju/mgo/v3/txn" 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 TxnCollectorSuite struct { 22 testing.IsolationSuite 23 collector *mongometrics.TxnCollector 24 } 25 26 var _ = gc.Suite(&TxnCollectorSuite{}) 27 28 func (s *TxnCollectorSuite) SetUpTest(c *gc.C) { 29 s.IsolationSuite.SetUpTest(c) 30 s.collector = mongometrics.NewTxnCollector() 31 } 32 33 func (s *TxnCollectorSuite) 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, 3) 44 c.Assert(descs[0].String(), gc.Matches, `.*fqName: "juju_mgo_txn_ops_total".*`) 45 c.Assert(descs[1].String(), gc.Matches, `.*fqName: "juju_mgo_txn_retries".*`) 46 c.Assert(descs[2].String(), gc.Matches, `.*fqName: "juju_mgo_txn_durations".*`) 47 } 48 49 func (s *TxnCollectorSuite) TestCollect(c *gc.C) { 50 s.collector.AfterRunTransaction("dbname", "modeluuid", 1, time.Millisecond, []txn.Op{{ 51 C: "update-coll", 52 Update: bson.D{}, 53 }, { 54 C: "insert-coll", 55 Insert: bson.D{}, 56 }, { 57 C: "remove-coll", 58 Remove: true, 59 }, { 60 C: "assert-coll", 61 }}, nil) 62 63 s.collector.AfterRunTransaction("dbname", "modeluuid", 1, time.Millisecond, []txn.Op{{ 64 C: "update-coll", 65 Update: bson.D{}, 66 }}, errors.New("bewm")) 67 68 ch := make(chan prometheus.Metric) 69 go func() { 70 defer close(ch) 71 s.collector.Collect(ch) 72 }() 73 74 var metrics []prometheus.Metric 75 for metric := range ch { 76 metrics = append(metrics, metric) 77 } 78 c.Assert(metrics, gc.HasLen, 7) 79 80 var dtoMetrics [7]dto.Metric 81 for i, metric := range metrics { 82 err := metric.Write(&dtoMetrics[i]) 83 c.Assert(err, jc.ErrorIsNil) 84 } 85 86 float64ptr := func(v float64) *float64 { 87 return &v 88 } 89 uint64ptr := func(v uint64) *uint64 { 90 return &v 91 } 92 labelpair := func(n, v string) *dto.LabelPair { 93 return &dto.LabelPair{Name: &n, Value: &v} 94 } 95 var retryBuckets []*dto.Bucket 96 for i := 0; i < 50; i++ { 97 count := uint64(0) 98 if i > 0 { 99 count = 5 100 } 101 retryBuckets = append(retryBuckets, &dto.Bucket{ 102 CumulativeCount: uint64ptr(count), 103 UpperBound: float64ptr(float64(i)), 104 }) 105 } 106 var durationBuckets []*dto.Bucket 107 for i := 0; i < 50; i++ { 108 count := uint64(0) 109 if i > 0 { 110 count = 5 111 } 112 durationBuckets = append(durationBuckets, &dto.Bucket{ 113 CumulativeCount: uint64ptr(count), 114 UpperBound: float64ptr(float64(2 * i)), 115 }) 116 } 117 expected := []dto.Metric{ 118 { 119 Counter: &dto.Counter{Value: float64ptr(1)}, 120 Label: []*dto.LabelPair{ 121 labelpair("collection", "update-coll"), 122 labelpair("database", "dbname"), 123 labelpair("failed", ""), 124 labelpair("optype", "update"), 125 }, 126 }, 127 { 128 Counter: &dto.Counter{Value: float64ptr(1)}, 129 Label: []*dto.LabelPair{ 130 labelpair("collection", "insert-coll"), 131 labelpair("database", "dbname"), 132 labelpair("failed", ""), 133 labelpair("optype", "insert"), 134 }, 135 }, 136 { 137 Counter: &dto.Counter{Value: float64ptr(1)}, 138 Label: []*dto.LabelPair{ 139 labelpair("collection", "remove-coll"), 140 labelpair("database", "dbname"), 141 labelpair("failed", ""), 142 labelpair("optype", "remove"), 143 }, 144 }, 145 { 146 Counter: &dto.Counter{Value: float64ptr(1)}, 147 Label: []*dto.LabelPair{ 148 labelpair("collection", "assert-coll"), 149 labelpair("database", "dbname"), 150 labelpair("failed", ""), 151 labelpair("optype", "assert"), 152 }, 153 }, 154 { 155 Counter: &dto.Counter{Value: float64ptr(1)}, 156 Label: []*dto.LabelPair{ 157 labelpair("collection", "update-coll"), 158 labelpair("database", "dbname"), 159 labelpair("failed", "failed"), 160 labelpair("optype", "update"), 161 }, 162 }, 163 { 164 Histogram: &dto.Histogram{ 165 SampleCount: uint64ptr(5), 166 SampleSum: float64ptr(5), 167 Bucket: retryBuckets, 168 }, 169 }, 170 { 171 Histogram: &dto.Histogram{ 172 SampleCount: uint64ptr(5), 173 SampleSum: float64ptr(5), 174 Bucket: durationBuckets, 175 }, 176 }, 177 } 178 for i := range dtoMetrics { 179 var found bool 180 for j := range expected { 181 if !metricsEqual(&dtoMetrics[i], &expected[j]) { 182 continue 183 } 184 expected = append(expected[:j], expected[j+1:]...) 185 found = true 186 break 187 } 188 if !found { 189 c.Errorf("metric %+v not expected", &dtoMetrics[i]) 190 } 191 } 192 }