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  }