github.com/thanos-io/thanos@v0.32.5/pkg/extprom/tx_gauge_test.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package extprom 5 6 import ( 7 "sort" 8 "testing" 9 10 "github.com/efficientgo/core/testutil" 11 "github.com/prometheus/client_golang/prometheus" 12 dto "github.com/prometheus/client_model/go" 13 "github.com/prometheus/prometheus/model/labels" 14 "google.golang.org/protobuf/proto" 15 ) 16 17 func TestTxGaugeVec(t *testing.T) { 18 g := NewTxGaugeVec(nil, prometheus.GaugeOpts{ 19 Name: "metric", 20 }, []string{"a", "b"}, []string{"a1", "b1"}, []string{"a2", "b2"}) 21 22 strPtr := func(s string) *string { 23 return &s 24 } 25 26 floatPtr := func(f float64) *float64 { 27 return &f 28 } 29 30 for _, tcase := range []struct { 31 name string 32 txUse func() 33 exp map[string]float64 34 expDto []proto.Message 35 }{ 36 { 37 name: "nothing", 38 txUse: func() {}, 39 expDto: []proto.Message{ 40 &dto.Metric{ 41 Gauge: &dto.Gauge{ 42 Value: floatPtr(0), 43 }, 44 Label: []*dto.LabelPair{ 45 { 46 Name: strPtr("a"), 47 Value: strPtr("a1"), 48 }, 49 { 50 Name: strPtr("b"), 51 Value: strPtr("b1"), 52 }, 53 }, 54 }, 55 &dto.Metric{ 56 Gauge: &dto.Gauge{ 57 Value: floatPtr(0), 58 }, 59 Label: []*dto.LabelPair{ 60 { 61 Name: strPtr("a"), 62 Value: strPtr("a2"), 63 }, 64 { 65 Name: strPtr("b"), 66 Value: strPtr("b2"), 67 }, 68 }, 69 }, 70 }, 71 }, 72 { 73 name: "change a=a1,b=b1", 74 txUse: func() { 75 g.WithLabelValues("a1", "b1").Inc() 76 g.WithLabelValues("a1", "b1").Add(0.3) 77 }, 78 expDto: []proto.Message{ 79 &dto.Metric{ 80 Gauge: &dto.Gauge{ 81 Value: floatPtr(1.3), 82 }, 83 Label: []*dto.LabelPair{ 84 { 85 Name: strPtr("a"), 86 Value: strPtr("a1"), 87 }, 88 { 89 Name: strPtr("b"), 90 Value: strPtr("b1"), 91 }, 92 }, 93 }, 94 &dto.Metric{ 95 Gauge: &dto.Gauge{ 96 Value: floatPtr(0), 97 }, 98 Label: []*dto.LabelPair{ 99 { 100 Name: strPtr("a"), 101 Value: strPtr("a2"), 102 }, 103 { 104 Name: strPtr("b"), 105 Value: strPtr("b2"), 106 }, 107 }, 108 }, 109 }, 110 }, 111 { 112 name: "change a=a1,b=b1 again, should return same result", 113 txUse: func() { 114 g.WithLabelValues("a1", "b1").Inc() 115 g.WithLabelValues("a1", "b1").Add(-10) 116 g.WithLabelValues("a1", "b1").Add(10.3) 117 }, 118 expDto: []proto.Message{ 119 &dto.Metric{ 120 Gauge: &dto.Gauge{ 121 Value: floatPtr(1.3000000000000007), 122 }, 123 Label: []*dto.LabelPair{ 124 { 125 Name: strPtr("a"), 126 Value: strPtr("a1"), 127 }, 128 { 129 Name: strPtr("b"), 130 Value: strPtr("b1"), 131 }, 132 }, 133 }, 134 &dto.Metric{ 135 Gauge: &dto.Gauge{ 136 Value: floatPtr(0), 137 }, 138 Label: []*dto.LabelPair{ 139 { 140 Name: strPtr("a"), 141 Value: strPtr("a2"), 142 }, 143 { 144 Name: strPtr("b"), 145 Value: strPtr("b2"), 146 }, 147 }, 148 }, 149 }, 150 }, 151 { 152 name: "change a=a1,b=b1 again, should return same result", 153 txUse: func() { 154 g.WithLabelValues("a1", "b1").Inc() 155 g.WithLabelValues("a1", "b1").Add(-10) 156 g.WithLabelValues("a1", "b1").Set(1.3) 157 }, 158 expDto: []proto.Message{ 159 &dto.Metric{ 160 Gauge: &dto.Gauge{ 161 Value: floatPtr(1.3), 162 }, 163 Label: []*dto.LabelPair{ 164 { 165 Name: strPtr("a"), 166 Value: strPtr("a1"), 167 }, 168 { 169 Name: strPtr("b"), 170 Value: strPtr("b1"), 171 }, 172 }, 173 }, 174 &dto.Metric{ 175 Gauge: &dto.Gauge{ 176 Value: floatPtr(0), 177 }, 178 Label: []*dto.LabelPair{ 179 { 180 Name: strPtr("a"), 181 Value: strPtr("a2"), 182 }, 183 { 184 Name: strPtr("b"), 185 Value: strPtr("b2"), 186 }, 187 }, 188 }, 189 }, 190 }, 191 { 192 name: "nothing again", 193 txUse: func() {}, 194 expDto: []proto.Message{ 195 &dto.Metric{ 196 Gauge: &dto.Gauge{ 197 Value: floatPtr(0), 198 }, 199 Label: []*dto.LabelPair{ 200 { 201 Name: strPtr("a"), 202 Value: strPtr("a1"), 203 }, 204 { 205 Name: strPtr("b"), 206 Value: strPtr("b1"), 207 }, 208 }, 209 }, 210 &dto.Metric{ 211 Gauge: &dto.Gauge{ 212 Value: floatPtr(0), 213 }, 214 Label: []*dto.LabelPair{ 215 { 216 Name: strPtr("a"), 217 Value: strPtr("a2"), 218 }, 219 { 220 Name: strPtr("b"), 221 Value: strPtr("b2"), 222 }, 223 }, 224 }, 225 }, 226 }, 227 { 228 name: "change a=aX,b=b1", 229 txUse: func() { 230 g.WithLabelValues("aX", "b1").Set(500.2) 231 }, 232 expDto: []proto.Message{ 233 &dto.Metric{ 234 Gauge: &dto.Gauge{ 235 Value: floatPtr(0), 236 }, 237 Label: []*dto.LabelPair{ 238 { 239 Name: strPtr("a"), 240 Value: strPtr("a1"), 241 }, 242 { 243 Name: strPtr("b"), 244 Value: strPtr("b1"), 245 }, 246 }, 247 }, 248 &dto.Metric{ 249 Gauge: &dto.Gauge{ 250 Value: floatPtr(0), 251 }, 252 Label: []*dto.LabelPair{ 253 { 254 Name: strPtr("a"), 255 Value: strPtr("a2"), 256 }, 257 { 258 Name: strPtr("b"), 259 Value: strPtr("b2"), 260 }, 261 }, 262 }, 263 &dto.Metric{ 264 Gauge: &dto.Gauge{ 265 Value: floatPtr(500.2), 266 }, 267 Label: []*dto.LabelPair{ 268 { 269 Name: strPtr("a"), 270 Value: strPtr("aX"), 271 }, 272 { 273 Name: strPtr("b"), 274 Value: strPtr("b1"), 275 }, 276 }, 277 }, 278 }, 279 }, 280 { 281 name: "change a=aX,b=b1", 282 txUse: func() { 283 g.WithLabelValues("aX", "b1").Set(500.2) 284 }, 285 expDto: []proto.Message{ 286 &dto.Metric{ 287 Gauge: &dto.Gauge{ 288 Value: floatPtr(0), 289 }, 290 Label: []*dto.LabelPair{ 291 { 292 Name: strPtr("a"), 293 Value: strPtr("a1"), 294 }, 295 { 296 Name: strPtr("b"), 297 Value: strPtr("b1"), 298 }, 299 }, 300 }, 301 &dto.Metric{ 302 Gauge: &dto.Gauge{ 303 Value: floatPtr(500.2), 304 }, 305 Label: []*dto.LabelPair{ 306 { 307 Name: strPtr("a"), 308 Value: strPtr("aX"), 309 }, 310 { 311 Name: strPtr("b"), 312 Value: strPtr("b1"), 313 }, 314 }, 315 }, 316 &dto.Metric{ 317 Gauge: &dto.Gauge{ 318 Value: floatPtr(0), 319 }, 320 Label: []*dto.LabelPair{ 321 { 322 Name: strPtr("a"), 323 Value: strPtr("a2"), 324 }, 325 { 326 Name: strPtr("b"), 327 Value: strPtr("b2"), 328 }, 329 }, 330 }, 331 }, 332 }, 333 { 334 name: "nothing again", 335 txUse: func() {}, 336 expDto: []proto.Message{ 337 &dto.Metric{ 338 Gauge: &dto.Gauge{ 339 Value: floatPtr(0), 340 }, 341 Label: []*dto.LabelPair{ 342 { 343 Name: strPtr("a"), 344 Value: strPtr("a1"), 345 }, 346 { 347 Name: strPtr("b"), 348 Value: strPtr("b1"), 349 }, 350 }, 351 }, 352 &dto.Metric{ 353 Gauge: &dto.Gauge{ 354 Value: floatPtr(0), 355 }, 356 Label: []*dto.LabelPair{ 357 { 358 Name: strPtr("a"), 359 Value: strPtr("a2"), 360 }, 361 { 362 Name: strPtr("b"), 363 Value: strPtr("b2"), 364 }, 365 }, 366 }, 367 }, 368 }, 369 { 370 name: "change 3 metrics", 371 txUse: func() { 372 g.WithLabelValues("a1", "b1").Inc() 373 g.WithLabelValues("a2", "b2").Add(-2) 374 g.WithLabelValues("a3", "b3").Set(1.1) 375 }, 376 expDto: []proto.Message{ 377 &dto.Metric{ 378 Gauge: &dto.Gauge{ 379 Value: floatPtr(1), 380 }, 381 Label: []*dto.LabelPair{ 382 { 383 Name: strPtr("a"), 384 Value: strPtr("a1"), 385 }, 386 { 387 Name: strPtr("b"), 388 Value: strPtr("b1"), 389 }, 390 }, 391 }, 392 &dto.Metric{ 393 Gauge: &dto.Gauge{ 394 Value: floatPtr(-2), 395 }, 396 Label: []*dto.LabelPair{ 397 { 398 Name: strPtr("a"), 399 Value: strPtr("a2"), 400 }, 401 { 402 Name: strPtr("b"), 403 Value: strPtr("b2"), 404 }, 405 }, 406 }, 407 &dto.Metric{ 408 Gauge: &dto.Gauge{ 409 Value: floatPtr(1.1), 410 }, 411 Label: []*dto.LabelPair{ 412 { 413 Name: strPtr("a"), 414 Value: strPtr("a3"), 415 }, 416 { 417 Name: strPtr("b"), 418 Value: strPtr("b3"), 419 }, 420 }, 421 }, 422 }, 423 }, 424 { 425 name: "nothing again", 426 txUse: func() {}, 427 expDto: []proto.Message{ 428 &dto.Metric{ 429 Gauge: &dto.Gauge{ 430 Value: floatPtr(0), 431 }, 432 Label: []*dto.LabelPair{ 433 { 434 Name: strPtr("a"), 435 Value: strPtr("a1"), 436 }, 437 { 438 Name: strPtr("b"), 439 Value: strPtr("b1"), 440 }, 441 }, 442 }, 443 &dto.Metric{ 444 Gauge: &dto.Gauge{ 445 Value: floatPtr(0), 446 }, 447 Label: []*dto.LabelPair{ 448 { 449 Name: strPtr("a"), 450 Value: strPtr("a2"), 451 }, 452 { 453 Name: strPtr("b"), 454 Value: strPtr("b2"), 455 }, 456 }, 457 }, 458 }, 459 }, 460 } { 461 if ok := t.Run(tcase.name, func(t *testing.T) { 462 g.ResetTx() 463 464 tcase.txUse() 465 g.Submit() 466 467 got := toProtoMessage(t, g) 468 testutil.Equals(t, len(tcase.expDto), len(got)) 469 470 sortDtoMessages(got) 471 sortDtoMessages(tcase.expDto) 472 for i := 0; i < len(tcase.expDto); i++ { 473 testutil.Equals(t, true, proto.Equal(got[i], tcase.expDto[i])) 474 } 475 }); !ok { 476 return 477 } 478 } 479 } 480 481 func sortDtoMessages(msgs []proto.Message) { 482 sort.Slice(msgs, func(i, j int) bool { 483 m1 := msgs[i].(*dto.Metric) 484 m2 := msgs[j].(*dto.Metric) 485 486 lbls1 := labels.Labels{} 487 for _, p := range m1.GetLabel() { 488 lbls1 = append(lbls1, labels.Label{Name: *p.Name, Value: *p.Value}) 489 } 490 lbls2 := labels.Labels{} 491 for _, p := range m2.GetLabel() { 492 lbls2 = append(lbls2, labels.Label{Name: *p.Name, Value: *p.Value}) 493 } 494 495 return labels.Compare(lbls1, lbls2) < 0 496 }) 497 } 498 499 func toProtoMessage(t *testing.T, c prometheus.Collector) []proto.Message { 500 var ( 501 mChan = make(chan prometheus.Metric) 502 messages = make([]proto.Message, 0) 503 ) 504 505 go func() { 506 c.Collect(mChan) 507 close(mChan) 508 }() 509 510 for m := range mChan { 511 pb := &dto.Metric{} 512 testutil.Ok(t, m.Write(pb)) 513 514 messages = append(messages, pb) 515 } 516 517 return messages 518 }