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  }