github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/logger/ring_test.go (about) 1 package logger // import "github.com/docker/docker/daemon/logger" 2 3 import ( 4 "context" 5 "strconv" 6 "testing" 7 "time" 8 ) 9 10 type mockLogger struct{ c chan *Message } 11 12 func (l *mockLogger) Log(msg *Message) error { 13 l.c <- msg 14 return nil 15 } 16 17 func (l *mockLogger) Name() string { 18 return "mock" 19 } 20 21 func (l *mockLogger) Close() error { 22 return nil 23 } 24 25 func TestRingLogger(t *testing.T) { 26 mockLog := &mockLogger{make(chan *Message)} // no buffer on this channel 27 ring := newRingLogger(mockLog, Info{}, 1) 28 defer ring.setClosed() 29 30 // this should never block 31 ring.Log(&Message{Line: []byte("1")}) 32 ring.Log(&Message{Line: []byte("2")}) 33 ring.Log(&Message{Line: []byte("3")}) 34 35 select { 36 case msg := <-mockLog.c: 37 if string(msg.Line) != "1" { 38 t.Fatalf("got unexpected msg: %q", string(msg.Line)) 39 } 40 case <-time.After(100 * time.Millisecond): 41 t.Fatal("timeout reading log message") 42 } 43 44 select { 45 case msg := <-mockLog.c: 46 t.Fatalf("expected no more messages in the queue, got: %q", string(msg.Line)) 47 default: 48 } 49 } 50 51 func TestRingCap(t *testing.T) { 52 r := newRing(5) 53 for i := 0; i < 10; i++ { 54 // queue messages with "0" to "10" 55 // the "5" to "10" messages should be dropped since we only allow 5 bytes in the buffer 56 if err := r.Enqueue(&Message{Line: []byte(strconv.Itoa(i))}); err != nil { 57 t.Fatal(err) 58 } 59 } 60 61 // should have messages in the queue for "0" to "4" 62 for i := 0; i < 5; i++ { 63 m, err := r.Dequeue() 64 if err != nil { 65 t.Fatal(err) 66 } 67 if string(m.Line) != strconv.Itoa(i) { 68 t.Fatalf("got unexpected message for iter %d: %s", i, string(m.Line)) 69 } 70 } 71 72 // queue a message that's bigger than the buffer cap 73 if err := r.Enqueue(&Message{Line: []byte("hello world")}); err != nil { 74 t.Fatal(err) 75 } 76 77 // queue another message that's bigger than the buffer cap 78 if err := r.Enqueue(&Message{Line: []byte("eat a banana")}); err != nil { 79 t.Fatal(err) 80 } 81 82 m, err := r.Dequeue() 83 if err != nil { 84 t.Fatal(err) 85 } 86 if string(m.Line) != "hello world" { 87 t.Fatalf("got unexpected message: %s", string(m.Line)) 88 } 89 if len(r.queue) != 0 { 90 t.Fatalf("expected queue to be empty, got: %d", len(r.queue)) 91 } 92 } 93 94 func TestRingClose(t *testing.T) { 95 r := newRing(1) 96 if err := r.Enqueue(&Message{Line: []byte("hello")}); err != nil { 97 t.Fatal(err) 98 } 99 r.Close() 100 if err := r.Enqueue(&Message{}); err != errClosed { 101 t.Fatalf("expected errClosed, got: %v", err) 102 } 103 if len(r.queue) != 1 { 104 t.Fatal("expected empty queue") 105 } 106 if m, err := r.Dequeue(); err == nil || m != nil { 107 t.Fatal("expected err on Dequeue after close") 108 } 109 110 ls := r.Drain() 111 if len(ls) != 1 { 112 t.Fatalf("expected one message: %v", ls) 113 } 114 if string(ls[0].Line) != "hello" { 115 t.Fatalf("got unexpected message: %s", string(ls[0].Line)) 116 } 117 } 118 119 func TestRingDrain(t *testing.T) { 120 r := newRing(5) 121 for i := 0; i < 5; i++ { 122 if err := r.Enqueue(&Message{Line: []byte(strconv.Itoa(i))}); err != nil { 123 t.Fatal(err) 124 } 125 } 126 127 ls := r.Drain() 128 if len(ls) != 5 { 129 t.Fatal("got unexpected length after drain") 130 } 131 132 for i := 0; i < 5; i++ { 133 if string(ls[i].Line) != strconv.Itoa(i) { 134 t.Fatalf("got unexpected message at position %d: %s", i, string(ls[i].Line)) 135 } 136 } 137 if r.sizeBytes != 0 { 138 t.Fatalf("expected buffer size to be 0 after drain, got: %d", r.sizeBytes) 139 } 140 141 ls = r.Drain() 142 if len(ls) != 0 { 143 t.Fatalf("expected 0 messages on 2nd drain: %v", ls) 144 } 145 } 146 147 type nopLogger struct{} 148 149 func (nopLogger) Name() string { return "nopLogger" } 150 func (nopLogger) Close() error { return nil } 151 func (nopLogger) Log(*Message) error { return nil } 152 153 func BenchmarkRingLoggerThroughputNoReceiver(b *testing.B) { 154 mockLog := &mockLogger{make(chan *Message)} 155 defer mockLog.Close() 156 l := NewRingLogger(mockLog, Info{}, -1) 157 msg := &Message{Line: []byte("hello humans and everyone else!")} 158 b.SetBytes(int64(len(msg.Line))) 159 160 for i := 0; i < b.N; i++ { 161 if err := l.Log(msg); err != nil { 162 b.Fatal(err) 163 } 164 } 165 } 166 167 func BenchmarkRingLoggerThroughputWithReceiverDelay0(b *testing.B) { 168 l := NewRingLogger(nopLogger{}, Info{}, -1) 169 msg := &Message{Line: []byte("hello humans and everyone else!")} 170 b.SetBytes(int64(len(msg.Line))) 171 172 for i := 0; i < b.N; i++ { 173 if err := l.Log(msg); err != nil { 174 b.Fatal(err) 175 } 176 } 177 } 178 179 func consumeWithDelay(delay time.Duration, c <-chan *Message) (cancel func()) { 180 started := make(chan struct{}) 181 ctx, cancel := context.WithCancel(context.Background()) 182 go func() { 183 close(started) 184 ticker := time.NewTicker(delay) 185 for range ticker.C { 186 select { 187 case <-ctx.Done(): 188 ticker.Stop() 189 return 190 case <-c: 191 } 192 } 193 }() 194 <-started 195 return cancel 196 } 197 198 func BenchmarkRingLoggerThroughputConsumeDelay1(b *testing.B) { 199 mockLog := &mockLogger{make(chan *Message)} 200 defer mockLog.Close() 201 l := NewRingLogger(mockLog, Info{}, -1) 202 msg := &Message{Line: []byte("hello humans and everyone else!")} 203 b.SetBytes(int64(len(msg.Line))) 204 205 cancel := consumeWithDelay(1*time.Millisecond, mockLog.c) 206 defer cancel() 207 208 for i := 0; i < b.N; i++ { 209 if err := l.Log(msg); err != nil { 210 b.Fatal(err) 211 } 212 } 213 } 214 215 func BenchmarkRingLoggerThroughputConsumeDelay10(b *testing.B) { 216 mockLog := &mockLogger{make(chan *Message)} 217 defer mockLog.Close() 218 l := NewRingLogger(mockLog, Info{}, -1) 219 msg := &Message{Line: []byte("hello humans and everyone else!")} 220 b.SetBytes(int64(len(msg.Line))) 221 222 cancel := consumeWithDelay(10*time.Millisecond, mockLog.c) 223 defer cancel() 224 225 for i := 0; i < b.N; i++ { 226 if err := l.Log(msg); err != nil { 227 b.Fatal(err) 228 } 229 } 230 } 231 232 func BenchmarkRingLoggerThroughputConsumeDelay50(b *testing.B) { 233 mockLog := &mockLogger{make(chan *Message)} 234 defer mockLog.Close() 235 l := NewRingLogger(mockLog, Info{}, -1) 236 msg := &Message{Line: []byte("hello humans and everyone else!")} 237 b.SetBytes(int64(len(msg.Line))) 238 239 cancel := consumeWithDelay(50*time.Millisecond, mockLog.c) 240 defer cancel() 241 242 for i := 0; i < b.N; i++ { 243 if err := l.Log(msg); err != nil { 244 b.Fatal(err) 245 } 246 } 247 } 248 249 func BenchmarkRingLoggerThroughputConsumeDelay100(b *testing.B) { 250 mockLog := &mockLogger{make(chan *Message)} 251 defer mockLog.Close() 252 l := NewRingLogger(mockLog, Info{}, -1) 253 msg := &Message{Line: []byte("hello humans and everyone else!")} 254 b.SetBytes(int64(len(msg.Line))) 255 256 cancel := consumeWithDelay(100*time.Millisecond, mockLog.c) 257 defer cancel() 258 259 for i := 0; i < b.N; i++ { 260 if err := l.Log(msg); err != nil { 261 b.Fatal(err) 262 } 263 } 264 } 265 266 func BenchmarkRingLoggerThroughputConsumeDelay300(b *testing.B) { 267 mockLog := &mockLogger{make(chan *Message)} 268 defer mockLog.Close() 269 l := NewRingLogger(mockLog, Info{}, -1) 270 msg := &Message{Line: []byte("hello humans and everyone else!")} 271 b.SetBytes(int64(len(msg.Line))) 272 273 cancel := consumeWithDelay(300*time.Millisecond, mockLog.c) 274 defer cancel() 275 276 for i := 0; i < b.N; i++ { 277 if err := l.Log(msg); err != nil { 278 b.Fatal(err) 279 } 280 } 281 } 282 283 func BenchmarkRingLoggerThroughputConsumeDelay500(b *testing.B) { 284 mockLog := &mockLogger{make(chan *Message)} 285 defer mockLog.Close() 286 l := NewRingLogger(mockLog, Info{}, -1) 287 msg := &Message{Line: []byte("hello humans and everyone else!")} 288 b.SetBytes(int64(len(msg.Line))) 289 290 cancel := consumeWithDelay(500*time.Millisecond, mockLog.c) 291 defer cancel() 292 293 for i := 0; i < b.N; i++ { 294 if err := l.Log(msg); err != nil { 295 b.Fatal(err) 296 } 297 } 298 }