github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/send/buffered_test.go (about)

     1  package send
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/mongodb/grip/level"
    11  	"github.com/mongodb/grip/message"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestBufferedSend(t *testing.T) {
    17  	ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
    18  	defer cancel()
    19  
    20  	newBufferedSender := func(interval time.Duration, size int) (*bufferedSender, *InternalSender, error) {
    21  		s, err := NewInternalLogger("buffs", LevelInfo{level.Debug, level.Debug})
    22  		if err != nil {
    23  			return nil, nil, err
    24  		}
    25  
    26  		bs, err := NewBufferedSender(ctx, s, BufferedSenderOptions{FlushInterval: interval, BufferSize: size})
    27  		return bs.(*bufferedSender), s, err
    28  	}
    29  
    30  	t.Run("RespectsPriority", func(t *testing.T) {
    31  		bs, s, err := newBufferedSender(time.Minute, 10)
    32  		defer bs.cancel()
    33  		require.NoError(t, err)
    34  
    35  		bs.Send(message.ConvertToComposer(level.Trace, fmt.Sprintf("should not send")))
    36  		assert.Empty(t, bs.buffer)
    37  		_, ok := s.GetMessageSafe()
    38  		assert.False(t, ok)
    39  	})
    40  	t.Run("FlushesAtCapactiy", func(t *testing.T) {
    41  		bs, s, err := newBufferedSender(time.Minute, 10)
    42  		defer bs.cancel()
    43  		require.NoError(t, err)
    44  
    45  		for i := 0; i < 12; i++ {
    46  			require.Len(t, bs.buffer, i%10)
    47  			bs.Send(message.ConvertToComposer(level.Debug, fmt.Sprintf("message %d", i+1)))
    48  		}
    49  		assert.Len(t, bs.buffer, 2)
    50  		msg, ok := s.GetMessageSafe()
    51  		require.True(t, ok)
    52  		msgs := strings.Split(msg.Message.String(), "\n")
    53  		assert.Len(t, msgs, 10)
    54  		for i, msg := range msgs {
    55  			require.Equal(t, fmt.Sprintf("message %d", i+1), msg)
    56  		}
    57  	})
    58  	t.Run("FlushesOnInterval", func(t *testing.T) {
    59  		bs, s, err := newBufferedSender(5*time.Second, 10)
    60  		defer bs.cancel()
    61  		require.NoError(t, err)
    62  
    63  		bs.Send(message.ConvertToComposer(level.Debug, "should flush"))
    64  		time.Sleep(6 * time.Second)
    65  		bs.mu.Lock()
    66  		assert.True(t, time.Since(bs.lastFlush) <= 2*time.Second)
    67  		bs.mu.Unlock()
    68  		msg, ok := s.GetMessageSafe()
    69  		require.True(t, ok)
    70  		assert.Equal(t, "should flush", msg.Message.String())
    71  	})
    72  	t.Run("ClosedSender", func(t *testing.T) {
    73  		bs, s, err := newBufferedSender(time.Minute, 10)
    74  		defer bs.cancel()
    75  		require.NoError(t, err)
    76  
    77  		bs.closed = true
    78  		bs.Send(message.ConvertToComposer(level.Debug, "should not send"))
    79  		assert.Empty(t, bs.buffer)
    80  		_, ok := s.GetMessageSafe()
    81  		assert.False(t, ok)
    82  	})
    83  	t.Run("ForceFlush", func(t *testing.T) {
    84  		bs, s, err := newBufferedSender(time.Minute, 10)
    85  		defer bs.cancel()
    86  		require.NoError(t, err)
    87  
    88  		bs.Send(message.ConvertToComposer(level.Debug, "message"))
    89  		assert.Len(t, bs.buffer, 1)
    90  		require.NoError(t, bs.Flush(context.TODO()))
    91  		bs.mu.Lock()
    92  		assert.True(t, time.Since(bs.lastFlush) <= time.Second)
    93  		bs.mu.Unlock()
    94  		assert.Empty(t, bs.buffer)
    95  		msg, ok := s.GetMessageSafe()
    96  		require.True(t, ok)
    97  		assert.Equal(t, "message", msg.Message.String())
    98  	})
    99  	t.Run("ClosedSender", func(t *testing.T) {
   100  		bs, s, err := newBufferedSender(time.Minute, 10)
   101  		defer bs.cancel()
   102  		require.NoError(t, err)
   103  
   104  		bs.buffer = append(bs.buffer, message.ConvertToComposer(level.Debug, "message"))
   105  		bs.cancel()
   106  		bs.closed = true
   107  
   108  		assert.NoError(t, bs.Flush(context.TODO()))
   109  		assert.Len(t, bs.buffer, 1)
   110  		_, ok := s.GetMessageSafe()
   111  		assert.False(t, ok)
   112  	})
   113  	t.Run("EmptyBuffer", func(t *testing.T) {
   114  		bs, s, err := newBufferedSender(time.Minute, 10)
   115  		defer bs.cancel()
   116  		require.NoError(t, err)
   117  
   118  		assert.Nil(t, bs.Close())
   119  		assert.True(t, bs.closed)
   120  		_, ok := s.GetMessageSafe()
   121  		assert.False(t, ok)
   122  	})
   123  	t.Run("NonEmptyBuffer", func(t *testing.T) {
   124  		bs, s, err := newBufferedSender(time.Minute, 10)
   125  		defer bs.cancel()
   126  		require.NoError(t, err)
   127  
   128  		bs.buffer = append(
   129  			bs.buffer,
   130  			message.ConvertToComposer(level.Debug, "message1"),
   131  			message.ConvertToComposer(level.Debug, "message2"),
   132  			message.ConvertToComposer(level.Debug, "message3"),
   133  		)
   134  
   135  		assert.Nil(t, bs.Close())
   136  		assert.True(t, bs.closed)
   137  		assert.Empty(t, bs.buffer)
   138  		msgs, ok := s.GetMessageSafe()
   139  		require.True(t, ok)
   140  		assert.Equal(t, "message1\nmessage2\nmessage3", msgs.Message.String())
   141  	})
   142  	t.Run("NoopWhenClosed", func(t *testing.T) {
   143  		bs, _, err := newBufferedSender(time.Minute, 10)
   144  		defer bs.cancel()
   145  		require.NoError(t, err)
   146  
   147  		assert.NoError(t, bs.Close())
   148  		assert.True(t, bs.closed)
   149  		assert.NoError(t, bs.Close())
   150  	})
   151  }
   152  
   153  func TestIntervalFlush(t *testing.T) {
   154  	s, err := NewInternalLogger("buffs", LevelInfo{level.Debug, level.Debug})
   155  	require.NoError(t, err)
   156  
   157  	t.Run("ReturnsWhenClosed", func(t *testing.T) {
   158  		ctx, cancel := context.WithCancel(context.Background())
   159  		bs := &bufferedSender{
   160  			Sender: s,
   161  			buffer: []message.Composer{},
   162  			cancel: cancel,
   163  		}
   164  		canceled := make(chan bool)
   165  
   166  		go func() {
   167  			bs.intervalFlush(ctx, time.Minute)
   168  			canceled <- true
   169  		}()
   170  		assert.NoError(t, bs.Close())
   171  		assert.True(t, <-canceled)
   172  	})
   173  }