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  }