github.com/grafana/pyroscope@v1.18.0/pkg/usagestats/stats_test.go (about) 1 package usagestats 2 3 import ( 4 "runtime" 5 "sync" 6 "testing" 7 "time" 8 9 "github.com/google/uuid" 10 jsoniter "github.com/json-iterator/go" 11 "github.com/stretchr/testify/require" 12 13 "github.com/grafana/pyroscope/pkg/util/build" 14 ) 15 16 func Test_BuildReport(t *testing.T) { 17 now := time.Now() 18 seed := ClusterSeed{ 19 UID: uuid.New().String(), 20 CreatedAt: now, 21 } 22 23 Edition("non-OSS") 24 Edition("OSS") 25 Target("distributor") 26 Target("compactor") 27 NewString("compression").Set("snappy") 28 NewString("compression").Set("lz4") 29 NewInt("compression_ratio").Set(50) 30 NewInt("compression_ratio").Set(100) 31 NewFloat("size_mb").Set(100.1) 32 NewFloat("size_mb").Set(200.1) 33 NewCounter("lines_written").Inc(200) 34 s := NewStatistics("query_throughput") 35 s.Record(25) 36 s = NewStatistics("query_throughput") 37 s.Record(300) 38 s.Record(5) 39 w := NewWordCounter("active_tenants") 40 w.Add("buz") 41 w = NewWordCounter("active_tenants") 42 w.Add("foo") 43 w.Add("bar") 44 w.Add("foo") 45 46 r := buildReport(seed, now.Add(time.Hour)) 47 require.Equal(t, r.Arch, runtime.GOARCH) 48 require.Equal(t, r.Os, runtime.GOOS) 49 require.Equal(t, r.PrometheusVersion, build.GetVersion()) 50 require.Equal(t, r.Edition, "OSS") 51 require.Equal(t, r.Target, "compactor") 52 require.Equal(t, r.Metrics["num_cpu"], runtime.NumCPU()) 53 // Don't check num_goroutine because it could have changed since the report was created. 54 require.Equal(t, r.Metrics["compression"], "lz4") 55 require.Equal(t, r.Metrics["compression_ratio"], int64(100)) 56 require.Equal(t, r.Metrics["size_mb"], 200.1) 57 require.Equal(t, r.Metrics["lines_written"].(map[string]interface{})["total"], int64(200)) 58 require.Equal(t, r.Metrics["query_throughput"].(map[string]interface{})["min"], float64(5)) 59 require.Equal(t, r.Metrics["query_throughput"].(map[string]interface{})["max"], float64(300)) 60 require.Equal(t, r.Metrics["query_throughput"].(map[string]interface{})["count"], int64(3)) 61 require.Equal(t, r.Metrics["query_throughput"].(map[string]interface{})["avg"], float64(25+300+5)/3) 62 require.Equal(t, r.Metrics["active_tenants"], int64(3)) 63 64 out, _ := jsoniter.MarshalIndent(r, "", " ") 65 t.Log(string(out)) 66 } 67 68 func TestCounter(t *testing.T) { 69 c := NewCounter("test_counter") 70 c.Inc(100) 71 c.Inc(200) 72 c.Inc(300) 73 time.Sleep(1 * time.Second) 74 c.updateRate() 75 v := c.Value() 76 require.Equal(t, int64(600), v["total"]) 77 require.GreaterOrEqual(t, v["rate"], float64(590)) 78 c.reset() 79 require.Equal(t, int64(0), c.Value()["total"]) 80 require.Equal(t, float64(0), c.Value()["rate"]) 81 } 82 83 func TestStatistic(t *testing.T) { 84 s := NewStatistics("test_stats") 85 s.Record(100) 86 s.Record(200) 87 s.Record(300) 88 v := s.Value() 89 require.Equal(t, float64(100), v["min"]) 90 require.Equal(t, float64(300), v["max"]) 91 require.Equal(t, int64(3), v["count"]) 92 require.Equal(t, float64(100+200+300)/3, v["avg"]) 93 require.Equal(t, float64(81.64965809277261), v["stddev"]) 94 require.Equal(t, float64(6666.666666666667), v["stdvar"]) 95 } 96 97 func TestWordCounter(t *testing.T) { 98 w := NewWordCounter("test_words_count") 99 var wg sync.WaitGroup 100 for i := 0; i < 100; i++ { 101 wg.Add(1) 102 go func() { 103 defer wg.Done() 104 w.Add("foo") 105 w.Add("bar") 106 w.Add("foo") 107 }() 108 } 109 wg.Wait() 110 require.Equal(t, int64(2), w.Value()) 111 } 112 113 func TestMultiCounter(t *testing.T) { 114 mc := NewMultiCounter("test_multi_counter", "key_name") 115 mc.Inc(100, "key_value_a") 116 mc.Inc(200, "key_value_b") 117 mc.Inc(300, "key_value_a") 118 time.Sleep(1 * time.Second) 119 mc.updateRate() 120 v := mc.Value() 121 require.Equal(t, int64(600), v["total"]) 122 require.GreaterOrEqual(t, v["rate"], float64(590)) 123 124 drilldown := v["drilldown"].([]interface{}) 125 require.Equal(t, 2, len(drilldown)) 126 for _, entry := range drilldown { 127 entryMap := entry.(map[string]interface{}) 128 data := entryMap["data"].(map[string]interface{}) 129 switch entryMap["key_name"] { 130 case "key_value_a": 131 require.Equal(t, int64(400), data["total"]) 132 case "key_value_b": 133 require.Equal(t, int64(200), data["total"]) 134 default: 135 t.FailNow() 136 } 137 } 138 139 mc.reset() 140 require.Equal(t, int64(0), mc.Value()["total"]) 141 require.Equal(t, float64(0), mc.Value()["rate"]) 142 } 143 144 func TestMultiStatistic(t *testing.T) { 145 ms := NewMultiStatistics("test_multi_stats", "key_name") 146 ms.Record(100, "key_value_a") 147 ms.Record(200, "key_value_b") 148 ms.Record(300, "key_value_a") 149 v := ms.Value() 150 require.Equal(t, float64(100), v["min"]) 151 require.Equal(t, float64(300), v["max"]) 152 require.Equal(t, int64(3), v["count"]) 153 require.Equal(t, float64(200), v["avg"]) 154 require.Equal(t, float64(81.64965809277261), v["stddev"]) 155 require.Equal(t, float64(6666.666666666667), v["stdvar"]) 156 157 drilldown := v["drilldown"].([]interface{}) 158 require.Equal(t, 2, len(drilldown)) 159 for _, entry := range drilldown { 160 entryMap := entry.(map[string]interface{}) 161 data := entryMap["data"].(map[string]interface{}) 162 switch entryMap["key_name"] { 163 case "key_value_a": 164 require.Equal(t, float64(100), data["min"]) 165 require.Equal(t, float64(300), data["max"]) 166 require.Equal(t, int64(2), data["count"]) 167 require.Equal(t, float64(200), data["avg"]) 168 require.Equal(t, float64(100), data["stddev"]) 169 require.Equal(t, float64(10000), data["stdvar"]) 170 case "key_value_b": 171 require.Equal(t, float64(200), data["min"]) 172 require.Equal(t, float64(200), data["max"]) 173 require.Equal(t, int64(1), data["count"]) 174 require.Equal(t, float64(200), data["avg"]) 175 require.Equal(t, float64(0), data["stddev"]) 176 require.Equal(t, float64(0), data["stdvar"]) 177 default: 178 t.FailNow() 179 } 180 } 181 } 182 183 func TestPanics(t *testing.T) { 184 require.Panics(t, func() { 185 NewStatistics("panicstats") 186 NewWordCounter("panicstats") 187 }) 188 189 require.Panics(t, func() { 190 NewWordCounter("panicwordcounter") 191 NewCounter("panicwordcounter") 192 }) 193 194 require.Panics(t, func() { 195 NewCounter("paniccounter") 196 NewStatistics("paniccounter") 197 }) 198 199 require.Panics(t, func() { 200 NewFloat("panicfloat") 201 NewInt("panicfloat") 202 }) 203 204 require.Panics(t, func() { 205 NewInt("panicint") 206 NewString("panicint") 207 }) 208 209 require.Panics(t, func() { 210 NewString("panicstring") 211 NewFloat("panicstring") 212 }) 213 214 require.Panics(t, func() { 215 NewFloat(targetKey) 216 Target("new target") 217 }) 218 219 require.Panics(t, func() { 220 NewFloat(editionKey) 221 Edition("new edition") 222 }) 223 }