github.com/thanos-io/thanos@v0.32.5/pkg/store/labelpb/label_test.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package labelpb
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"reflect"
    10  	"sort"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/prometheus/prometheus/model/labels"
    15  
    16  	"github.com/efficientgo/core/testutil"
    17  )
    18  
    19  var testLsetMap = map[string]string{
    20  	"a":                           "1",
    21  	"c":                           "2",
    22  	"d":                           "dsfsdfsdfsdf123414234",
    23  	"124134235423534534ffdasdfsf": "1",
    24  	"":                            "",
    25  	"b":                           "",
    26  }
    27  
    28  func TestLabelsToPromLabels_LabelsToPromLabels(t *testing.T) {
    29  	testutil.Equals(t, labels.FromMap(testLsetMap), ZLabelsToPromLabels(ZLabelsFromPromLabels(labels.FromMap(testLsetMap))))
    30  
    31  	lset := labels.FromMap(testLsetMap)
    32  	for i := range ZLabelsFromPromLabels(lset) {
    33  		if lset[i].Name != "a" {
    34  			continue
    35  		}
    36  		lset[i].Value += "yolo"
    37  
    38  	}
    39  	m := lset.Map()
    40  	testutil.Equals(t, "1yolo", m["a"])
    41  
    42  	m["a"] = "1"
    43  	testutil.Equals(t, testLsetMap, m)
    44  }
    45  
    46  func TestLabelMarshal_Unmarshal(t *testing.T) {
    47  	l := ZLabelsFromPromLabels(labels.FromStrings("aaaaaaa", "bbbbb"))[0]
    48  	b, err := (&l).Marshal()
    49  	testutil.Ok(t, err)
    50  
    51  	l2 := &ZLabel{}
    52  	testutil.Ok(t, l2.Unmarshal(b))
    53  	testutil.Equals(t, labels.FromStrings("aaaaaaa", "bbbbb"), ZLabelsToPromLabels([]ZLabel{*l2}))
    54  }
    55  
    56  func TestExtendLabels(t *testing.T) {
    57  	testutil.Equals(t, labels.Labels{{Name: "a", Value: "1"}, {Name: "replica", Value: "01"}, {Name: "xb", Value: "2"}},
    58  		ExtendSortedLabels(labels.Labels{{Name: "a", Value: "1"}, {Name: "xb", Value: "2"}}, labels.FromStrings("replica", "01")))
    59  
    60  	testutil.Equals(t, labels.Labels{{Name: "replica", Value: "01"}},
    61  		ExtendSortedLabels(labels.Labels{}, labels.FromStrings("replica", "01")))
    62  
    63  	testutil.Equals(t, labels.Labels{{Name: "a", Value: "1"}, {Name: "replica", Value: "01"}, {Name: "xb", Value: "2"}},
    64  		ExtendSortedLabels(labels.Labels{{Name: "a", Value: "1"}, {Name: "replica", Value: "NOT01"}, {Name: "xb", Value: "2"}}, labels.FromStrings("replica", "01")))
    65  
    66  	testInjectExtLabels(testutil.NewTB(t))
    67  }
    68  
    69  func TestValidateLabels(t *testing.T) {
    70  	testCases := []struct {
    71  		labelSet    []ZLabel
    72  		expectedErr error
    73  	}{
    74  		{
    75  			// No labels at all.
    76  			labelSet:    []ZLabel{},
    77  			expectedErr: ErrEmptyLabels,
    78  		},
    79  		{
    80  			// Empty label.
    81  			labelSet: []ZLabel{
    82  				{
    83  					Name:  "foo",
    84  					Value: "bar",
    85  				},
    86  				{
    87  					Name:  "",
    88  					Value: "baz",
    89  				},
    90  			},
    91  			expectedErr: ErrEmptyLabels,
    92  		},
    93  		{
    94  			// Empty label (first label).
    95  			labelSet: []ZLabel{
    96  				{
    97  					Name:  "",
    98  					Value: "bar",
    99  				},
   100  				{
   101  					Name:  "foo",
   102  					Value: "baz",
   103  				},
   104  			},
   105  			expectedErr: ErrEmptyLabels,
   106  		},
   107  		{
   108  			// Empty label (empty value).
   109  			labelSet: []ZLabel{
   110  				{
   111  					Name:  "foo",
   112  					Value: "bar",
   113  				},
   114  				{
   115  					Name:  "baz",
   116  					Value: "",
   117  				},
   118  			},
   119  			expectedErr: ErrEmptyLabels,
   120  		},
   121  		{
   122  			// Out-of-order and duplicate label (out-of-order comes first).
   123  			labelSet: []ZLabel{
   124  				{
   125  					Name:  "foo",
   126  					Value: "bar",
   127  				},
   128  				{
   129  					Name:  "test",
   130  					Value: "baz",
   131  				},
   132  				{
   133  					Name:  "foo",
   134  					Value: "bar",
   135  				},
   136  			},
   137  			expectedErr: ErrOutOfOrderLabels,
   138  		},
   139  		{
   140  			// Out-of-order and duplicate label (out-of-order comes first).
   141  			labelSet: []ZLabel{
   142  				{
   143  					Name:  "__test__",
   144  					Value: "baz",
   145  				},
   146  				{
   147  					Name:  "foo",
   148  					Value: "bar",
   149  				},
   150  				{
   151  					Name:  "foo",
   152  					Value: "bar",
   153  				},
   154  				{
   155  					Name:  "test",
   156  					Value: "baz",
   157  				},
   158  			},
   159  			expectedErr: ErrDuplicateLabels,
   160  		},
   161  		{
   162  			// Empty and duplicate label (empty comes first).
   163  			labelSet: []ZLabel{
   164  				{
   165  					Name:  "foo",
   166  					Value: "bar",
   167  				},
   168  				{
   169  					Name:  "",
   170  					Value: "baz",
   171  				},
   172  				{
   173  					Name:  "foo",
   174  					Value: "bar",
   175  				},
   176  			},
   177  			expectedErr: ErrEmptyLabels,
   178  		},
   179  		{
   180  			// Wrong order.
   181  			labelSet: []ZLabel{
   182  				{
   183  					Name:  "a",
   184  					Value: "bar",
   185  				},
   186  				{
   187  					Name:  "b",
   188  					Value: "baz",
   189  				},
   190  				{
   191  					Name:  "__name__",
   192  					Value: "test",
   193  				},
   194  			},
   195  			expectedErr: ErrOutOfOrderLabels,
   196  		},
   197  		{
   198  			// Wrong order and duplicate (wrong order comes first).
   199  			labelSet: []ZLabel{
   200  				{
   201  					Name:  "a",
   202  					Value: "bar",
   203  				},
   204  				{
   205  					Name:  "__name__",
   206  					Value: "test",
   207  				},
   208  				{
   209  					Name:  "a",
   210  					Value: "bar",
   211  				},
   212  			},
   213  			expectedErr: ErrOutOfOrderLabels,
   214  		},
   215  		{
   216  			// All good.
   217  			labelSet: []ZLabel{
   218  				{
   219  					Name:  "__name__",
   220  					Value: "test",
   221  				},
   222  				{
   223  					Name:  "a1",
   224  					Value: "bar",
   225  				},
   226  				{
   227  					Name:  "a2",
   228  					Value: "baz",
   229  				},
   230  			},
   231  			expectedErr: nil,
   232  		},
   233  	}
   234  
   235  	for i, tc := range testCases {
   236  		t.Run(fmt.Sprintf("case %d", i+1), func(t *testing.T) {
   237  			err := ValidateLabels(tc.labelSet)
   238  			testutil.Equals(t, tc.expectedErr, err)
   239  		})
   240  	}
   241  
   242  }
   243  
   244  func BenchmarkExtendLabels(b *testing.B) {
   245  	testInjectExtLabels(testutil.NewTB(b))
   246  }
   247  
   248  var x labels.Labels
   249  
   250  func testInjectExtLabels(tb testutil.TB) {
   251  	in := labels.FromStrings(
   252  		"__name__", "subscription_labels",
   253  		"_id", "0dfsdfsdsfdsffd1e96-4432-9abe-e33436ea969a",
   254  		"account", "1afsdfsddsfsdfsdfsdfsdfs",
   255  		"ebs_account", "1asdasdad45",
   256  		"email_domain", "asdasddgfkw.example.com",
   257  		"endpoint", "metrics",
   258  		"external_organization", "dfsdfsdf",
   259  		"instance", "10.128.4.231:8080",
   260  		"job", "sdd-acct-mngr-metrics",
   261  		"managed", "false",
   262  		"namespace", "production",
   263  		"organization", "dasdadasdasasdasaaFGDSG",
   264  		"pod", "sdd-acct-mngr-6669c947c8-xjx7f",
   265  		"prometheus", "telemeter-production/telemeter",
   266  		"prometheus_replica", "prometheus-telemeter-1",
   267  		"risk", "5",
   268  		"service", "sdd-acct-mngr-metrics",
   269  		"support", "Self-Support", // Should be overwritten.
   270  	)
   271  	extLset := labels.FromStrings(
   272  		"support", "Host-Support",
   273  		"replica", "1",
   274  		"tenant", "2342",
   275  	)
   276  	tb.ResetTimer()
   277  	for i := 0; i < tb.N(); i++ {
   278  		x = ExtendSortedLabels(in, extLset)
   279  
   280  		if !tb.IsBenchmark() {
   281  			testutil.Equals(tb, labels.FromStrings(
   282  				"__name__", "subscription_labels",
   283  				"_id", "0dfsdfsdsfdsffd1e96-4432-9abe-e33436ea969a",
   284  				"account", "1afsdfsddsfsdfsdfsdfsdfs",
   285  				"ebs_account", "1asdasdad45",
   286  				"email_domain", "asdasddgfkw.example.com",
   287  				"endpoint", "metrics",
   288  				"external_organization", "dfsdfsdf",
   289  				"instance", "10.128.4.231:8080",
   290  				"job", "sdd-acct-mngr-metrics",
   291  				"managed", "false",
   292  				"namespace", "production",
   293  				"organization", "dasdadasdasasdasaaFGDSG",
   294  				"pod", "sdd-acct-mngr-6669c947c8-xjx7f",
   295  				"prometheus", "telemeter-production/telemeter",
   296  				"prometheus_replica", "prometheus-telemeter-1",
   297  				"replica", "1",
   298  				"risk", "5",
   299  				"service", "sdd-acct-mngr-metrics",
   300  				"support", "Host-Support",
   301  				"tenant", "2342",
   302  			), x)
   303  		}
   304  	}
   305  	fmt.Fprint(io.Discard, x)
   306  }
   307  
   308  var (
   309  	zdest ZLabel
   310  	dest  Label
   311  )
   312  
   313  func BenchmarkZLabelsMarshalUnmarshal(b *testing.B) {
   314  	const (
   315  		fmtLbl = "%07daaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"
   316  		num    = 1000000
   317  	)
   318  
   319  	b.Run("Label", func(b *testing.B) {
   320  		b.ReportAllocs()
   321  		lbls := LabelSet{Labels: make([]Label, 0, num)}
   322  		for i := 0; i < num; i++ {
   323  			lbls.Labels = append(lbls.Labels, Label{Name: fmt.Sprintf(fmtLbl, i), Value: fmt.Sprintf(fmtLbl, i)})
   324  		}
   325  		b.ResetTimer()
   326  
   327  		for i := 0; i < b.N; i++ {
   328  			data, err := lbls.Marshal()
   329  			testutil.Ok(b, err)
   330  
   331  			dest = Label{}
   332  			testutil.Ok(b, (&dest).Unmarshal(data))
   333  		}
   334  	})
   335  
   336  	b.Run("ZLabel", func(b *testing.B) {
   337  		b.ReportAllocs()
   338  		lbls := ZLabelSet{Labels: make([]ZLabel, 0, num)}
   339  		for i := 0; i < num; i++ {
   340  			lbls.Labels = append(lbls.Labels, ZLabel{Name: fmt.Sprintf(fmtLbl, i), Value: fmt.Sprintf(fmtLbl, i)})
   341  		}
   342  		b.ResetTimer()
   343  
   344  		for i := 0; i < b.N; i++ {
   345  			data, err := lbls.Marshal()
   346  			testutil.Ok(b, err)
   347  
   348  			zdest = ZLabel{}
   349  			testutil.Ok(b, (&zdest).Unmarshal(data))
   350  		}
   351  	})
   352  }
   353  
   354  func BenchmarkTransformWithAndWithoutCopyWithSingleLabel(b *testing.B) {
   355  	benchmarkTransformWithAndWithoutCopy(b, 1)
   356  }
   357  
   358  func BenchmarkTransformWithAndWithoutCopyWith1000Labels(b *testing.B) {
   359  	benchmarkTransformWithAndWithoutCopy(b, 1000)
   360  }
   361  
   362  func BenchmarkTransformWithAndWithoutCopyWith100000Labels(b *testing.B) {
   363  	benchmarkTransformWithAndWithoutCopy(b, 100000)
   364  }
   365  
   366  var ret labels.Labels
   367  
   368  func benchmarkTransformWithAndWithoutCopy(b *testing.B, num int) {
   369  	const fmtLbl = "%07daaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"
   370  
   371  	b.Run("ZLabelsToPromLabels", func(b *testing.B) {
   372  		b.ReportAllocs()
   373  		lbls := make([]ZLabel, num)
   374  		for i := 0; i < num; i++ {
   375  			lbls[i] = ZLabel{Name: fmt.Sprintf(fmtLbl, i), Value: fmt.Sprintf(fmtLbl, i)}
   376  		}
   377  		b.ResetTimer()
   378  
   379  		for i := 0; i < b.N; i++ {
   380  			ret = ZLabelsToPromLabels(lbls)
   381  		}
   382  	})
   383  	b.Run("ZLabelsToPromLabelsWithRealloc", func(b *testing.B) {
   384  		b.ReportAllocs()
   385  		lbls := make([]ZLabel, num)
   386  		for i := 0; i < num; i++ {
   387  			lbls[i] = ZLabel{Name: fmt.Sprintf(fmtLbl, i), Value: fmt.Sprintf(fmtLbl, i)}
   388  		}
   389  		b.ResetTimer()
   390  
   391  		for i := 0; i < b.N; i++ {
   392  			ReAllocZLabelsStrings(&lbls, true)
   393  			ret = ZLabelsToPromLabels(lbls)
   394  		}
   395  	})
   396  }
   397  
   398  func TestSortZLabelSets(t *testing.T) {
   399  	expectedResult := ZLabelSets{
   400  		{
   401  			Labels: ZLabelsFromPromLabels(
   402  				labels.FromMap(map[string]string{
   403  					"__name__":    "grpc_client_handled_total",
   404  					"cluster":     "test",
   405  					"grpc_code":   "OK",
   406  					"grpc_method": "Info",
   407  				}),
   408  			),
   409  		},
   410  		{
   411  			Labels: ZLabelsFromPromLabels(
   412  				labels.FromMap(map[string]string{
   413  					"__name__":    "grpc_client_handled_total",
   414  					"cluster":     "test",
   415  					"grpc_code":   "OK",
   416  					"grpc_method": "LabelNames",
   417  				}),
   418  			),
   419  		},
   420  		{
   421  			Labels: ZLabelsFromPromLabels(
   422  				labels.FromMap(map[string]string{
   423  					"__name__":  "grpc_client_handled_total",
   424  					"cluster":   "test",
   425  					"grpc_code": "OK",
   426  					"aa":        "1",
   427  					"bb":        "2",
   428  					"cc":        "3",
   429  					"dd":        "4",
   430  					"ee":        "5",
   431  				}),
   432  			),
   433  		},
   434  		{
   435  			Labels: ZLabelsFromPromLabels(
   436  				labels.FromMap(map[string]string{
   437  					"__name__":  "grpc_client_handled_total",
   438  					"cluster":   "test",
   439  					"grpc_code": "OK",
   440  					"aa":        "1",
   441  					"bb":        "2",
   442  					"cc":        "3",
   443  					"dd":        "4",
   444  					"ee":        "5",
   445  				}),
   446  			),
   447  		},
   448  		{
   449  			Labels: ZLabelsFromPromLabels(
   450  				labels.FromMap(map[string]string{
   451  					"__name__":    "grpc_server_handled_total",
   452  					"cluster":     "test",
   453  					"grpc_code":   "OK",
   454  					"grpc_method": "Info",
   455  				}),
   456  			),
   457  		},
   458  		{
   459  			Labels: ZLabelsFromPromLabels(
   460  				labels.FromMap(map[string]string{
   461  					"__name__": "up",
   462  					"instance": "localhost:10908",
   463  				}),
   464  			),
   465  		},
   466  	}
   467  
   468  	list := ZLabelSets{
   469  		{
   470  			Labels: ZLabelsFromPromLabels(
   471  				labels.FromMap(map[string]string{
   472  					"__name__": "up",
   473  					"instance": "localhost:10908",
   474  				}),
   475  			),
   476  		},
   477  		{
   478  			Labels: ZLabelsFromPromLabels(
   479  				labels.FromMap(map[string]string{
   480  					"__name__":    "grpc_server_handled_total",
   481  					"cluster":     "test",
   482  					"grpc_code":   "OK",
   483  					"grpc_method": "Info",
   484  				}),
   485  			),
   486  		},
   487  		{
   488  			Labels: ZLabelsFromPromLabels(
   489  				labels.FromMap(map[string]string{
   490  					"__name__":    "grpc_client_handled_total",
   491  					"cluster":     "test",
   492  					"grpc_code":   "OK",
   493  					"grpc_method": "LabelNames",
   494  				}),
   495  			),
   496  		},
   497  		{
   498  			Labels: ZLabelsFromPromLabels(
   499  				labels.FromMap(map[string]string{
   500  					"__name__":    "grpc_client_handled_total",
   501  					"cluster":     "test",
   502  					"grpc_code":   "OK",
   503  					"grpc_method": "Info",
   504  				}),
   505  			),
   506  		},
   507  		{
   508  			Labels: ZLabelsFromPromLabels(
   509  				labels.FromMap(map[string]string{
   510  					"__name__":  "grpc_client_handled_total",
   511  					"cluster":   "test",
   512  					"grpc_code": "OK",
   513  					"aa":        "1",
   514  					"bb":        "2",
   515  					"cc":        "3",
   516  					"dd":        "4",
   517  					"ee":        "5",
   518  				}),
   519  			),
   520  		},
   521  		// This label set is the same as the previous one, which should correctly return 0 in Less() function.
   522  		{
   523  			Labels: ZLabelsFromPromLabels(
   524  				labels.FromMap(map[string]string{
   525  					"cluster":   "test",
   526  					"__name__":  "grpc_client_handled_total",
   527  					"grpc_code": "OK",
   528  					"aa":        "1",
   529  					"bb":        "2",
   530  					"cc":        "3",
   531  					"dd":        "4",
   532  					"ee":        "5",
   533  				}),
   534  			),
   535  		},
   536  	}
   537  
   538  	sort.Sort(list)
   539  	reflect.DeepEqual(expectedResult, list)
   540  }
   541  
   542  func TestHashWithPrefix(t *testing.T) {
   543  	lbls := []ZLabel{
   544  		{Name: "foo", Value: "bar"},
   545  		{Name: "baz", Value: "qux"},
   546  	}
   547  	testutil.Equals(t, HashWithPrefix("a", lbls), HashWithPrefix("a", lbls))
   548  	testutil.Assert(t, HashWithPrefix("a", lbls) != HashWithPrefix("a", []ZLabel{lbls[0]}))
   549  	testutil.Assert(t, HashWithPrefix("a", lbls) != HashWithPrefix("a", []ZLabel{lbls[1], lbls[0]}))
   550  	testutil.Assert(t, HashWithPrefix("a", lbls) != HashWithPrefix("b", lbls))
   551  }
   552  
   553  var benchmarkLabelsResult uint64
   554  
   555  func BenchmarkHasWithPrefix(b *testing.B) {
   556  	for _, tcase := range []struct {
   557  		name string
   558  		lbls []ZLabel
   559  	}{
   560  		{
   561  			name: "typical labels under 1KB",
   562  			lbls: func() []ZLabel {
   563  				lbls := make([]ZLabel, 10)
   564  				for i := 0; i < len(lbls); i++ {
   565  					// ZLabel ~20B name, 50B value.
   566  					lbls[i] = ZLabel{Name: fmt.Sprintf("abcdefghijabcdefghijabcdefghij%d", i), Value: fmt.Sprintf("abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij%d", i)}
   567  				}
   568  				return lbls
   569  			}(),
   570  		},
   571  		{
   572  			name: "bigger labels over 1KB",
   573  			lbls: func() []ZLabel {
   574  				lbls := make([]ZLabel, 10)
   575  				for i := 0; i < len(lbls); i++ {
   576  					//ZLabel ~50B name, 50B value.
   577  					lbls[i] = ZLabel{Name: fmt.Sprintf("abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij%d", i), Value: fmt.Sprintf("abcdefghijabcdefghijabcdefghijabcdefghijabcdefghij%d", i)}
   578  				}
   579  				return lbls
   580  			}(),
   581  		},
   582  		{
   583  			name: "extremely large label value 10MB",
   584  			lbls: func() []ZLabel {
   585  				lbl := &strings.Builder{}
   586  				lbl.Grow(1024 * 1024 * 10) // 10MB.
   587  				word := "abcdefghij"
   588  				for i := 0; i < lbl.Cap()/len(word); i++ {
   589  					_, _ = lbl.WriteString(word)
   590  				}
   591  				return []ZLabel{{Name: "__name__", Value: lbl.String()}}
   592  			}(),
   593  		},
   594  	} {
   595  		b.Run(tcase.name, func(b *testing.B) {
   596  			var h uint64
   597  
   598  			const prefix = "test-"
   599  
   600  			b.ReportAllocs()
   601  			b.ResetTimer()
   602  			for i := 0; i < b.N; i++ {
   603  				h = HashWithPrefix(prefix, tcase.lbls)
   604  			}
   605  			benchmarkLabelsResult = h
   606  		})
   607  	}
   608  }