github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/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  
   148  type nopLogger struct{}
   149  
   150  func (nopLogger) Name() string       { return "nopLogger" }
   151  func (nopLogger) Close() error       { return nil }
   152  func (nopLogger) Log(*Message) error { return nil }
   153  
   154  func BenchmarkRingLoggerThroughputNoReceiver(b *testing.B) {
   155  	mockLog := &mockLogger{make(chan *Message)}
   156  	defer mockLog.Close()
   157  	l := NewRingLogger(mockLog, Info{}, -1)
   158  	msg := &Message{Line: []byte("hello humans and everyone else!")}
   159  	b.SetBytes(int64(len(msg.Line)))
   160  
   161  	for i := 0; i < b.N; i++ {
   162  		if err := l.Log(msg); err != nil {
   163  			b.Fatal(err)
   164  		}
   165  	}
   166  }
   167  
   168  func BenchmarkRingLoggerThroughputWithReceiverDelay0(b *testing.B) {
   169  	l := NewRingLogger(nopLogger{}, Info{}, -1)
   170  	msg := &Message{Line: []byte("hello humans and everyone else!")}
   171  	b.SetBytes(int64(len(msg.Line)))
   172  
   173  	for i := 0; i < b.N; i++ {
   174  		if err := l.Log(msg); err != nil {
   175  			b.Fatal(err)
   176  		}
   177  	}
   178  }
   179  
   180  func consumeWithDelay(delay time.Duration, c <-chan *Message) (cancel func()) {
   181  	started := make(chan struct{})
   182  	ctx, cancel := context.WithCancel(context.Background())
   183  	go func() {
   184  		close(started)
   185  		ticker := time.NewTicker(delay)
   186  		for range ticker.C {
   187  			select {
   188  			case <-ctx.Done():
   189  				ticker.Stop()
   190  				return
   191  			case <-c:
   192  			}
   193  		}
   194  	}()
   195  	<-started
   196  	return cancel
   197  }
   198  
   199  func BenchmarkRingLoggerThroughputConsumeDelay1(b *testing.B) {
   200  	mockLog := &mockLogger{make(chan *Message)}
   201  	defer mockLog.Close()
   202  	l := NewRingLogger(mockLog, Info{}, -1)
   203  	msg := &Message{Line: []byte("hello humans and everyone else!")}
   204  	b.SetBytes(int64(len(msg.Line)))
   205  
   206  	cancel := consumeWithDelay(1*time.Millisecond, mockLog.c)
   207  	defer cancel()
   208  
   209  	for i := 0; i < b.N; i++ {
   210  		if err := l.Log(msg); err != nil {
   211  			b.Fatal(err)
   212  		}
   213  	}
   214  }
   215  
   216  func BenchmarkRingLoggerThroughputConsumeDelay10(b *testing.B) {
   217  	mockLog := &mockLogger{make(chan *Message)}
   218  	defer mockLog.Close()
   219  	l := NewRingLogger(mockLog, Info{}, -1)
   220  	msg := &Message{Line: []byte("hello humans and everyone else!")}
   221  	b.SetBytes(int64(len(msg.Line)))
   222  
   223  	cancel := consumeWithDelay(10*time.Millisecond, mockLog.c)
   224  	defer cancel()
   225  
   226  	for i := 0; i < b.N; i++ {
   227  		if err := l.Log(msg); err != nil {
   228  			b.Fatal(err)
   229  		}
   230  	}
   231  }
   232  
   233  func BenchmarkRingLoggerThroughputConsumeDelay50(b *testing.B) {
   234  	mockLog := &mockLogger{make(chan *Message)}
   235  	defer mockLog.Close()
   236  	l := NewRingLogger(mockLog, Info{}, -1)
   237  	msg := &Message{Line: []byte("hello humans and everyone else!")}
   238  	b.SetBytes(int64(len(msg.Line)))
   239  
   240  	cancel := consumeWithDelay(50*time.Millisecond, mockLog.c)
   241  	defer cancel()
   242  
   243  	for i := 0; i < b.N; i++ {
   244  		if err := l.Log(msg); err != nil {
   245  			b.Fatal(err)
   246  		}
   247  	}
   248  }
   249  
   250  func BenchmarkRingLoggerThroughputConsumeDelay100(b *testing.B) {
   251  	mockLog := &mockLogger{make(chan *Message)}
   252  	defer mockLog.Close()
   253  	l := NewRingLogger(mockLog, Info{}, -1)
   254  	msg := &Message{Line: []byte("hello humans and everyone else!")}
   255  	b.SetBytes(int64(len(msg.Line)))
   256  
   257  	cancel := consumeWithDelay(100*time.Millisecond, mockLog.c)
   258  	defer cancel()
   259  
   260  	for i := 0; i < b.N; i++ {
   261  		if err := l.Log(msg); err != nil {
   262  			b.Fatal(err)
   263  		}
   264  	}
   265  }
   266  
   267  func BenchmarkRingLoggerThroughputConsumeDelay300(b *testing.B) {
   268  	mockLog := &mockLogger{make(chan *Message)}
   269  	defer mockLog.Close()
   270  	l := NewRingLogger(mockLog, Info{}, -1)
   271  	msg := &Message{Line: []byte("hello humans and everyone else!")}
   272  	b.SetBytes(int64(len(msg.Line)))
   273  
   274  	cancel := consumeWithDelay(300*time.Millisecond, mockLog.c)
   275  	defer cancel()
   276  
   277  	for i := 0; i < b.N; i++ {
   278  		if err := l.Log(msg); err != nil {
   279  			b.Fatal(err)
   280  		}
   281  	}
   282  }
   283  
   284  func BenchmarkRingLoggerThroughputConsumeDelay500(b *testing.B) {
   285  	mockLog := &mockLogger{make(chan *Message)}
   286  	defer mockLog.Close()
   287  	l := NewRingLogger(mockLog, Info{}, -1)
   288  	msg := &Message{Line: []byte("hello humans and everyone else!")}
   289  	b.SetBytes(int64(len(msg.Line)))
   290  
   291  	cancel := consumeWithDelay(500*time.Millisecond, mockLog.c)
   292  	defer cancel()
   293  
   294  	for i := 0; i < b.N; i++ {
   295  		if err := l.Log(msg); err != nil {
   296  			b.Fatal(err)
   297  		}
   298  	}
   299  }