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 }