github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/daemon/logger/loggerutils/logfile_test.go (about) 1 package loggerutils 2 3 import ( 4 "bufio" 5 "context" 6 "io" 7 "io/ioutil" 8 "os" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/docker/docker/daemon/logger" 14 "github.com/docker/docker/pkg/tailfile" 15 "gotest.tools/assert" 16 ) 17 18 func TestTailFiles(t *testing.T) { 19 s1 := strings.NewReader("Hello.\nMy name is Inigo Montoya.\n") 20 s2 := strings.NewReader("I'm serious.\nDon't call me Shirley!\n") 21 s3 := strings.NewReader("Roads?\nWhere we're going we don't need roads.\n") 22 23 files := []SizeReaderAt{s1, s2, s3} 24 watcher := logger.NewLogWatcher() 25 createDecoder := func(r io.Reader) func() (*logger.Message, error) { 26 scanner := bufio.NewScanner(r) 27 return func() (*logger.Message, error) { 28 if !scanner.Scan() { 29 return nil, scanner.Err() 30 } 31 // some comment 32 return &logger.Message{Line: scanner.Bytes(), Timestamp: time.Now()}, nil 33 } 34 } 35 36 tailReader := func(ctx context.Context, r SizeReaderAt, lines int) (io.Reader, int, error) { 37 return tailfile.NewTailReader(ctx, r, lines) 38 } 39 40 for desc, config := range map[string]logger.ReadConfig{} { 41 t.Run(desc, func(t *testing.T) { 42 started := make(chan struct{}) 43 go func() { 44 close(started) 45 tailFiles(files, watcher, createDecoder, tailReader, config) 46 }() 47 <-started 48 }) 49 } 50 51 config := logger.ReadConfig{Tail: 2} 52 started := make(chan struct{}) 53 go func() { 54 close(started) 55 tailFiles(files, watcher, createDecoder, tailReader, config) 56 }() 57 <-started 58 59 select { 60 case <-time.After(60 * time.Second): 61 t.Fatal("timeout waiting for tail line") 62 case err := <-watcher.Err: 63 assert.NilError(t, err) 64 case msg := <-watcher.Msg: 65 assert.Assert(t, msg != nil) 66 assert.Assert(t, string(msg.Line) == "Roads?", string(msg.Line)) 67 } 68 69 select { 70 case <-time.After(60 * time.Second): 71 t.Fatal("timeout waiting for tail line") 72 case err := <-watcher.Err: 73 assert.NilError(t, err) 74 case msg := <-watcher.Msg: 75 assert.Assert(t, msg != nil) 76 assert.Assert(t, string(msg.Line) == "Where we're going we don't need roads.", string(msg.Line)) 77 } 78 } 79 80 func TestFollowLogsConsumerGone(t *testing.T) { 81 lw := logger.NewLogWatcher() 82 83 f, err := ioutil.TempFile("", t.Name()) 84 assert.NilError(t, err) 85 defer func() { 86 f.Close() 87 os.Remove(f.Name()) 88 }() 89 90 makeDecoder := func(rdr io.Reader) func() (*logger.Message, error) { 91 return func() (*logger.Message, error) { 92 return &logger.Message{}, nil 93 } 94 } 95 96 followLogsDone := make(chan struct{}) 97 var since, until time.Time 98 go func() { 99 followLogs(f, lw, make(chan interface{}), makeDecoder, since, until) 100 close(followLogsDone) 101 }() 102 103 select { 104 case <-lw.Msg: 105 case err := <-lw.Err: 106 assert.NilError(t, err) 107 case <-followLogsDone: 108 t.Fatal("follow logs finished unexpectedly") 109 case <-time.After(10 * time.Second): 110 t.Fatal("timeout waiting for log message") 111 } 112 113 lw.ConsumerGone() 114 select { 115 case <-followLogsDone: 116 case <-time.After(20 * time.Second): 117 t.Fatal("timeout waiting for followLogs() to finish") 118 } 119 } 120 121 func TestFollowLogsProducerGone(t *testing.T) { 122 lw := logger.NewLogWatcher() 123 124 f, err := ioutil.TempFile("", t.Name()) 125 assert.NilError(t, err) 126 defer os.Remove(f.Name()) 127 128 var sent, received, closed int 129 makeDecoder := func(rdr io.Reader) func() (*logger.Message, error) { 130 return func() (*logger.Message, error) { 131 if closed == 1 { 132 closed++ 133 t.Logf("logDecode() closed after sending %d messages\n", sent) 134 return nil, io.EOF 135 } else if closed > 1 { 136 t.Fatal("logDecode() called after closing!") 137 return nil, io.EOF 138 } 139 sent++ 140 return &logger.Message{}, nil 141 } 142 } 143 var since, until time.Time 144 145 followLogsDone := make(chan struct{}) 146 go func() { 147 followLogs(f, lw, make(chan interface{}), makeDecoder, since, until) 148 close(followLogsDone) 149 }() 150 151 // read 1 message 152 select { 153 case <-lw.Msg: 154 received++ 155 case err := <-lw.Err: 156 assert.NilError(t, err) 157 case <-followLogsDone: 158 t.Fatal("followLogs() finished unexpectedly") 159 case <-time.After(10 * time.Second): 160 t.Fatal("timeout waiting for log message") 161 } 162 163 // "stop" the "container" 164 closed = 1 165 lw.ProducerGone() 166 167 // should receive all the messages sent 168 readDone := make(chan struct{}) 169 go func() { 170 defer close(readDone) 171 for { 172 select { 173 case <-lw.Msg: 174 received++ 175 if received == sent { 176 return 177 } 178 case err := <-lw.Err: 179 assert.NilError(t, err) 180 } 181 } 182 }() 183 select { 184 case <-readDone: 185 case <-time.After(30 * time.Second): 186 t.Fatalf("timeout waiting for log messages to be read (sent: %d, received: %d", sent, received) 187 } 188 189 t.Logf("messages sent: %d, received: %d", sent, received) 190 191 // followLogs() should be done by now 192 select { 193 case <-followLogsDone: 194 case <-time.After(30 * time.Second): 195 t.Fatal("timeout waiting for followLogs() to finish") 196 } 197 198 select { 199 case <-lw.WatchConsumerGone(): 200 t.Fatal("consumer should not have exited") 201 default: 202 } 203 }