github.com/MetalBlockchain/metalgo@v1.11.9/api/metrics/label_gatherer_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package metrics 5 6 import ( 7 "testing" 8 9 "github.com/prometheus/client_golang/prometheus" 10 "github.com/stretchr/testify/require" 11 "google.golang.org/protobuf/proto" 12 13 dto "github.com/prometheus/client_model/go" 14 ) 15 16 func TestLabelGatherer_Gather(t *testing.T) { 17 const ( 18 labelName = "smith" 19 labelValueA = "rick" 20 labelValueB = "morty" 21 customLabelName = "tag" 22 customLabelValueA = "a" 23 customLabelValueB = "b" 24 ) 25 tests := []struct { 26 name string 27 labelName string 28 expectedMetrics []*dto.Metric 29 expectErr bool 30 }{ 31 { 32 name: "no overlap", 33 labelName: customLabelName, 34 expectedMetrics: []*dto.Metric{ 35 { 36 Label: []*dto.LabelPair{ 37 { 38 Name: proto.String(labelName), 39 Value: proto.String(labelValueB), 40 }, 41 { 42 Name: proto.String(customLabelName), 43 Value: proto.String(customLabelValueB), 44 }, 45 }, 46 Counter: &dto.Counter{ 47 Value: proto.Float64(1), 48 }, 49 }, 50 { 51 Label: []*dto.LabelPair{ 52 { 53 Name: proto.String(labelName), 54 Value: proto.String(labelValueA), 55 }, 56 { 57 Name: proto.String(customLabelName), 58 Value: proto.String(customLabelValueA), 59 }, 60 }, 61 Counter: &dto.Counter{ 62 Value: proto.Float64(0), 63 }, 64 }, 65 }, 66 expectErr: false, 67 }, 68 { 69 name: "has overlap", 70 labelName: labelName, 71 expectedMetrics: []*dto.Metric{ 72 { 73 Label: []*dto.LabelPair{ 74 { 75 Name: proto.String(labelName), 76 Value: proto.String(labelValueB), 77 }, 78 { 79 Name: proto.String(customLabelName), 80 Value: proto.String(customLabelValueB), 81 }, 82 }, 83 Counter: &dto.Counter{ 84 Value: proto.Float64(1), 85 }, 86 }, 87 }, 88 expectErr: true, 89 }, 90 } 91 for _, test := range tests { 92 t.Run(test.name, func(t *testing.T) { 93 require := require.New(t) 94 95 gatherer := NewLabelGatherer(labelName) 96 require.NotNil(gatherer) 97 98 registerA := prometheus.NewRegistry() 99 require.NoError(gatherer.Register(labelValueA, registerA)) 100 { 101 counterA := prometheus.NewCounterVec( 102 counterOpts, 103 []string{test.labelName}, 104 ) 105 counterA.With(prometheus.Labels{test.labelName: customLabelValueA}) 106 require.NoError(registerA.Register(counterA)) 107 } 108 109 registerB := prometheus.NewRegistry() 110 require.NoError(gatherer.Register(labelValueB, registerB)) 111 { 112 counterB := prometheus.NewCounterVec( 113 counterOpts, 114 []string{customLabelName}, 115 ) 116 counterB.With(prometheus.Labels{customLabelName: customLabelValueB}).Inc() 117 require.NoError(registerB.Register(counterB)) 118 } 119 120 metrics, err := gatherer.Gather() 121 if test.expectErr { 122 require.Error(err) //nolint:forbidigo // the error is not exported 123 } else { 124 require.NoError(err) 125 } 126 require.Equal( 127 []*dto.MetricFamily{ 128 { 129 Name: proto.String(counterOpts.Name), 130 Help: proto.String(counterOpts.Help), 131 Type: dto.MetricType_COUNTER.Enum(), 132 Metric: test.expectedMetrics, 133 }, 134 }, 135 metrics, 136 ) 137 }) 138 } 139 } 140 141 func TestLabelGatherer_Register(t *testing.T) { 142 firstLabeledGatherer := &labeledGatherer{ 143 labelValue: "first", 144 gatherer: &testGatherer{}, 145 } 146 firstLabelGatherer := func() *labelGatherer { 147 return &labelGatherer{ 148 multiGatherer: multiGatherer{ 149 names: []string{firstLabeledGatherer.labelValue}, 150 gatherers: prometheus.Gatherers{ 151 firstLabeledGatherer, 152 }, 153 }, 154 } 155 } 156 secondLabeledGatherer := &labeledGatherer{ 157 labelValue: "second", 158 gatherer: &testGatherer{ 159 mfs: []*dto.MetricFamily{{}}, 160 }, 161 } 162 secondLabelGatherer := &labelGatherer{ 163 multiGatherer: multiGatherer{ 164 names: []string{ 165 firstLabeledGatherer.labelValue, 166 secondLabeledGatherer.labelValue, 167 }, 168 gatherers: prometheus.Gatherers{ 169 firstLabeledGatherer, 170 secondLabeledGatherer, 171 }, 172 }, 173 } 174 175 tests := []struct { 176 name string 177 labelGatherer *labelGatherer 178 labelValue string 179 gatherer prometheus.Gatherer 180 expectedErr error 181 expectedLabelGatherer *labelGatherer 182 }{ 183 { 184 name: "first registration", 185 labelGatherer: &labelGatherer{}, 186 labelValue: "first", 187 gatherer: firstLabeledGatherer.gatherer, 188 expectedErr: nil, 189 expectedLabelGatherer: firstLabelGatherer(), 190 }, 191 { 192 name: "second registration", 193 labelGatherer: firstLabelGatherer(), 194 labelValue: "second", 195 gatherer: secondLabeledGatherer.gatherer, 196 expectedErr: nil, 197 expectedLabelGatherer: secondLabelGatherer, 198 }, 199 { 200 name: "conflicts with previous registration", 201 labelGatherer: firstLabelGatherer(), 202 labelValue: "first", 203 gatherer: secondLabeledGatherer.gatherer, 204 expectedErr: errDuplicateGatherer, 205 expectedLabelGatherer: firstLabelGatherer(), 206 }, 207 } 208 for _, test := range tests { 209 t.Run(test.name, func(t *testing.T) { 210 require := require.New(t) 211 212 err := test.labelGatherer.Register(test.labelValue, test.gatherer) 213 require.ErrorIs(err, test.expectedErr) 214 require.Equal(test.expectedLabelGatherer, test.labelGatherer) 215 }) 216 } 217 }