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

     1  package metrics
     2  
     3  import (
     4  	"io/ioutil"
     5  	"log"
     6  	"reflect"
     7  	"sync/atomic"
     8  	"testing"
     9  	"time"
    10  )
    11  
    12  func TestDefaultConfig(t *testing.T) {
    13  	conf := DefaultConfig("service")
    14  	if conf.ServiceName != "service" {
    15  		t.Fatalf("Bad name")
    16  	}
    17  	if conf.HostName == "" {
    18  		t.Fatalf("missing hostname")
    19  	}
    20  	if !conf.EnableHostname || !conf.EnableRuntimeMetrics {
    21  		t.Fatalf("expect true")
    22  	}
    23  	if conf.EnableTypePrefix {
    24  		t.Fatalf("expect false")
    25  	}
    26  	if conf.TimerGranularity != time.Millisecond {
    27  		t.Fatalf("bad granularity")
    28  	}
    29  	if conf.ProfileInterval != time.Second {
    30  		t.Fatalf("bad interval")
    31  	}
    32  }
    33  
    34  func Test_GlobalMetrics(t *testing.T) {
    35  	var tests = []struct {
    36  		desc string
    37  		key  []string
    38  		val  float32
    39  		fn   func([]string, float32)
    40  	}{
    41  		{"SetGauge", []string{"test"}, 42, SetGauge},
    42  		{"EmitKey", []string{"test"}, 42, EmitKey},
    43  		{"IncrCounter", []string{"test"}, 42, IncrCounter},
    44  		{"AddSample", []string{"test"}, 42, AddSample},
    45  	}
    46  
    47  	for _, tt := range tests {
    48  		t.Run(tt.desc, func(t *testing.T) {
    49  			s := &MockSink{}
    50  			globalMetrics.Store(&Metrics{Config: Config{FilterDefault: true}, sink: s})
    51  			tt.fn(tt.key, tt.val)
    52  			if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) {
    53  				t.Fatalf("got key %s want %s", got, want)
    54  			}
    55  			if got, want := s.vals[0], tt.val; !reflect.DeepEqual(got, want) {
    56  				t.Fatalf("got val %v want %v", got, want)
    57  			}
    58  		})
    59  	}
    60  }
    61  
    62  func Test_GlobalMetrics_Labels(t *testing.T) {
    63  	labels := []Label{{"a", "b"}}
    64  	var tests = []struct {
    65  		desc   string
    66  		key    []string
    67  		val    float32
    68  		fn     func([]string, float32, []Label)
    69  		labels []Label
    70  	}{
    71  		{"SetGaugeWithLabels", []string{"test"}, 42, SetGaugeWithLabels, labels},
    72  		{"IncrCounterWithLabels", []string{"test"}, 42, IncrCounterWithLabels, labels},
    73  		{"AddSampleWithLabels", []string{"test"}, 42, AddSampleWithLabels, labels},
    74  	}
    75  
    76  	for _, tt := range tests {
    77  		t.Run(tt.desc, func(t *testing.T) {
    78  			s := &MockSink{}
    79  			globalMetrics.Store(&Metrics{Config: Config{FilterDefault: true}, sink: s})
    80  			tt.fn(tt.key, tt.val, tt.labels)
    81  			if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) {
    82  				t.Fatalf("got key %s want %s", got, want)
    83  			}
    84  			if got, want := s.vals[0], tt.val; !reflect.DeepEqual(got, want) {
    85  				t.Fatalf("got val %v want %v", got, want)
    86  			}
    87  			if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) {
    88  				t.Fatalf("got val %s want %s", got, want)
    89  			}
    90  		})
    91  	}
    92  }
    93  
    94  func Test_GlobalPrecisionMetrics_Labels(t *testing.T) {
    95  	labels := []Label{{"a", "b"}}
    96  	var tests = []struct {
    97  		desc   string
    98  		key    []string
    99  		val    float64
   100  		fn     func([]string, float64, []Label)
   101  		labels []Label
   102  	}{
   103  		{"SetPrecisionGaugeWithLabels", []string{"test"}, 42, SetPrecisionGaugeWithLabels, labels},
   104  	}
   105  
   106  	for _, tt := range tests {
   107  		t.Run(tt.desc, func(t *testing.T) {
   108  			s := &MockSink{}
   109  			globalMetrics.Store(&Metrics{Config: Config{FilterDefault: true}, sink: s})
   110  			tt.fn(tt.key, tt.val, tt.labels)
   111  			if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) {
   112  				t.Fatalf("got key %s want %s", got, want)
   113  			}
   114  			if got, want := s.precisionVals[0], tt.val; !reflect.DeepEqual(got, want) {
   115  				t.Fatalf("got val %v want %v", got, want)
   116  			}
   117  			if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) {
   118  				t.Fatalf("got val %s want %s", got, want)
   119  			}
   120  		})
   121  	}
   122  }
   123  
   124  func Test_GlobalMetrics_DefaultLabels(t *testing.T) {
   125  	config := Config{
   126  		HostName:            "host1",
   127  		ServiceName:         "redis",
   128  		EnableHostnameLabel: true,
   129  		EnableServiceLabel:  true,
   130  		FilterDefault:       true,
   131  	}
   132  	labels := []Label{
   133  		{"host", config.HostName},
   134  		{"service", config.ServiceName},
   135  	}
   136  	var tests = []struct {
   137  		desc   string
   138  		key    []string
   139  		val    float32
   140  		fn     func([]string, float32, []Label)
   141  		labels []Label
   142  	}{
   143  		{"SetGaugeWithLabels", []string{"test"}, 42, SetGaugeWithLabels, labels},
   144  		{"IncrCounterWithLabels", []string{"test"}, 42, IncrCounterWithLabels, labels},
   145  		{"AddSampleWithLabels", []string{"test"}, 42, AddSampleWithLabels, labels},
   146  	}
   147  
   148  	for _, tt := range tests {
   149  		t.Run(tt.desc, func(t *testing.T) {
   150  			s := &MockSink{}
   151  			globalMetrics.Store(&Metrics{Config: config, sink: s})
   152  			tt.fn(tt.key, tt.val, nil)
   153  			if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) {
   154  				t.Fatalf("got key %s want %s", got, want)
   155  			}
   156  			if got, want := s.vals[0], tt.val; !reflect.DeepEqual(got, want) {
   157  				t.Fatalf("got val %v want %v", got, want)
   158  			}
   159  			if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) {
   160  				t.Fatalf("got val %s want %s", got, want)
   161  			}
   162  		})
   163  	}
   164  }
   165  
   166  func Test_GlobalPrecisionMetrics_DefaultLabels(t *testing.T) {
   167  	config := Config{
   168  		HostName:            "host1",
   169  		ServiceName:         "redis",
   170  		EnableHostnameLabel: true,
   171  		EnableServiceLabel:  true,
   172  		FilterDefault:       true,
   173  	}
   174  	labels := []Label{
   175  		{"host", config.HostName},
   176  		{"service", config.ServiceName},
   177  	}
   178  	var tests = []struct {
   179  		desc   string
   180  		key    []string
   181  		val    float64
   182  		fn     func([]string, float64, []Label)
   183  		labels []Label
   184  	}{
   185  		{"SetGaugeWithLabels", []string{"test"}, 42, SetPrecisionGaugeWithLabels, labels},
   186  	}
   187  
   188  	for _, tt := range tests {
   189  		t.Run(tt.desc, func(t *testing.T) {
   190  			s := &MockSink{}
   191  			globalMetrics.Store(&Metrics{Config: config, sink: s})
   192  			tt.fn(tt.key, tt.val, nil)
   193  			if got, want := s.keys[0], tt.key; !reflect.DeepEqual(got, want) {
   194  				t.Fatalf("got key %s want %s", got, want)
   195  			}
   196  			if got, want := s.precisionVals[0], tt.val; !reflect.DeepEqual(got, want) {
   197  				t.Fatalf("got val %v want %v", got, want)
   198  			}
   199  			if got, want := s.labels[0], tt.labels; !reflect.DeepEqual(got, want) {
   200  				t.Fatalf("got val %s want %s", got, want)
   201  			}
   202  		})
   203  	}
   204  }
   205  
   206  func Test_GlobalMetrics_MeasureSince(t *testing.T) {
   207  	s := &MockSink{}
   208  	m := &Metrics{sink: s, Config: Config{TimerGranularity: time.Millisecond, FilterDefault: true}}
   209  	globalMetrics.Store(m)
   210  
   211  	k := []string{"test"}
   212  	now := time.Now()
   213  	MeasureSince(k, now)
   214  
   215  	if !reflect.DeepEqual(s.keys[0], k) {
   216  		t.Fatalf("key not equal")
   217  	}
   218  	if s.vals[0] > 0.1 {
   219  		t.Fatalf("val too large %v", s.vals[0])
   220  	}
   221  
   222  	labels := []Label{{"a", "b"}}
   223  	MeasureSinceWithLabels(k, now, labels)
   224  	if got, want := s.keys[1], k; !reflect.DeepEqual(got, want) {
   225  		t.Fatalf("got key %s want %s", got, want)
   226  	}
   227  	if s.vals[1] > 0.1 {
   228  		t.Fatalf("val too large %v", s.vals[0])
   229  	}
   230  	if got, want := s.labels[1], labels; !reflect.DeepEqual(got, want) {
   231  		t.Fatalf("got val %s want %s", got, want)
   232  	}
   233  }
   234  
   235  func Test_GlobalMetrics_UpdateFilter(t *testing.T) {
   236  	globalMetrics.Store(&Metrics{Config: Config{
   237  		AllowedPrefixes: []string{"a"},
   238  		BlockedPrefixes: []string{"b"},
   239  		AllowedLabels:   []string{"1"},
   240  		BlockedLabels:   []string{"2"},
   241  	}})
   242  	UpdateFilterAndLabels([]string{"c"}, []string{"d"}, []string{"3"}, []string{"4"})
   243  
   244  	m := globalMetrics.Load().(*Metrics)
   245  	if m.AllowedPrefixes[0] != "c" {
   246  		t.Fatalf("bad: %v", m.AllowedPrefixes)
   247  	}
   248  	if m.BlockedPrefixes[0] != "d" {
   249  		t.Fatalf("bad: %v", m.BlockedPrefixes)
   250  	}
   251  	if m.AllowedLabels[0] != "3" {
   252  		t.Fatalf("bad: %v", m.AllowedPrefixes)
   253  	}
   254  	if m.BlockedLabels[0] != "4" {
   255  		t.Fatalf("bad: %v", m.AllowedPrefixes)
   256  	}
   257  	if _, ok := m.allowedLabels["3"]; !ok {
   258  		t.Fatalf("bad: %v", m.allowedLabels)
   259  	}
   260  	if _, ok := m.blockedLabels["4"]; !ok {
   261  		t.Fatalf("bad: %v", m.blockedLabels)
   262  	}
   263  }
   264  
   265  func Test_GlobalMetrics_Shutdown(t *testing.T) {
   266  	s := &MockSink{}
   267  	m := &Metrics{sink: s}
   268  	globalMetrics.Store(m)
   269  
   270  	Shutdown()
   271  
   272  	loaded := globalMetrics.Load()
   273  	metrics, ok := loaded.(*Metrics)
   274  	if !ok {
   275  		t.Fatalf("Expected globalMetrics to contain a Metrics pointer, but found: %v", loaded)
   276  	}
   277  	if metrics == m {
   278  		t.Errorf("Calling shutdown should have replaced the Metrics struct stored in globalMetrics")
   279  	}
   280  	if !s.shutdown {
   281  		t.Errorf("Expected Shutdown to have been called on MockSink")
   282  	}
   283  }
   284  
   285  // Benchmark_GlobalMetrics_Direct/direct-8         	 5000000	       278 ns/op
   286  // Benchmark_GlobalMetrics_Direct/atomic.Value-8   	 5000000	       235 ns/op
   287  func Benchmark_GlobalMetrics_Direct(b *testing.B) {
   288  	log.SetOutput(ioutil.Discard)
   289  	s := &MockSink{}
   290  	m := &Metrics{sink: s}
   291  	var v atomic.Value
   292  	v.Store(m)
   293  	k := []string{"test"}
   294  	b.Run("direct", func(b *testing.B) {
   295  		for i := 0; i < b.N; i++ {
   296  			m.IncrCounter(k, 1)
   297  		}
   298  	})
   299  	b.Run("atomic.Value", func(b *testing.B) {
   300  		for i := 0; i < b.N; i++ {
   301  			v.Load().(*Metrics).IncrCounter(k, 1)
   302  		}
   303  	})
   304  	// do something with m so that the compiler does not optimize this away
   305  	b.Logf("%d", m.lastNumGC)
   306  }