github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/daemon/logger/adapter_test.go (about)

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