github.com/blend/go-sdk@v1.20220411.3/statsd/client_test.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package statsd 9 10 import ( 11 "bytes" 12 "fmt" 13 "io" 14 "math/rand" 15 "strconv" 16 "strings" 17 "sync" 18 "testing" 19 "time" 20 21 "github.com/blend/go-sdk/assert" 22 "github.com/blend/go-sdk/stats" 23 ) 24 25 type noOpWriteCloser struct { 26 io.Writer 27 } 28 29 // Close is a no-op. 30 func (n noOpWriteCloser) Close() error { return nil } 31 32 func Test_Client_Options(t *testing.T) { 33 assert := assert.New(t) 34 35 c := new(Client) 36 assert.Empty(c.Addr) 37 assert.Nil(OptAddr("192.168.1.1:0")(c)) 38 assert.Equal("192.168.1.1:0", c.Addr) 39 40 assert.Zero(c.DialTimeout) 41 assert.Nil(OptDialTimeout(time.Second)(c)) 42 assert.Equal(time.Second, c.DialTimeout) 43 44 assert.Zero(c.MaxPacketSize) 45 assert.Nil(OptMaxPacketSize(1024)(c)) 46 assert.Equal(1024, c.MaxPacketSize) 47 48 assert.Zero(c.MaxBufferSize) 49 assert.Nil(OptMaxBufferSize(512)(c)) 50 assert.Equal(512, c.MaxBufferSize) 51 52 cfg := Config{ 53 Addr: "127.0.0.1:0", 54 DialTimeout: 500 * time.Millisecond, 55 MaxPacketSize: 1024, 56 MaxBufferSize: 64, 57 DefaultTags: map[string]string{ 58 "foo": "bar", 59 "env": "sandbox", 60 }, 61 SampleRate: 0.8, 62 } 63 64 configClient := new(Client) 65 assert.Nil(configClient.SampleProvider) 66 assert.Nil(OptConfig(cfg)(configClient)) 67 68 assert.Equal("127.0.0.1:0", configClient.Addr) 69 assert.Equal(500*time.Millisecond, configClient.DialTimeout) 70 assert.Equal(1024, configClient.MaxPacketSize) 71 assert.Equal(64, configClient.MaxBufferSize) 72 73 assert.Any(configClient.DefaultTags(), func(v interface{}) bool { return v.(string) == "foo:bar" }) 74 assert.Any(configClient.DefaultTags(), func(v interface{}) bool { return v.(string) == "env:sandbox" }) 75 76 assert.NotNil(configClient.SampleProvider) 77 78 c.SampleProvider = nil 79 assert.NotNil(OptSampleRate(-1)(c)) 80 assert.NotNil(OptSampleRate(1.01)(c)) 81 82 assert.Nil(OptSampleRate(1.0)(c)) 83 assert.Nil(c.SampleProvider) 84 85 assert.Nil(OptSampleRate(0.8)(c)) 86 assert.NotNil(c.SampleProvider) 87 } 88 89 func Test_Client_AddDefaultTag(t *testing.T) { 90 assert := assert.New(t) 91 92 c := new(Client) 93 assert.Empty(c.defaultTags) 94 c.AddDefaultTags(stats.Tag("foo", "bar")) 95 assert.Equal([]string{"foo:bar"}, c.defaultTags) 96 } 97 98 func Test_ClientCount_Sampling(t *testing.T) { 99 assert := assert.New(t) 100 101 buffer := new(bytes.Buffer) 102 103 client := &Client{ 104 SampleProvider: func() bool { 105 return rand.Float64() < 0.5 106 }, 107 conn: noOpWriteCloser{buffer}, 108 } 109 110 for x := 0; x < 512; x++ { 111 assert.Nil(client.Count("sampling test", int64(x))) 112 } 113 114 contents := strings.Split(buffer.String(), "\n") 115 assert.True(len(contents) > 200, len(contents)) 116 assert.True(len(contents) < 300, len(contents)) 117 } 118 119 func Test_ClientGauge_Sampling(t *testing.T) { 120 assert := assert.New(t) 121 122 buffer := new(bytes.Buffer) 123 124 client := &Client{ 125 SampleProvider: func() bool { 126 return rand.Float64() < 0.5 127 }, 128 conn: noOpWriteCloser{buffer}, 129 } 130 131 for x := 0; x < 512; x++ { 132 assert.Nil(client.Gauge("sampling test", float64(x))) 133 } 134 135 contents := strings.Split(buffer.String(), "\n") 136 assert.True(len(contents) > 200, len(contents)) 137 assert.True(len(contents) < 300, len(contents)) 138 } 139 140 func Test_ClientCount_Unbuffered(t *testing.T) { 141 assert := assert.New(t) 142 143 listener, err := NewUDPListener("127.0.0.1:0") 144 assert.Nil(err) 145 146 wg := sync.WaitGroup{} 147 wg.Add(10) 148 149 metrics := make(chan Metric, 10) 150 mock := &Server{ 151 Listener: listener, 152 Handler: func(ms ...Metric) { 153 defer wg.Done() 154 for _, m := range ms { 155 metrics <- m 156 } 157 }, 158 } 159 go func() { _ = mock.Start() }() 160 defer func() { _ = mock.Stop() }() 161 162 client, err := New( 163 OptAddr(mock.Listener.LocalAddr().String()), 164 OptMaxBufferSize(0), 165 ) 166 assert.Nil(err) 167 168 for x := 0; x < 10; x++ { 169 assert.Nil(client.Count(fmt.Sprintf("count%d", x), 10+int64(x), Tag("env", "dev"), Tag("role", "test"), Tag("index", strconv.Itoa(x)))) 170 } 171 172 wg.Wait() 173 assert.Len(metrics, 10) 174 175 m := <-metrics 176 assert.Equal("c", m.Type) 177 assert.Equal("count0", m.Name) 178 assert.Equal("10", m.Value) 179 assert.Equal([]string{"env:dev", "role:test", "index:0"}, m.Tags) 180 181 m = <-metrics 182 assert.Equal("c", m.Type) 183 assert.Equal("count1", m.Name) 184 assert.Equal("11", m.Value) 185 assert.Equal([]string{"env:dev", "role:test", "index:1"}, m.Tags) 186 } 187 188 func Test_ClientGauge_Unbuffered(t *testing.T) { 189 assert := assert.New(t) 190 191 listener, err := NewUDPListener("127.0.0.1:0") 192 assert.Nil(err) 193 194 wg := sync.WaitGroup{} 195 wg.Add(10) 196 197 metrics := make(chan Metric, 10) 198 mock := &Server{ 199 Listener: listener, 200 Handler: func(ms ...Metric) { 201 defer wg.Done() 202 for _, m := range ms { 203 metrics <- m 204 } 205 }, 206 } 207 go func() { _ = mock.Start() }() 208 defer func() { _ = mock.Stop() }() 209 210 client, err := New( 211 OptAddr(mock.Listener.LocalAddr().String()), 212 OptMaxBufferSize(0), 213 ) 214 assert.Nil(err) 215 216 for x := 0; x < 10; x++ { 217 assert.Nil(client.Gauge(fmt.Sprintf("gauge%d", x), 10+float64(x), Tag("env", "dev"), Tag("role", "test"), Tag("index", strconv.Itoa(x)))) 218 } 219 220 wg.Wait() 221 assert.Len(metrics, 10) 222 223 m := <-metrics 224 assert.Equal("g", m.Type) 225 assert.Equal("gauge0", m.Name) 226 assert.Equal("10", m.Value) 227 assert.Equal([]string{"env:dev", "role:test", "index:0"}, m.Tags) 228 229 m = <-metrics 230 assert.Equal("g", m.Type) 231 assert.Equal("gauge1", m.Name) 232 assert.Equal("11", m.Value) 233 assert.Equal([]string{"env:dev", "role:test", "index:1"}, m.Tags) 234 } 235 236 func Test_ClientCount_Buffered(t *testing.T) { 237 assert := assert.New(t) 238 239 listener, err := NewUDPListener("127.0.0.1:0") 240 assert.Nil(err) 241 242 wg := sync.WaitGroup{} 243 wg.Add(5) // 10/2 flushes 244 245 metrics := make(chan Metric, 10) 246 mock := &Server{ 247 Listener: listener, 248 Handler: func(ms ...Metric) { 249 defer wg.Done() 250 for _, m := range ms { 251 metrics <- m 252 } 253 }, 254 } 255 go func() { _ = mock.Start() }() 256 defer func() { _ = mock.Stop() }() 257 258 client, err := New( 259 OptAddr(mock.Listener.LocalAddr().String()), 260 OptMaxBufferSize(2), 261 ) 262 assert.Nil(err) 263 264 for x := 0; x < 10; x++ { 265 assert.Nil(client.Count(fmt.Sprintf("count%d", x), 10, Tag("env", "dev"), Tag("role", "test"), Tag("index", strconv.Itoa(x)))) 266 } 267 268 wg.Wait() 269 assert.Len(metrics, 10) 270 } 271 272 func Test_ClientGauge_Buffered(t *testing.T) { 273 assert := assert.New(t) 274 275 listener, err := NewUDPListener("127.0.0.1:0") 276 assert.Nil(err) 277 278 wg := sync.WaitGroup{} 279 wg.Add(5) 280 281 metrics := make(chan Metric, 10) 282 mock := &Server{ 283 Listener: listener, 284 Handler: func(ms ...Metric) { 285 defer wg.Done() 286 for _, m := range ms { 287 metrics <- m 288 } 289 }, 290 } 291 go func() { _ = mock.Start() }() 292 defer func() { _ = mock.Stop() }() 293 294 client, err := New( 295 OptAddr(mock.Listener.LocalAddr().String()), 296 OptMaxBufferSize(2), 297 ) 298 assert.Nil(err) 299 300 for x := 0; x < 10; x++ { 301 assert.Nil(client.Gauge(fmt.Sprintf("gauge%d", x), 10, Tag("env", "dev"), Tag("role", "test"), Tag("index", strconv.Itoa(x)))) 302 } 303 304 wg.Wait() 305 assert.Len(metrics, 10) 306 } 307 308 func Test_ClientTimeInMilliseconds_Buffered(t *testing.T) { 309 assert := assert.New(t) 310 311 listener, err := NewUDPListener("127.0.0.1:0") 312 assert.Nil(err) 313 314 wg := sync.WaitGroup{} 315 wg.Add(5) 316 317 metrics := make(chan Metric, 10) 318 mock := &Server{ 319 Listener: listener, 320 Handler: func(ms ...Metric) { 321 defer wg.Done() 322 for _, m := range ms { 323 metrics <- m 324 } 325 }, 326 } 327 go func() { _ = mock.Start() }() 328 defer func() { _ = mock.Stop() }() 329 330 client, err := New( 331 OptAddr(mock.Listener.LocalAddr().String()), 332 OptMaxBufferSize(2), 333 ) 334 assert.Nil(err) 335 336 for x := 0; x < 10; x++ { 337 assert.Nil(client.TimeInMilliseconds(fmt.Sprintf("time%d", x), 10*time.Millisecond, Tag("env", "dev"), Tag("role", "test"), Tag("index", strconv.Itoa(x)))) 338 } 339 340 wg.Wait() 341 assert.Len(metrics, 10) 342 } 343 344 func Test_ClientIncrement_Buffered(t *testing.T) { 345 assert := assert.New(t) 346 347 listener, err := NewUDPListener("127.0.0.1:0") 348 assert.Nil(err) 349 350 wg := sync.WaitGroup{} 351 wg.Add(5) 352 353 metrics := make(chan Metric, 10) 354 mock := &Server{ 355 Listener: listener, 356 Handler: func(ms ...Metric) { 357 defer wg.Done() 358 for _, m := range ms { 359 metrics <- m 360 } 361 }, 362 } 363 go func() { _ = mock.Start() }() 364 defer func() { _ = mock.Stop() }() 365 366 client, err := New( 367 OptAddr(mock.Listener.LocalAddr().String()), 368 OptMaxBufferSize(2), 369 ) 370 assert.Nil(err) 371 372 for x := 0; x < 10; x++ { 373 assert.Nil(client.Increment(fmt.Sprintf("increment%d", x), Tag("env", "dev"), Tag("role", "test"), Tag("index", strconv.Itoa(x)))) 374 } 375 376 wg.Wait() 377 assert.Len(metrics, 10) 378 379 m := <-metrics 380 381 assert.Equal(MetricTypeCount, m.Type) 382 assert.Equal("increment0", m.Name) 383 assert.Equal("1", m.Value) 384 assert.Equal([]string{"env:dev", "role:test", "index:0"}, m.Tags) 385 } 386 387 func Test_ClientHistogram_Buffered(t *testing.T) { 388 assert := assert.New(t) 389 390 listener, err := NewUDPListener("127.0.0.1:0") 391 assert.Nil(err) 392 393 wg := sync.WaitGroup{} 394 wg.Add(5) 395 396 metrics := make(chan Metric, 10) 397 mock := &Server{ 398 Listener: listener, 399 Handler: func(ms ...Metric) { 400 defer wg.Done() 401 for _, m := range ms { 402 metrics <- m 403 } 404 }, 405 } 406 go func() { _ = mock.Start() }() 407 defer func() { _ = mock.Stop() }() 408 409 client, err := New( 410 OptAddr(mock.Listener.LocalAddr().String()), 411 OptMaxBufferSize(2), 412 ) 413 assert.Nil(err) 414 415 for x := 0; x < 10; x++ { 416 assert.Nil(client.Histogram(fmt.Sprintf("histogram%d", x), float64(x), Tag("env", "dev"), Tag("role", "test"), Tag("index", strconv.Itoa(x)))) 417 } 418 419 wg.Wait() 420 assert.Len(metrics, 10) 421 422 m := <-metrics 423 424 assert.Equal(MetricTypeHistogram, m.Type) 425 assert.Equal("histogram0", m.Name) 426 assert.Equal("0", m.Value) 427 assert.Equal([]string{"env:dev", "role:test", "index:0"}, m.Tags) 428 }