github.com/hashicorp/go-metrics@v0.5.3/metrics_test.go (about)

     1  package metrics
     2  
     3  import (
     4  	"reflect"
     5  	"runtime"
     6  	"testing"
     7  	"time"
     8  )
     9  
    10  func mockMetric() (*MockSink, *Metrics) {
    11  	m := &MockSink{}
    12  	met := &Metrics{Config: Config{FilterDefault: true}, sink: m}
    13  	return m, met
    14  }
    15  
    16  func TestMetrics_SetGauge(t *testing.T) {
    17  	m, met := mockMetric()
    18  	met.SetGauge([]string{"key"}, float32(1))
    19  	if m.getKeys()[0][0] != "key" {
    20  		t.Fatalf("")
    21  	}
    22  	if m.vals[0] != 1 {
    23  		t.Fatalf("")
    24  	}
    25  
    26  	m, met = mockMetric()
    27  	labels := []Label{{"a", "b"}}
    28  	met.SetGaugeWithLabels([]string{"key"}, float32(1), labels)
    29  	if m.getKeys()[0][0] != "key" {
    30  		t.Fatalf("")
    31  	}
    32  	if m.vals[0] != 1 {
    33  		t.Fatalf("")
    34  	}
    35  	if !reflect.DeepEqual(m.labels[0], labels) {
    36  		t.Fatalf("")
    37  	}
    38  
    39  	m, met = mockMetric()
    40  	met.HostName = "test"
    41  	met.EnableHostname = true
    42  	met.SetGauge([]string{"key"}, float32(1))
    43  	if m.getKeys()[0][0] != "test" || m.getKeys()[0][1] != "key" {
    44  		t.Fatalf("")
    45  	}
    46  	if m.vals[0] != 1 {
    47  		t.Fatalf("")
    48  	}
    49  
    50  	m, met = mockMetric()
    51  	met.EnableTypePrefix = true
    52  	met.SetGauge([]string{"key"}, float32(1))
    53  	if m.getKeys()[0][0] != "gauge" || m.getKeys()[0][1] != "key" {
    54  		t.Fatalf("")
    55  	}
    56  	if m.vals[0] != 1 {
    57  		t.Fatalf("")
    58  	}
    59  
    60  	m, met = mockMetric()
    61  	met.ServiceName = "service"
    62  	met.SetGauge([]string{"key"}, float32(1))
    63  	if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" {
    64  		t.Fatalf("")
    65  	}
    66  	if m.vals[0] != 1 {
    67  		t.Fatalf("")
    68  	}
    69  }
    70  
    71  func TestMetrics_SetPrecisionGauge(t *testing.T) {
    72  	m, met := mockMetric()
    73  	met.SetPrecisionGauge([]string{"key"}, float64(1))
    74  	if m.getKeys()[0][0] != "key" {
    75  		t.Fatalf("")
    76  	}
    77  	if m.precisionVals[0] != 1 {
    78  		t.Fatalf("")
    79  	}
    80  
    81  	m, met = mockMetric()
    82  	labels := []Label{{"a", "b"}}
    83  	met.SetPrecisionGaugeWithLabels([]string{"key"}, float64(1), labels)
    84  	if m.getKeys()[0][0] != "key" {
    85  		t.Fatalf("")
    86  	}
    87  	if m.precisionVals[0] != 1 {
    88  		t.Fatalf("")
    89  	}
    90  	if !reflect.DeepEqual(m.labels[0], labels) {
    91  		t.Fatalf("")
    92  	}
    93  
    94  	m, met = mockMetric()
    95  	met.HostName = "test"
    96  	met.EnableHostname = true
    97  	met.SetPrecisionGauge([]string{"key"}, float64(1))
    98  	if m.getKeys()[0][0] != "test" || m.getKeys()[0][1] != "key" {
    99  		t.Fatalf("")
   100  	}
   101  	if m.precisionVals[0] != 1 {
   102  		t.Fatalf("")
   103  	}
   104  
   105  	m, met = mockMetric()
   106  	met.EnableTypePrefix = true
   107  	met.SetPrecisionGauge([]string{"key"}, float64(1))
   108  	if m.getKeys()[0][0] != "gauge" || m.getKeys()[0][1] != "key" {
   109  		t.Fatalf("")
   110  	}
   111  	if m.precisionVals[0] != 1 {
   112  		t.Fatalf("")
   113  	}
   114  
   115  	m, met = mockMetric()
   116  	met.ServiceName = "service"
   117  	met.SetPrecisionGauge([]string{"key"}, float64(1))
   118  	if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" {
   119  		t.Fatalf("")
   120  	}
   121  	if m.precisionVals[0] != 1 {
   122  		t.Fatalf("")
   123  	}
   124  }
   125  
   126  func TestMetrics_EmitKey(t *testing.T) {
   127  	m, met := mockMetric()
   128  	met.EmitKey([]string{"key"}, float32(1))
   129  	if m.getKeys()[0][0] != "key" {
   130  		t.Fatalf("")
   131  	}
   132  	if m.vals[0] != 1 {
   133  		t.Fatalf("")
   134  	}
   135  
   136  	m, met = mockMetric()
   137  	met.EnableTypePrefix = true
   138  	met.EmitKey([]string{"key"}, float32(1))
   139  	if m.getKeys()[0][0] != "kv" || m.getKeys()[0][1] != "key" {
   140  		t.Fatalf("")
   141  	}
   142  	if m.vals[0] != 1 {
   143  		t.Fatalf("")
   144  	}
   145  
   146  	m, met = mockMetric()
   147  	met.ServiceName = "service"
   148  	met.EmitKey([]string{"key"}, float32(1))
   149  	if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" {
   150  		t.Fatalf("")
   151  	}
   152  	if m.vals[0] != 1 {
   153  		t.Fatalf("")
   154  	}
   155  }
   156  
   157  func TestMetrics_IncrCounter(t *testing.T) {
   158  	m, met := mockMetric()
   159  	met.IncrCounter([]string{"key"}, float32(1))
   160  	if m.getKeys()[0][0] != "key" {
   161  		t.Fatalf("")
   162  	}
   163  	if m.vals[0] != 1 {
   164  		t.Fatalf("")
   165  	}
   166  
   167  	m, met = mockMetric()
   168  	labels := []Label{{"a", "b"}}
   169  	met.IncrCounterWithLabels([]string{"key"}, float32(1), labels)
   170  	if m.getKeys()[0][0] != "key" {
   171  		t.Fatalf("")
   172  	}
   173  	if m.vals[0] != 1 {
   174  		t.Fatalf("")
   175  	}
   176  	if !reflect.DeepEqual(m.labels[0], labels) {
   177  		t.Fatalf("")
   178  	}
   179  
   180  	m, met = mockMetric()
   181  	met.EnableTypePrefix = true
   182  	met.IncrCounter([]string{"key"}, float32(1))
   183  	if m.getKeys()[0][0] != "counter" || m.getKeys()[0][1] != "key" {
   184  		t.Fatalf("")
   185  	}
   186  	if m.vals[0] != 1 {
   187  		t.Fatalf("")
   188  	}
   189  
   190  	m, met = mockMetric()
   191  	met.ServiceName = "service"
   192  	met.IncrCounter([]string{"key"}, float32(1))
   193  	if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" {
   194  		t.Fatalf("")
   195  	}
   196  	if m.vals[0] != 1 {
   197  		t.Fatalf("")
   198  	}
   199  }
   200  
   201  func TestMetrics_AddSample(t *testing.T) {
   202  	m, met := mockMetric()
   203  	met.AddSample([]string{"key"}, float32(1))
   204  	if m.getKeys()[0][0] != "key" {
   205  		t.Fatalf("")
   206  	}
   207  	if m.vals[0] != 1 {
   208  		t.Fatalf("")
   209  	}
   210  
   211  	m, met = mockMetric()
   212  	labels := []Label{{"a", "b"}}
   213  	met.AddSampleWithLabels([]string{"key"}, float32(1), labels)
   214  	if m.getKeys()[0][0] != "key" {
   215  		t.Fatalf("")
   216  	}
   217  	if m.vals[0] != 1 {
   218  		t.Fatalf("")
   219  	}
   220  	if !reflect.DeepEqual(m.labels[0], labels) {
   221  		t.Fatalf("")
   222  	}
   223  
   224  	m, met = mockMetric()
   225  	met.EnableTypePrefix = true
   226  	met.AddSample([]string{"key"}, float32(1))
   227  	if m.getKeys()[0][0] != "sample" || m.getKeys()[0][1] != "key" {
   228  		t.Fatalf("")
   229  	}
   230  	if m.vals[0] != 1 {
   231  		t.Fatalf("")
   232  	}
   233  
   234  	m, met = mockMetric()
   235  	met.ServiceName = "service"
   236  	met.AddSample([]string{"key"}, float32(1))
   237  	if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" {
   238  		t.Fatalf("")
   239  	}
   240  	if m.vals[0] != 1 {
   241  		t.Fatalf("")
   242  	}
   243  }
   244  
   245  func TestMetrics_MeasureSince(t *testing.T) {
   246  	m, met := mockMetric()
   247  	met.TimerGranularity = time.Millisecond
   248  	n := time.Now()
   249  	met.MeasureSince([]string{"key"}, n)
   250  	if m.getKeys()[0][0] != "key" {
   251  		t.Fatalf("")
   252  	}
   253  	if m.vals[0] > 0.1 {
   254  		t.Fatalf("")
   255  	}
   256  
   257  	m, met = mockMetric()
   258  	met.TimerGranularity = time.Millisecond
   259  	labels := []Label{{"a", "b"}}
   260  	met.MeasureSinceWithLabels([]string{"key"}, n, labels)
   261  	if m.getKeys()[0][0] != "key" {
   262  		t.Fatalf("")
   263  	}
   264  	if m.vals[0] > 0.1 {
   265  		t.Fatalf("")
   266  	}
   267  	if !reflect.DeepEqual(m.labels[0], labels) {
   268  		t.Fatalf("")
   269  	}
   270  
   271  	m, met = mockMetric()
   272  	met.TimerGranularity = time.Millisecond
   273  	met.EnableTypePrefix = true
   274  	met.MeasureSince([]string{"key"}, n)
   275  	if m.getKeys()[0][0] != "timer" || m.getKeys()[0][1] != "key" {
   276  		t.Fatalf("")
   277  	}
   278  	if m.vals[0] > 0.1 {
   279  		t.Fatalf("")
   280  	}
   281  
   282  	m, met = mockMetric()
   283  	met.TimerGranularity = time.Millisecond
   284  	met.ServiceName = "service"
   285  	met.MeasureSince([]string{"key"}, n)
   286  	if m.getKeys()[0][0] != "service" || m.getKeys()[0][1] != "key" {
   287  		t.Fatalf("")
   288  	}
   289  	if m.vals[0] > 0.1 {
   290  		t.Fatalf("")
   291  	}
   292  }
   293  
   294  func TestMetrics_EmitRuntimeStats(t *testing.T) {
   295  	runtime.GC()
   296  	m, met := mockMetric()
   297  	met.EmitRuntimeStats()
   298  
   299  	if m.getKeys()[0][0] != "runtime" || m.getKeys()[0][1] != "num_goroutines" {
   300  		t.Fatalf("bad key %v", m.getKeys())
   301  	}
   302  	if m.vals[0] <= 1 {
   303  		t.Fatalf("bad val: %v", m.vals)
   304  	}
   305  
   306  	if m.getKeys()[1][0] != "runtime" || m.getKeys()[1][1] != "alloc_bytes" {
   307  		t.Fatalf("bad key %v", m.getKeys())
   308  	}
   309  	if m.vals[1] <= 40000 {
   310  		t.Fatalf("bad val: %v", m.vals)
   311  	}
   312  
   313  	if m.getKeys()[2][0] != "runtime" || m.getKeys()[2][1] != "sys_bytes" {
   314  		t.Fatalf("bad key %v", m.getKeys())
   315  	}
   316  	if m.vals[2] <= 100000 {
   317  		t.Fatalf("bad val: %v", m.vals)
   318  	}
   319  
   320  	if m.getKeys()[3][0] != "runtime" || m.getKeys()[3][1] != "malloc_count" {
   321  		t.Fatalf("bad key %v", m.getKeys())
   322  	}
   323  	if m.vals[3] <= 100 {
   324  		t.Fatalf("bad val: %v", m.vals)
   325  	}
   326  
   327  	if m.getKeys()[4][0] != "runtime" || m.getKeys()[4][1] != "free_count" {
   328  		t.Fatalf("bad key %v", m.getKeys())
   329  	}
   330  	if m.vals[4] <= 100 {
   331  		t.Fatalf("bad val: %v", m.vals)
   332  	}
   333  
   334  	if m.getKeys()[5][0] != "runtime" || m.getKeys()[5][1] != "heap_objects" {
   335  		t.Fatalf("bad key %v", m.getKeys())
   336  	}
   337  	if m.vals[5] <= 100 {
   338  		t.Fatalf("bad val: %v", m.vals)
   339  	}
   340  
   341  	if m.getKeys()[6][0] != "runtime" || m.getKeys()[6][1] != "total_gc_pause_ns" {
   342  		t.Fatalf("bad key %v", m.getKeys())
   343  	}
   344  	if m.vals[6] <= 100 {
   345  		t.Fatalf("bad val: %v\nkeys: %v", m.vals, m.getKeys())
   346  	}
   347  
   348  	if m.getKeys()[7][0] != "runtime" || m.getKeys()[7][1] != "total_gc_runs" {
   349  		t.Fatalf("bad key %v", m.getKeys())
   350  	}
   351  	if m.vals[7] < 1 {
   352  		t.Fatalf("bad val: %v", m.vals)
   353  	}
   354  
   355  	if m.getKeys()[8][0] != "runtime" || m.getKeys()[8][1] != "gc_pause_ns" {
   356  		t.Fatalf("bad key %v", m.getKeys())
   357  	}
   358  	if m.vals[8] <= 1000 {
   359  		t.Fatalf("bad val: %v", m.vals)
   360  	}
   361  }
   362  
   363  func TestInsert(t *testing.T) {
   364  	k := []string{"hi", "bob"}
   365  	exp := []string{"hi", "there", "bob"}
   366  	out := insert(1, "there", k)
   367  	if !reflect.DeepEqual(exp, out) {
   368  		t.Fatalf("bad insert %v %v", exp, out)
   369  	}
   370  }
   371  
   372  func TestMetrics_Filter_Blacklist(t *testing.T) {
   373  	m := &MockSink{}
   374  	conf := DefaultConfig("")
   375  	conf.AllowedPrefixes = []string{"service", "debug.thing"}
   376  	conf.BlockedPrefixes = []string{"debug"}
   377  	conf.EnableHostname = false
   378  	met, err := New(conf, m)
   379  	if err != nil {
   380  		t.Fatal(err)
   381  	}
   382  
   383  	// Allowed by default
   384  	key := []string{"thing"}
   385  	met.SetGauge(key, 1)
   386  	if !reflect.DeepEqual(m.getKeys()[0], key) {
   387  		t.Fatalf("key doesn't exist %v, %v", m.getKeys()[0], key)
   388  	}
   389  	if m.vals[0] != 1 {
   390  		t.Fatalf("bad val: %v", m.vals[0])
   391  	}
   392  
   393  	// Allowed by filter
   394  	key = []string{"service", "thing"}
   395  	met.SetGauge(key, 2)
   396  	if !reflect.DeepEqual(m.getKeys()[1], key) {
   397  		t.Fatalf("key doesn't exist")
   398  	}
   399  	if m.vals[1] != 2 {
   400  		t.Fatalf("bad val: %v", m.vals[1])
   401  	}
   402  
   403  	// Allowed by filter, subtree of a blocked entry
   404  	key = []string{"debug", "thing"}
   405  	met.SetGauge(key, 3)
   406  	if !reflect.DeepEqual(m.getKeys()[2], key) {
   407  		t.Fatalf("key doesn't exist")
   408  	}
   409  	if m.vals[2] != 3 {
   410  		t.Fatalf("bad val: %v", m.vals[2])
   411  	}
   412  
   413  	// Blocked by filter
   414  	key = []string{"debug", "other-thing"}
   415  	met.SetGauge(key, 4)
   416  	if len(m.getKeys()) != 3 {
   417  		t.Fatalf("key shouldn't exist")
   418  	}
   419  }
   420  
   421  func HasElem(s interface{}, elem interface{}) bool {
   422  	arrV := reflect.ValueOf(s)
   423  
   424  	if arrV.Kind() == reflect.Slice {
   425  		for i := 0; i < arrV.Len(); i++ {
   426  			if arrV.Index(i).Interface() == elem {
   427  				return true
   428  			}
   429  		}
   430  	}
   431  
   432  	return false
   433  }
   434  
   435  func TestMetrics_Filter_Whitelist(t *testing.T) {
   436  	m := &MockSink{}
   437  	conf := DefaultConfig("")
   438  	conf.AllowedPrefixes = []string{"service", "debug.thing"}
   439  	conf.BlockedPrefixes = []string{"debug"}
   440  	conf.FilterDefault = false
   441  	conf.EnableHostname = false
   442  	conf.BlockedLabels = []string{"bad_label"}
   443  	met, err := New(conf, m)
   444  	if err != nil {
   445  		t.Fatal(err)
   446  	}
   447  
   448  	// Blocked by default
   449  	key := []string{"thing"}
   450  	met.SetGauge(key, 1)
   451  	if len(m.getKeys()) != 0 {
   452  		t.Fatalf("key should not exist")
   453  	}
   454  
   455  	// Allowed by filter
   456  	key = []string{"service", "thing"}
   457  	met.SetGauge(key, 2)
   458  	if !reflect.DeepEqual(m.getKeys()[0], key) {
   459  		t.Fatalf("key doesn't exist")
   460  	}
   461  	if m.vals[0] != 2 {
   462  		t.Fatalf("bad val: %v", m.vals[0])
   463  	}
   464  
   465  	// Allowed by filter, subtree of a blocked entry
   466  	key = []string{"debug", "thing"}
   467  	met.SetGauge(key, 3)
   468  	if !reflect.DeepEqual(m.getKeys()[1], key) {
   469  		t.Fatalf("key doesn't exist")
   470  	}
   471  	if m.vals[1] != 3 {
   472  		t.Fatalf("bad val: %v", m.vals[1])
   473  	}
   474  
   475  	// Blocked by filter
   476  	key = []string{"debug", "other-thing"}
   477  	met.SetGauge(key, 4)
   478  	if len(m.getKeys()) != 2 {
   479  		t.Fatalf("key shouldn't exist")
   480  	}
   481  	// Test blacklisting of labels
   482  	key = []string{"debug", "thing"}
   483  	goodLabel := Label{Name: "good", Value: "should be present"}
   484  	badLabel := Label{Name: "bad_label", Value: "should not be there"}
   485  	labels := []Label{badLabel, goodLabel}
   486  	met.SetGaugeWithLabels(key, 3, labels)
   487  	if !reflect.DeepEqual(m.getKeys()[1], key) {
   488  		t.Fatalf("key doesn't exist")
   489  	}
   490  	if m.vals[2] != 3 {
   491  		t.Fatalf("bad val: %v", m.vals[1])
   492  	}
   493  	if HasElem(m.labels[2], badLabel) {
   494  		t.Fatalf("bad_label should not be present in %v", m.labels[2])
   495  	}
   496  	if !HasElem(m.labels[2], goodLabel) {
   497  		t.Fatalf("good label is not present in %v", m.labels[2])
   498  	}
   499  }
   500  
   501  func TestMetrics_Filter_Labels_Whitelist(t *testing.T) {
   502  	m := &MockSink{}
   503  	conf := DefaultConfig("")
   504  	conf.AllowedPrefixes = []string{"service", "debug.thing"}
   505  	conf.BlockedPrefixes = []string{"debug"}
   506  	conf.FilterDefault = false
   507  	conf.EnableHostname = false
   508  	conf.AllowedLabels = []string{"good_label"}
   509  	conf.BlockedLabels = []string{"bad_label"}
   510  	met, err := New(conf, m)
   511  	if err != nil {
   512  		t.Fatal(err)
   513  	}
   514  
   515  	// Blocked by default
   516  	key := []string{"thing"}
   517  	key = []string{"debug", "thing"}
   518  	goodLabel := Label{Name: "good_label", Value: "should be present"}
   519  	notReallyGoodLabel := Label{Name: "not_really_good_label", Value: "not whitelisted, but not blacklisted"}
   520  	badLabel := Label{Name: "bad_label", Value: "should not be there"}
   521  	labels := []Label{badLabel, notReallyGoodLabel, goodLabel}
   522  	met.SetGaugeWithLabels(key, 1, labels)
   523  
   524  	if HasElem(m.labels[0], badLabel) {
   525  		t.Fatalf("bad_label should not be present in %v", m.labels[0])
   526  	}
   527  	if HasElem(m.labels[0], notReallyGoodLabel) {
   528  		t.Fatalf("not_really_good_label should not be present in %v", m.labels[0])
   529  	}
   530  	if !HasElem(m.labels[0], goodLabel) {
   531  		t.Fatalf("good label is not present in %v", m.labels[0])
   532  	}
   533  
   534  	conf.AllowedLabels = nil
   535  	met.UpdateFilterAndLabels(conf.AllowedPrefixes, conf.BlockedLabels, conf.AllowedLabels, conf.BlockedLabels)
   536  	met.SetGaugeWithLabels(key, 1, labels)
   537  
   538  	if HasElem(m.labels[1], badLabel) {
   539  		t.Fatalf("bad_label should not be present in %v", m.labels[1])
   540  	}
   541  	// Since no whitelist, not_really_good_label should be there
   542  	if !HasElem(m.labels[1], notReallyGoodLabel) {
   543  		t.Fatalf("not_really_good_label is not present in %v", m.labels[1])
   544  	}
   545  	if !HasElem(m.labels[1], goodLabel) {
   546  		t.Fatalf("good label is not present in %v", m.labels[1])
   547  	}
   548  }
   549  
   550  func TestMetrics_Filter_Labels_ModifyArgs(t *testing.T) {
   551  	m := &MockSink{}
   552  	conf := DefaultConfig("")
   553  	conf.FilterDefault = false
   554  	conf.EnableHostname = false
   555  	conf.AllowedLabels = []string{"keep"}
   556  	conf.BlockedLabels = []string{"delete"}
   557  	met, err := New(conf, m)
   558  	if err != nil {
   559  		t.Fatal(err)
   560  	}
   561  
   562  	// Blocked by default
   563  	key := []string{"thing"}
   564  	key = []string{"debug", "thing"}
   565  	goodLabel := Label{Name: "keep", Value: "should be kept"}
   566  	badLabel := Label{Name: "delete", Value: "should be deleted"}
   567  	argLabels := []Label{badLabel, goodLabel, badLabel, goodLabel, badLabel, goodLabel, badLabel}
   568  	origLabels := append([]Label{}, argLabels...)
   569  	met.SetGaugeWithLabels(key, 1, argLabels)
   570  
   571  	if !reflect.DeepEqual(argLabels, origLabels) {
   572  		t.Fatalf("SetGaugeWithLabels modified the input argument")
   573  	}
   574  }