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 }