github.com/rudderlabs/rudder-go-kit@v0.30.0/stats/metric/registry_test.go (about)

     1  package metric
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  type testMeasurement struct {
    12  	name string
    13  	tag  string
    14  }
    15  
    16  func (r testMeasurement) GetName() string {
    17  	return r.name
    18  }
    19  
    20  func (r testMeasurement) GetTags() map[string]string {
    21  	return map[string]string{"tag": r.tag}
    22  }
    23  
    24  func TestRegistryGet(t *testing.T) {
    25  	registry := NewRegistry()
    26  
    27  	counterKey := testMeasurement{name: "key1"}
    28  	counter := registry.MustGetCounter(counterKey)
    29  	counter.Inc()
    30  	otherCounter := registry.MustGetCounter(counterKey)
    31  	// otherCounter should be the same counter, since we are using the same key
    32  	if expected, got := counter.Value(), otherCounter.Value(); expected != got {
    33  		t.Errorf("Expected %f, got %f.", expected, got)
    34  	}
    35  
    36  	gaugeKey := testMeasurement{name: "key2"}
    37  	gauge := registry.MustGetCounter(gaugeKey)
    38  	gauge.Inc()
    39  	otherGauge := registry.MustGetCounter(gaugeKey)
    40  	// otherGauge should be the same gauge, since we are using the same key
    41  	if expected, got := gauge.Value(), otherGauge.Value(); expected != got {
    42  		t.Errorf("Expected %f, got %f.", expected, got)
    43  	}
    44  
    45  	// trying to get a gauge using the counter's key should result in an error
    46  	if g, err := registry.GetGauge(counterKey); err == nil {
    47  		t.Errorf("Expected an error, got %T", g)
    48  	}
    49  
    50  	if expected, got := `a different type of metric exists in the registry with the same key [{name:key1 tag:}]: *metric.counter`, mustGetGauge(registry, counterKey).Error(); expected != got {
    51  		t.Errorf("Expected error %q, got %q.", expected, got)
    52  	}
    53  
    54  	smaKey := testMeasurement{name: "key3"}
    55  	sma := registry.MustGetSimpleMovingAvg(smaKey)
    56  	sma.Add(1)
    57  	otherSma := registry.MustGetSimpleMovingAvg(smaKey)
    58  	// otherSma should be the same ma, since we are using the same key
    59  	if expected, got := sma.Value(), otherSma.Value(); expected != got {
    60  		t.Errorf("Expected %f, got %f.", expected, got)
    61  	}
    62  
    63  	vma10Key := testMeasurement{name: "key4"}
    64  	vma10 := registry.MustGetVarMovingAvg(vma10Key, 10)
    65  	vma10.Add(1)
    66  	otherVma10 := registry.MustGetVarMovingAvg(vma10Key, 10)
    67  	// otherVma10 should be the same vma10, since we are using the same key
    68  	if expected, got := vma10.Value(), otherVma10.Value(); expected != got {
    69  		t.Errorf("Expected %f, got %f.", expected, got)
    70  	}
    71  
    72  	// trying to get a vma of different age using a key that corresponds to another age should result in an error
    73  	if g, err := registry.GetVarMovingAvg(vma10Key, 20); err == nil {
    74  		t.Errorf("Expected an error, got %T", g)
    75  	}
    76  
    77  	if expected, got := `another moving average with age 12.000000 instead of 20.000000 exists in the registry with the same key [{name:key4 tag:}]: *metric.VariableEWMA`, mustGetVMA(registry, vma10Key, 20).Error(); expected != got {
    78  		t.Errorf("Expected error %q, got %q.", expected, got)
    79  	}
    80  }
    81  
    82  func TestRegistryNameIndex(t *testing.T) {
    83  	registry := NewRegistry()
    84  	m1 := testMeasurement{name: "key1", tag: "tag1"}
    85  	m2 := testMeasurement{name: "key1", tag: "tag2"}
    86  	m3 := testMeasurement{name: "key2", tag: "tag1"}
    87  	registry.MustGetCounter(m1).Inc()
    88  	registry.MustGetCounter(m2).Add(2)
    89  	registry.MustGetCounter(m3).Add(3)
    90  
    91  	metrics := registry.GetMetricsByName("key1")
    92  
    93  	require.Equal(t, 2, len(metrics), "should receive 2 metrics")
    94  	res := map[string]float64{}
    95  	res[metrics[0].Tags["tag"]] = metrics[0].Value.(Counter).Value()
    96  	res[metrics[1].Tags["tag"]] = metrics[1].Value.(Counter).Value()
    97  
    98  	require.Equal(t, res, map[string]float64{"tag1": 1.0, "tag2": 2.0})
    99  }
   100  
   101  func TestRegistryGetConcurrently(t *testing.T) {
   102  	const concurrency = 1000
   103  	registry := NewRegistry()
   104  	key := testMeasurement{name: "key"}
   105  	var wg sync.WaitGroup
   106  	wg.Add(concurrency)
   107  	for i := 0; i < concurrency; i++ {
   108  		go func() {
   109  			registry.MustGetCounter(key).Inc()
   110  			wg.Done()
   111  		}()
   112  	}
   113  	wg.Wait()
   114  	if expected, got := float64(concurrency), registry.MustGetCounter(key).Value(); expected != got {
   115  		t.Errorf("Expected %f, got %f.", expected, got)
   116  	}
   117  }
   118  
   119  func mustGetGauge(registry Registry, key Measurement) (err error) {
   120  	defer func() {
   121  		if e := recover(); e != nil {
   122  			err = e.(error)
   123  		}
   124  	}()
   125  	registry.MustGetGauge(key)
   126  	return errors.New("")
   127  }
   128  
   129  func mustGetVMA(registry Registry, key Measurement, age float64) (err error) {
   130  	defer func() {
   131  		if e := recover(); e != nil {
   132  			err = e.(error)
   133  		}
   134  	}()
   135  	registry.MustGetVarMovingAvg(key, age)
   136  	return errors.New("")
   137  }
   138  
   139  func BenchmarkRegistryGetCounterAndInc1(b *testing.B) {
   140  	benchmarkRegistryGetCounterAndInc(b, 1)
   141  }
   142  
   143  func BenchmarkRegistryGetCounterAndInc10(b *testing.B) {
   144  	benchmarkRegistryGetCounterAndInc(b, 10)
   145  }
   146  
   147  func BenchmarkRegistryGetCounterAndInc100(b *testing.B) {
   148  	benchmarkRegistryGetCounterAndInc(b, 100)
   149  }
   150  
   151  func benchmarkRegistryGetCounterAndInc(b *testing.B, concurrency int) {
   152  	b.StopTimer()
   153  	var start, end sync.WaitGroup
   154  	start.Add(1)
   155  	n := b.N / concurrency
   156  	registry := NewRegistry()
   157  	key := testMeasurement{name: "key"}
   158  	end.Add(concurrency)
   159  	for i := 0; i < concurrency; i++ {
   160  		go func() {
   161  			start.Wait()
   162  			for i := 0; i < n; i++ {
   163  				counter := registry.MustGetCounter(key)
   164  				counter.Inc()
   165  			}
   166  			end.Done()
   167  		}()
   168  	}
   169  
   170  	b.StartTimer()
   171  	start.Done()
   172  	end.Wait()
   173  }
   174  
   175  func BenchmarkMutexMapGetIntAndInc1(b *testing.B) {
   176  	benchmarkMutexMapGetIntAndInc(b, 1)
   177  }
   178  
   179  func BenchmarkMutexMapGetIntAndInc10(b *testing.B) {
   180  	benchmarkMutexMapGetIntAndInc(b, 10)
   181  }
   182  
   183  func BenchmarkMutexMapGetIntAndInc100(b *testing.B) {
   184  	benchmarkMutexMapGetIntAndInc(b, 100)
   185  }
   186  
   187  func benchmarkMutexMapGetIntAndInc(b *testing.B, concurrency int) {
   188  	b.StopTimer()
   189  	var mutex sync.RWMutex
   190  	var start, end sync.WaitGroup
   191  	start.Add(1)
   192  	n := b.N / concurrency
   193  	registry := map[string]int{"key": 0}
   194  	end.Add(concurrency)
   195  	for i := 0; i < concurrency; i++ {
   196  		go func() {
   197  			for i := 0; i < n; i++ {
   198  				mutex.Lock()
   199  				registry["key"] += 1
   200  				mutex.Unlock()
   201  			}
   202  			end.Done()
   203  		}()
   204  	}
   205  
   206  	b.StartTimer()
   207  	start.Done()
   208  	end.Wait()
   209  }