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  }