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 }