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 }