github.com/LazyboyChen7/engine@v17.12.1-ce-rc2+incompatible/daemon/logger/copier_test.go (about) 1 package logger 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "os" 9 "strings" 10 "sync" 11 "testing" 12 "time" 13 ) 14 15 type TestLoggerJSON struct { 16 *json.Encoder 17 mu sync.Mutex 18 delay time.Duration 19 } 20 21 func (l *TestLoggerJSON) Log(m *Message) error { 22 if l.delay > 0 { 23 time.Sleep(l.delay) 24 } 25 l.mu.Lock() 26 defer l.mu.Unlock() 27 return l.Encode(m) 28 } 29 30 func (l *TestLoggerJSON) Close() error { return nil } 31 32 func (l *TestLoggerJSON) Name() string { return "json" } 33 34 type TestSizedLoggerJSON struct { 35 *json.Encoder 36 mu sync.Mutex 37 } 38 39 func (l *TestSizedLoggerJSON) Log(m *Message) error { 40 l.mu.Lock() 41 defer l.mu.Unlock() 42 return l.Encode(m) 43 } 44 45 func (*TestSizedLoggerJSON) Close() error { return nil } 46 47 func (*TestSizedLoggerJSON) Name() string { return "sized-json" } 48 49 func (*TestSizedLoggerJSON) BufSize() int { 50 return 32 * 1024 51 } 52 53 func TestCopier(t *testing.T) { 54 stdoutLine := "Line that thinks that it is log line from docker stdout" 55 stderrLine := "Line that thinks that it is log line from docker stderr" 56 stdoutTrailingLine := "stdout trailing line" 57 stderrTrailingLine := "stderr trailing line" 58 59 var stdout bytes.Buffer 60 var stderr bytes.Buffer 61 for i := 0; i < 30; i++ { 62 if _, err := stdout.WriteString(stdoutLine + "\n"); err != nil { 63 t.Fatal(err) 64 } 65 if _, err := stderr.WriteString(stderrLine + "\n"); err != nil { 66 t.Fatal(err) 67 } 68 } 69 70 // Test remaining lines without line-endings 71 if _, err := stdout.WriteString(stdoutTrailingLine); err != nil { 72 t.Fatal(err) 73 } 74 if _, err := stderr.WriteString(stderrTrailingLine); err != nil { 75 t.Fatal(err) 76 } 77 78 var jsonBuf bytes.Buffer 79 80 jsonLog := &TestLoggerJSON{Encoder: json.NewEncoder(&jsonBuf)} 81 82 c := NewCopier( 83 map[string]io.Reader{ 84 "stdout": &stdout, 85 "stderr": &stderr, 86 }, 87 jsonLog) 88 c.Run() 89 wait := make(chan struct{}) 90 go func() { 91 c.Wait() 92 close(wait) 93 }() 94 select { 95 case <-time.After(1 * time.Second): 96 t.Fatal("Copier failed to do its work in 1 second") 97 case <-wait: 98 } 99 dec := json.NewDecoder(&jsonBuf) 100 for { 101 var msg Message 102 if err := dec.Decode(&msg); err != nil { 103 if err == io.EOF { 104 break 105 } 106 t.Fatal(err) 107 } 108 if msg.Source != "stdout" && msg.Source != "stderr" { 109 t.Fatalf("Wrong Source: %q, should be %q or %q", msg.Source, "stdout", "stderr") 110 } 111 if msg.Source == "stdout" { 112 if string(msg.Line) != stdoutLine && string(msg.Line) != stdoutTrailingLine { 113 t.Fatalf("Wrong Line: %q, expected %q or %q", msg.Line, stdoutLine, stdoutTrailingLine) 114 } 115 } 116 if msg.Source == "stderr" { 117 if string(msg.Line) != stderrLine && string(msg.Line) != stderrTrailingLine { 118 t.Fatalf("Wrong Line: %q, expected %q or %q", msg.Line, stderrLine, stderrTrailingLine) 119 } 120 } 121 } 122 } 123 124 // TestCopierLongLines tests long lines without line breaks 125 func TestCopierLongLines(t *testing.T) { 126 // Long lines (should be split at "defaultBufSize") 127 stdoutLongLine := strings.Repeat("a", defaultBufSize) 128 stderrLongLine := strings.Repeat("b", defaultBufSize) 129 stdoutTrailingLine := "stdout trailing line" 130 stderrTrailingLine := "stderr trailing line" 131 132 var stdout bytes.Buffer 133 var stderr bytes.Buffer 134 135 for i := 0; i < 3; i++ { 136 if _, err := stdout.WriteString(stdoutLongLine); err != nil { 137 t.Fatal(err) 138 } 139 if _, err := stderr.WriteString(stderrLongLine); err != nil { 140 t.Fatal(err) 141 } 142 } 143 144 if _, err := stdout.WriteString(stdoutTrailingLine); err != nil { 145 t.Fatal(err) 146 } 147 if _, err := stderr.WriteString(stderrTrailingLine); err != nil { 148 t.Fatal(err) 149 } 150 151 var jsonBuf bytes.Buffer 152 153 jsonLog := &TestLoggerJSON{Encoder: json.NewEncoder(&jsonBuf)} 154 155 c := NewCopier( 156 map[string]io.Reader{ 157 "stdout": &stdout, 158 "stderr": &stderr, 159 }, 160 jsonLog) 161 c.Run() 162 wait := make(chan struct{}) 163 go func() { 164 c.Wait() 165 close(wait) 166 }() 167 select { 168 case <-time.After(1 * time.Second): 169 t.Fatal("Copier failed to do its work in 1 second") 170 case <-wait: 171 } 172 dec := json.NewDecoder(&jsonBuf) 173 for { 174 var msg Message 175 if err := dec.Decode(&msg); err != nil { 176 if err == io.EOF { 177 break 178 } 179 t.Fatal(err) 180 } 181 if msg.Source != "stdout" && msg.Source != "stderr" { 182 t.Fatalf("Wrong Source: %q, should be %q or %q", msg.Source, "stdout", "stderr") 183 } 184 if msg.Source == "stdout" { 185 if string(msg.Line) != stdoutLongLine && string(msg.Line) != stdoutTrailingLine { 186 t.Fatalf("Wrong Line: %q, expected 'stdoutLongLine' or 'stdoutTrailingLine'", msg.Line) 187 } 188 } 189 if msg.Source == "stderr" { 190 if string(msg.Line) != stderrLongLine && string(msg.Line) != stderrTrailingLine { 191 t.Fatalf("Wrong Line: %q, expected 'stderrLongLine' or 'stderrTrailingLine'", msg.Line) 192 } 193 } 194 } 195 } 196 197 func TestCopierSlow(t *testing.T) { 198 stdoutLine := "Line that thinks that it is log line from docker stdout" 199 var stdout bytes.Buffer 200 for i := 0; i < 30; i++ { 201 if _, err := stdout.WriteString(stdoutLine + "\n"); err != nil { 202 t.Fatal(err) 203 } 204 } 205 206 var jsonBuf bytes.Buffer 207 //encoder := &encodeCloser{Encoder: json.NewEncoder(&jsonBuf)} 208 jsonLog := &TestLoggerJSON{Encoder: json.NewEncoder(&jsonBuf), delay: 100 * time.Millisecond} 209 210 c := NewCopier(map[string]io.Reader{"stdout": &stdout}, jsonLog) 211 c.Run() 212 wait := make(chan struct{}) 213 go func() { 214 c.Wait() 215 close(wait) 216 }() 217 <-time.After(150 * time.Millisecond) 218 c.Close() 219 select { 220 case <-time.After(200 * time.Millisecond): 221 t.Fatal("failed to exit in time after the copier is closed") 222 case <-wait: 223 } 224 } 225 226 func TestCopierWithSized(t *testing.T) { 227 var jsonBuf bytes.Buffer 228 expectedMsgs := 2 229 sizedLogger := &TestSizedLoggerJSON{Encoder: json.NewEncoder(&jsonBuf)} 230 logbuf := bytes.NewBufferString(strings.Repeat(".", sizedLogger.BufSize()*expectedMsgs)) 231 c := NewCopier(map[string]io.Reader{"stdout": logbuf}, sizedLogger) 232 233 c.Run() 234 // Wait for Copier to finish writing to the buffered logger. 235 c.Wait() 236 c.Close() 237 238 recvdMsgs := 0 239 dec := json.NewDecoder(&jsonBuf) 240 for { 241 var msg Message 242 if err := dec.Decode(&msg); err != nil { 243 if err == io.EOF { 244 break 245 } 246 t.Fatal(err) 247 } 248 if msg.Source != "stdout" { 249 t.Fatalf("Wrong Source: %q, should be %q", msg.Source, "stdout") 250 } 251 if len(msg.Line) != sizedLogger.BufSize() { 252 t.Fatalf("Line was not of expected max length %d, was %d", sizedLogger.BufSize(), len(msg.Line)) 253 } 254 recvdMsgs++ 255 } 256 if recvdMsgs != expectedMsgs { 257 t.Fatalf("expected to receive %d messages, actually received %d", expectedMsgs, recvdMsgs) 258 } 259 } 260 261 type BenchmarkLoggerDummy struct { 262 } 263 264 func (l *BenchmarkLoggerDummy) Log(m *Message) error { PutMessage(m); return nil } 265 266 func (l *BenchmarkLoggerDummy) Close() error { return nil } 267 268 func (l *BenchmarkLoggerDummy) Name() string { return "dummy" } 269 270 func BenchmarkCopier64(b *testing.B) { 271 benchmarkCopier(b, 1<<6) 272 } 273 func BenchmarkCopier128(b *testing.B) { 274 benchmarkCopier(b, 1<<7) 275 } 276 func BenchmarkCopier256(b *testing.B) { 277 benchmarkCopier(b, 1<<8) 278 } 279 func BenchmarkCopier512(b *testing.B) { 280 benchmarkCopier(b, 1<<9) 281 } 282 func BenchmarkCopier1K(b *testing.B) { 283 benchmarkCopier(b, 1<<10) 284 } 285 func BenchmarkCopier2K(b *testing.B) { 286 benchmarkCopier(b, 1<<11) 287 } 288 func BenchmarkCopier4K(b *testing.B) { 289 benchmarkCopier(b, 1<<12) 290 } 291 func BenchmarkCopier8K(b *testing.B) { 292 benchmarkCopier(b, 1<<13) 293 } 294 func BenchmarkCopier16K(b *testing.B) { 295 benchmarkCopier(b, 1<<14) 296 } 297 func BenchmarkCopier32K(b *testing.B) { 298 benchmarkCopier(b, 1<<15) 299 } 300 func BenchmarkCopier64K(b *testing.B) { 301 benchmarkCopier(b, 1<<16) 302 } 303 func BenchmarkCopier128K(b *testing.B) { 304 benchmarkCopier(b, 1<<17) 305 } 306 func BenchmarkCopier256K(b *testing.B) { 307 benchmarkCopier(b, 1<<18) 308 } 309 310 func piped(b *testing.B, iterations int, delay time.Duration, buf []byte) io.Reader { 311 r, w, err := os.Pipe() 312 if err != nil { 313 b.Fatal(err) 314 return nil 315 } 316 go func() { 317 for i := 0; i < iterations; i++ { 318 time.Sleep(delay) 319 if n, err := w.Write(buf); err != nil || n != len(buf) { 320 if err != nil { 321 b.Fatal(err) 322 } 323 b.Fatal(fmt.Errorf("short write")) 324 } 325 } 326 w.Close() 327 }() 328 return r 329 } 330 331 func benchmarkCopier(b *testing.B, length int) { 332 b.StopTimer() 333 buf := []byte{'A'} 334 for len(buf) < length { 335 buf = append(buf, buf...) 336 } 337 buf = append(buf[:length-1], []byte{'\n'}...) 338 b.StartTimer() 339 for i := 0; i < b.N; i++ { 340 c := NewCopier( 341 map[string]io.Reader{ 342 "buffer": piped(b, 10, time.Nanosecond, buf), 343 }, 344 &BenchmarkLoggerDummy{}) 345 c.Run() 346 c.Wait() 347 c.Close() 348 } 349 }