mirror of
https://github.com/moby/moby.git
synced 2026-07-17 13:01:51 +00:00
Before this change a call to `Close` could be blocked if the the channel used to buffer logs is full. When this happens the container state will end up wedged causing a deadlock on anything that needs to lock the container state. This removes the use of a channel which has semantics which are difficult to manage to something more suitable for the situation. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
88 lines
1.8 KiB
Go
88 lines
1.8 KiB
Go
package loggerutils
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/docker/docker/daemon/logger"
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
func TestQueue(t *testing.T) {
|
|
q := NewMessageQueue(2)
|
|
msg := &logger.Message{Line: []byte("hello")}
|
|
|
|
ctx := context.Background()
|
|
err := q.Enqueue(ctx, msg)
|
|
assert.Check(t, err)
|
|
|
|
recv := q.Receiver()
|
|
// These pointer values should be the same
|
|
assert.Equal(t, msg, <-recv)
|
|
|
|
err = q.Enqueue(ctx, msg)
|
|
assert.Check(t, err)
|
|
|
|
err = q.Enqueue(ctx, msg)
|
|
assert.Check(t, err)
|
|
|
|
q.Close()
|
|
|
|
// We have 2 messages in the queue
|
|
// Even though this is closed, we should get a true value from dequeue twice.
|
|
assert.Equal(t, msg, <-recv)
|
|
assert.Equal(t, msg, <-recv)
|
|
|
|
// This should not block and should return false
|
|
_, more := <-recv
|
|
assert.Check(t, !more, "expected no more messages in the queue")
|
|
|
|
// Test with unbuffered
|
|
q = &MessageQueue{}
|
|
recv = q.Receiver()
|
|
|
|
chAdd := make(chan error, 1)
|
|
go func() {
|
|
chAdd <- q.Enqueue(ctx, msg)
|
|
}()
|
|
|
|
assert.Equal(t, msg, <-recv)
|
|
assert.Assert(t, <-chAdd)
|
|
|
|
ctxC, cancel := context.WithCancel(ctx)
|
|
cancel()
|
|
|
|
err = q.Enqueue(ctxC, msg)
|
|
assert.ErrorIs(t, err, context.Canceled)
|
|
|
|
// Test that blocked senders do not cause a panic on close.
|
|
// This check is useful because the underlying implementation uses channels
|
|
// with the send channel eventually getting closed when q.Close is called.
|
|
go func() {
|
|
chAdd <- q.Enqueue(ctx, msg)
|
|
}()
|
|
|
|
// Wait for enqueue to be ready (or as close to ready as it can be)
|
|
for {
|
|
q.mu.Lock()
|
|
if q.sendWaiters == 1 {
|
|
q.mu.Unlock()
|
|
break
|
|
}
|
|
q.mu.Unlock()
|
|
time.Sleep(time.Millisecond)
|
|
}
|
|
|
|
q.Close()
|
|
|
|
select {
|
|
case <-time.After(5 * time.Second):
|
|
case err := <-chAdd:
|
|
assert.ErrorIs(t, err, ErrQueueClosed)
|
|
}
|
|
|
|
// Double-close should not cause any issues
|
|
q.Close()
|
|
}
|