github.com/LazyboyChen7/engine@v17.12.1-ce-rc2+incompatible/daemon/logger/adapter_test.go (about)

     1  package logger
     2  
     3  import (
     4  	"encoding/binary"
     5  	"io"
     6  	"io/ioutil"
     7  	"os"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/docker/docker/api/types/plugins/logdriver"
    12  	protoio "github.com/gogo/protobuf/io"
    13  	"github.com/stretchr/testify/assert"
    14  )
    15  
    16  // mockLoggingPlugin implements the loggingPlugin interface for testing purposes
    17  // it only supports a single log stream
    18  type mockLoggingPlugin struct {
    19  	inStream io.ReadCloser
    20  	f        *os.File
    21  	closed   chan struct{}
    22  	t        *testing.T
    23  }
    24  
    25  func (l *mockLoggingPlugin) StartLogging(file string, info Info) error {
    26  	go func() {
    27  		io.Copy(l.f, l.inStream)
    28  		close(l.closed)
    29  	}()
    30  	return nil
    31  }
    32  
    33  func (l *mockLoggingPlugin) StopLogging(file string) error {
    34  	l.inStream.Close()
    35  	l.f.Close()
    36  	os.Remove(l.f.Name())
    37  	return nil
    38  }
    39  
    40  func (l *mockLoggingPlugin) Capabilities() (cap Capability, err error) {
    41  	return Capability{ReadLogs: true}, nil
    42  }
    43  
    44  func (l *mockLoggingPlugin) ReadLogs(info Info, config ReadConfig) (io.ReadCloser, error) {
    45  	r, w := io.Pipe()
    46  	f, err := os.Open(l.f.Name())
    47  	if err != nil {
    48  		return nil, err
    49  	}
    50  	go func() {
    51  		defer f.Close()
    52  		dec := protoio.NewUint32DelimitedReader(f, binary.BigEndian, 1e6)
    53  		enc := logdriver.NewLogEntryEncoder(w)
    54  
    55  		for {
    56  			select {
    57  			case <-l.closed:
    58  				w.Close()
    59  				return
    60  			default:
    61  			}
    62  
    63  			var msg logdriver.LogEntry
    64  			if err := dec.ReadMsg(&msg); err != nil {
    65  				if err == io.EOF {
    66  					if !config.Follow {
    67  						w.Close()
    68  						return
    69  					}
    70  					dec = protoio.NewUint32DelimitedReader(f, binary.BigEndian, 1e6)
    71  					continue
    72  				}
    73  
    74  				l.t.Fatal(err)
    75  				continue
    76  			}
    77  
    78  			if err := enc.Encode(&msg); err != nil {
    79  				w.CloseWithError(err)
    80  				return
    81  			}
    82  		}
    83  	}()
    84  
    85  	return r, nil
    86  }
    87  
    88  func newMockPluginAdapter(t *testing.T) Logger {
    89  	r, w := io.Pipe()
    90  	f, err := ioutil.TempFile("", "mock-plugin-adapter")
    91  	assert.NoError(t, err)
    92  
    93  	enc := logdriver.NewLogEntryEncoder(w)
    94  	a := &pluginAdapterWithRead{
    95  		&pluginAdapter{
    96  			plugin: &mockLoggingPlugin{
    97  				inStream: r,
    98  				f:        f,
    99  				closed:   make(chan struct{}),
   100  				t:        t,
   101  			},
   102  			stream: w,
   103  			enc:    enc,
   104  		},
   105  	}
   106  	a.plugin.StartLogging("", Info{})
   107  	return a
   108  }
   109  
   110  func TestAdapterReadLogs(t *testing.T) {
   111  	l := newMockPluginAdapter(t)
   112  
   113  	testMsg := []Message{
   114  		{Line: []byte("Are you the keymaker?"), Timestamp: time.Now()},
   115  		{Line: []byte("Follow the white rabbit"), Timestamp: time.Now()},
   116  	}
   117  	for _, msg := range testMsg {
   118  		m := msg.copy()
   119  		assert.NoError(t, l.Log(m))
   120  	}
   121  
   122  	lr, ok := l.(LogReader)
   123  	assert.NotNil(t, ok)
   124  
   125  	lw := lr.ReadLogs(ReadConfig{})
   126  
   127  	for _, x := range testMsg {
   128  		select {
   129  		case msg := <-lw.Msg:
   130  			testMessageEqual(t, &x, msg)
   131  		case <-time.After(10 * time.Second):
   132  			t.Fatal("timeout reading logs")
   133  		}
   134  	}
   135  
   136  	select {
   137  	case _, ok := <-lw.Msg:
   138  		assert.False(t, ok, "expected message channel to be closed")
   139  	case <-time.After(10 * time.Second):
   140  		t.Fatal("timeout waiting for message channel to close")
   141  
   142  	}
   143  	lw.Close()
   144  
   145  	lw = lr.ReadLogs(ReadConfig{Follow: true})
   146  	for _, x := range testMsg {
   147  		select {
   148  		case msg := <-lw.Msg:
   149  			testMessageEqual(t, &x, msg)
   150  		case <-time.After(10 * time.Second):
   151  			t.Fatal("timeout reading logs")
   152  		}
   153  	}
   154  
   155  	x := Message{Line: []byte("Too infinity and beyond!"), Timestamp: time.Now()}
   156  	assert.NoError(t, l.Log(x.copy()))
   157  
   158  	select {
   159  	case msg, ok := <-lw.Msg:
   160  		assert.NotNil(t, ok, "message channel unexpectedly closed")
   161  		testMessageEqual(t, &x, msg)
   162  	case <-time.After(10 * time.Second):
   163  		t.Fatal("timeout reading logs")
   164  	}
   165  
   166  	l.Close()
   167  	select {
   168  	case msg, ok := <-lw.Msg:
   169  		assert.False(t, ok, "expected message channel to be closed")
   170  		assert.Nil(t, msg)
   171  	case <-time.After(10 * time.Second):
   172  		t.Fatal("timeout waiting for logger to close")
   173  	}
   174  }
   175  
   176  func testMessageEqual(t *testing.T, a, b *Message) {
   177  	assert.Equal(t, a.Line, b.Line)
   178  	assert.Equal(t, a.Timestamp.UnixNano(), b.Timestamp.UnixNano())
   179  	assert.Equal(t, a.Source, b.Source)
   180  }