github.com/tompao/docker@v1.9.1/daemon/logger/awslogs/cloudwatchlogs_test.go (about)

     1  package awslogs
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/aws/awserr"
    11  	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
    12  	"github.com/docker/docker/daemon/logger"
    13  )
    14  
    15  const (
    16  	groupName         = "groupName"
    17  	streamName        = "streamName"
    18  	sequenceToken     = "sequenceToken"
    19  	nextSequenceToken = "nextSequenceToken"
    20  	logline           = "this is a log line"
    21  )
    22  
    23  func TestCreateSuccess(t *testing.T) {
    24  	mockClient := newMockClient()
    25  	stream := &logStream{
    26  		client:        mockClient,
    27  		logGroupName:  groupName,
    28  		logStreamName: streamName,
    29  	}
    30  	mockClient.createLogStreamResult <- &createLogStreamResult{}
    31  
    32  	err := stream.create()
    33  
    34  	if err != nil {
    35  		t.Errorf("Received unexpected err: %v\n", err)
    36  	}
    37  	argument := <-mockClient.createLogStreamArgument
    38  	if argument.LogGroupName == nil {
    39  		t.Fatal("Expected non-nil LogGroupName")
    40  	}
    41  	if *argument.LogGroupName != groupName {
    42  		t.Errorf("Expected LogGroupName to be %s", groupName)
    43  	}
    44  	if argument.LogStreamName == nil {
    45  		t.Fatal("Expected non-nil LogGroupName")
    46  	}
    47  	if *argument.LogStreamName != streamName {
    48  		t.Errorf("Expected LogStreamName to be %s", streamName)
    49  	}
    50  }
    51  
    52  func TestCreateError(t *testing.T) {
    53  	mockClient := newMockClient()
    54  	stream := &logStream{
    55  		client: mockClient,
    56  	}
    57  	mockClient.createLogStreamResult <- &createLogStreamResult{
    58  		errorResult: errors.New("Error!"),
    59  	}
    60  
    61  	err := stream.create()
    62  
    63  	if err == nil {
    64  		t.Fatal("Expected non-nil err")
    65  	}
    66  }
    67  
    68  func TestCreateAlreadyExists(t *testing.T) {
    69  	mockClient := newMockClient()
    70  	stream := &logStream{
    71  		client: mockClient,
    72  	}
    73  	mockClient.createLogStreamResult <- &createLogStreamResult{
    74  		errorResult: awserr.New(resourceAlreadyExistsCode, "", nil),
    75  	}
    76  
    77  	err := stream.create()
    78  
    79  	if err != nil {
    80  		t.Fatal("Expected nil err")
    81  	}
    82  }
    83  
    84  func TestPublishBatchSuccess(t *testing.T) {
    85  	mockClient := newMockClient()
    86  	stream := &logStream{
    87  		client:        mockClient,
    88  		logGroupName:  groupName,
    89  		logStreamName: streamName,
    90  		sequenceToken: aws.String(sequenceToken),
    91  	}
    92  	mockClient.putLogEventsResult <- &putLogEventsResult{
    93  		successResult: &cloudwatchlogs.PutLogEventsOutput{
    94  			NextSequenceToken: aws.String(nextSequenceToken),
    95  		},
    96  	}
    97  
    98  	events := []*cloudwatchlogs.InputLogEvent{
    99  		{
   100  			Message: aws.String(logline),
   101  		},
   102  	}
   103  
   104  	stream.publishBatch(events)
   105  	if stream.sequenceToken == nil {
   106  		t.Fatal("Expected non-nil sequenceToken")
   107  	}
   108  	if *stream.sequenceToken != nextSequenceToken {
   109  		t.Errorf("Expected sequenceToken to be %s, but was %s", nextSequenceToken, *stream.sequenceToken)
   110  	}
   111  	argument := <-mockClient.putLogEventsArgument
   112  	if argument == nil {
   113  		t.Fatal("Expected non-nil PutLogEventsInput")
   114  	}
   115  	if argument.SequenceToken == nil {
   116  		t.Fatal("Expected non-nil PutLogEventsInput.SequenceToken")
   117  	}
   118  	if *argument.SequenceToken != sequenceToken {
   119  		t.Errorf("Expected PutLogEventsInput.SequenceToken to be %s, but was %s", sequenceToken, *argument.SequenceToken)
   120  	}
   121  	if len(argument.LogEvents) != 1 {
   122  		t.Errorf("Expected LogEvents to contain 1 element, but contains %d", len(argument.LogEvents))
   123  	}
   124  	if argument.LogEvents[0] != events[0] {
   125  		t.Error("Expected event to equal input")
   126  	}
   127  }
   128  
   129  func TestPublishBatchError(t *testing.T) {
   130  	mockClient := newMockClient()
   131  	stream := &logStream{
   132  		client:        mockClient,
   133  		logGroupName:  groupName,
   134  		logStreamName: streamName,
   135  		sequenceToken: aws.String(sequenceToken),
   136  	}
   137  	mockClient.putLogEventsResult <- &putLogEventsResult{
   138  		errorResult: errors.New("Error!"),
   139  	}
   140  
   141  	events := []*cloudwatchlogs.InputLogEvent{
   142  		{
   143  			Message: aws.String(logline),
   144  		},
   145  	}
   146  
   147  	stream.publishBatch(events)
   148  	if stream.sequenceToken == nil {
   149  		t.Fatal("Expected non-nil sequenceToken")
   150  	}
   151  	if *stream.sequenceToken != sequenceToken {
   152  		t.Errorf("Expected sequenceToken to be %s, but was %s", sequenceToken, *stream.sequenceToken)
   153  	}
   154  }
   155  
   156  func TestPublishBatchInvalidSeqSuccess(t *testing.T) {
   157  	mockClient := newMockClientBuffered(2)
   158  	stream := &logStream{
   159  		client:        mockClient,
   160  		logGroupName:  groupName,
   161  		logStreamName: streamName,
   162  		sequenceToken: aws.String(sequenceToken),
   163  	}
   164  	mockClient.putLogEventsResult <- &putLogEventsResult{
   165  		errorResult: awserr.New(invalidSequenceTokenCode, "use token token", nil),
   166  	}
   167  	mockClient.putLogEventsResult <- &putLogEventsResult{
   168  		successResult: &cloudwatchlogs.PutLogEventsOutput{
   169  			NextSequenceToken: aws.String(nextSequenceToken),
   170  		},
   171  	}
   172  
   173  	events := []*cloudwatchlogs.InputLogEvent{
   174  		{
   175  			Message: aws.String(logline),
   176  		},
   177  	}
   178  
   179  	stream.publishBatch(events)
   180  	if stream.sequenceToken == nil {
   181  		t.Fatal("Expected non-nil sequenceToken")
   182  	}
   183  	if *stream.sequenceToken != nextSequenceToken {
   184  		t.Errorf("Expected sequenceToken to be %s, but was %s", nextSequenceToken, *stream.sequenceToken)
   185  	}
   186  
   187  	argument := <-mockClient.putLogEventsArgument
   188  	if argument == nil {
   189  		t.Fatal("Expected non-nil PutLogEventsInput")
   190  	}
   191  	if argument.SequenceToken == nil {
   192  		t.Fatal("Expected non-nil PutLogEventsInput.SequenceToken")
   193  	}
   194  	if *argument.SequenceToken != sequenceToken {
   195  		t.Errorf("Expected PutLogEventsInput.SequenceToken to be %s, but was %s", sequenceToken, *argument.SequenceToken)
   196  	}
   197  	if len(argument.LogEvents) != 1 {
   198  		t.Errorf("Expected LogEvents to contain 1 element, but contains %d", len(argument.LogEvents))
   199  	}
   200  	if argument.LogEvents[0] != events[0] {
   201  		t.Error("Expected event to equal input")
   202  	}
   203  
   204  	argument = <-mockClient.putLogEventsArgument
   205  	if argument == nil {
   206  		t.Fatal("Expected non-nil PutLogEventsInput")
   207  	}
   208  	if argument.SequenceToken == nil {
   209  		t.Fatal("Expected non-nil PutLogEventsInput.SequenceToken")
   210  	}
   211  	if *argument.SequenceToken != "token" {
   212  		t.Errorf("Expected PutLogEventsInput.SequenceToken to be %s, but was %s", "token", *argument.SequenceToken)
   213  	}
   214  	if len(argument.LogEvents) != 1 {
   215  		t.Errorf("Expected LogEvents to contain 1 element, but contains %d", len(argument.LogEvents))
   216  	}
   217  	if argument.LogEvents[0] != events[0] {
   218  		t.Error("Expected event to equal input")
   219  	}
   220  }
   221  
   222  func TestPublishBatchAlreadyAccepted(t *testing.T) {
   223  	mockClient := newMockClient()
   224  	stream := &logStream{
   225  		client:        mockClient,
   226  		logGroupName:  groupName,
   227  		logStreamName: streamName,
   228  		sequenceToken: aws.String(sequenceToken),
   229  	}
   230  	mockClient.putLogEventsResult <- &putLogEventsResult{
   231  		errorResult: awserr.New(dataAlreadyAcceptedCode, "use token token", nil),
   232  	}
   233  
   234  	events := []*cloudwatchlogs.InputLogEvent{
   235  		{
   236  			Message: aws.String(logline),
   237  		},
   238  	}
   239  
   240  	stream.publishBatch(events)
   241  	if stream.sequenceToken == nil {
   242  		t.Fatal("Expected non-nil sequenceToken")
   243  	}
   244  	if *stream.sequenceToken != "token" {
   245  		t.Errorf("Expected sequenceToken to be %s, but was %s", "token", *stream.sequenceToken)
   246  	}
   247  
   248  	argument := <-mockClient.putLogEventsArgument
   249  	if argument == nil {
   250  		t.Fatal("Expected non-nil PutLogEventsInput")
   251  	}
   252  	if argument.SequenceToken == nil {
   253  		t.Fatal("Expected non-nil PutLogEventsInput.SequenceToken")
   254  	}
   255  	if *argument.SequenceToken != sequenceToken {
   256  		t.Errorf("Expected PutLogEventsInput.SequenceToken to be %s, but was %s", sequenceToken, *argument.SequenceToken)
   257  	}
   258  	if len(argument.LogEvents) != 1 {
   259  		t.Errorf("Expected LogEvents to contain 1 element, but contains %d", len(argument.LogEvents))
   260  	}
   261  	if argument.LogEvents[0] != events[0] {
   262  		t.Error("Expected event to equal input")
   263  	}
   264  }
   265  
   266  func TestCollectBatchSimple(t *testing.T) {
   267  	mockClient := newMockClient()
   268  	stream := &logStream{
   269  		client:        mockClient,
   270  		logGroupName:  groupName,
   271  		logStreamName: streamName,
   272  		sequenceToken: aws.String(sequenceToken),
   273  		messages:      make(chan *logger.Message),
   274  	}
   275  	mockClient.putLogEventsResult <- &putLogEventsResult{
   276  		successResult: &cloudwatchlogs.PutLogEventsOutput{
   277  			NextSequenceToken: aws.String(nextSequenceToken),
   278  		},
   279  	}
   280  	ticks := make(chan time.Time)
   281  	newTicker = func(_ time.Duration) *time.Ticker {
   282  		return &time.Ticker{
   283  			C: ticks,
   284  		}
   285  	}
   286  
   287  	go stream.collectBatch()
   288  
   289  	stream.Log(&logger.Message{
   290  		Line:      []byte(logline),
   291  		Timestamp: time.Time{},
   292  	})
   293  
   294  	ticks <- time.Time{}
   295  	stream.Close()
   296  
   297  	argument := <-mockClient.putLogEventsArgument
   298  	if argument == nil {
   299  		t.Fatal("Expected non-nil PutLogEventsInput")
   300  	}
   301  	if len(argument.LogEvents) != 1 {
   302  		t.Errorf("Expected LogEvents to contain 1 element, but contains %d", len(argument.LogEvents))
   303  	}
   304  	if *argument.LogEvents[0].Message != logline {
   305  		t.Errorf("Expected message to be %s but was %s", logline, *argument.LogEvents[0].Message)
   306  	}
   307  }
   308  
   309  func TestCollectBatchTicker(t *testing.T) {
   310  	mockClient := newMockClient()
   311  	stream := &logStream{
   312  		client:        mockClient,
   313  		logGroupName:  groupName,
   314  		logStreamName: streamName,
   315  		sequenceToken: aws.String(sequenceToken),
   316  		messages:      make(chan *logger.Message),
   317  	}
   318  	mockClient.putLogEventsResult <- &putLogEventsResult{
   319  		successResult: &cloudwatchlogs.PutLogEventsOutput{
   320  			NextSequenceToken: aws.String(nextSequenceToken),
   321  		},
   322  	}
   323  	ticks := make(chan time.Time)
   324  	newTicker = func(_ time.Duration) *time.Ticker {
   325  		return &time.Ticker{
   326  			C: ticks,
   327  		}
   328  	}
   329  
   330  	go stream.collectBatch()
   331  
   332  	stream.Log(&logger.Message{
   333  		Line:      []byte(logline + " 1"),
   334  		Timestamp: time.Time{},
   335  	})
   336  	stream.Log(&logger.Message{
   337  		Line:      []byte(logline + " 2"),
   338  		Timestamp: time.Time{},
   339  	})
   340  
   341  	ticks <- time.Time{}
   342  
   343  	// Verify first batch
   344  	argument := <-mockClient.putLogEventsArgument
   345  	if argument == nil {
   346  		t.Fatal("Expected non-nil PutLogEventsInput")
   347  	}
   348  	if len(argument.LogEvents) != 2 {
   349  		t.Errorf("Expected LogEvents to contain 2 elements, but contains %d", len(argument.LogEvents))
   350  	}
   351  	if *argument.LogEvents[0].Message != logline+" 1" {
   352  		t.Errorf("Expected message to be %s but was %s", logline+" 1", *argument.LogEvents[0].Message)
   353  	}
   354  	if *argument.LogEvents[1].Message != logline+" 2" {
   355  		t.Errorf("Expected message to be %s but was %s", logline+" 2", *argument.LogEvents[0].Message)
   356  	}
   357  
   358  	stream.Log(&logger.Message{
   359  		Line:      []byte(logline + " 3"),
   360  		Timestamp: time.Time{},
   361  	})
   362  
   363  	ticks <- time.Time{}
   364  	argument = <-mockClient.putLogEventsArgument
   365  	if argument == nil {
   366  		t.Fatal("Expected non-nil PutLogEventsInput")
   367  	}
   368  	if len(argument.LogEvents) != 1 {
   369  		t.Errorf("Expected LogEvents to contain 1 elements, but contains %d", len(argument.LogEvents))
   370  	}
   371  	if *argument.LogEvents[0].Message != logline+" 3" {
   372  		t.Errorf("Expected message to be %s but was %s", logline+" 3", *argument.LogEvents[0].Message)
   373  	}
   374  
   375  	stream.Close()
   376  
   377  }
   378  
   379  func TestCollectBatchClose(t *testing.T) {
   380  	mockClient := newMockClient()
   381  	stream := &logStream{
   382  		client:        mockClient,
   383  		logGroupName:  groupName,
   384  		logStreamName: streamName,
   385  		sequenceToken: aws.String(sequenceToken),
   386  		messages:      make(chan *logger.Message),
   387  	}
   388  	mockClient.putLogEventsResult <- &putLogEventsResult{
   389  		successResult: &cloudwatchlogs.PutLogEventsOutput{
   390  			NextSequenceToken: aws.String(nextSequenceToken),
   391  		},
   392  	}
   393  	var ticks = make(chan time.Time)
   394  	newTicker = func(_ time.Duration) *time.Ticker {
   395  		return &time.Ticker{
   396  			C: ticks,
   397  		}
   398  	}
   399  
   400  	go stream.collectBatch()
   401  
   402  	stream.Log(&logger.Message{
   403  		Line:      []byte(logline),
   404  		Timestamp: time.Time{},
   405  	})
   406  
   407  	// no ticks
   408  	stream.Close()
   409  
   410  	argument := <-mockClient.putLogEventsArgument
   411  	if argument == nil {
   412  		t.Fatal("Expected non-nil PutLogEventsInput")
   413  	}
   414  	if len(argument.LogEvents) != 1 {
   415  		t.Errorf("Expected LogEvents to contain 1 element, but contains %d", len(argument.LogEvents))
   416  	}
   417  	if *argument.LogEvents[0].Message != logline {
   418  		t.Errorf("Expected message to be %s but was %s", logline, *argument.LogEvents[0].Message)
   419  	}
   420  }
   421  
   422  func TestCollectBatchLineSplit(t *testing.T) {
   423  	mockClient := newMockClient()
   424  	stream := &logStream{
   425  		client:        mockClient,
   426  		logGroupName:  groupName,
   427  		logStreamName: streamName,
   428  		sequenceToken: aws.String(sequenceToken),
   429  		messages:      make(chan *logger.Message),
   430  	}
   431  	mockClient.putLogEventsResult <- &putLogEventsResult{
   432  		successResult: &cloudwatchlogs.PutLogEventsOutput{
   433  			NextSequenceToken: aws.String(nextSequenceToken),
   434  		},
   435  	}
   436  	var ticks = make(chan time.Time)
   437  	newTicker = func(_ time.Duration) *time.Ticker {
   438  		return &time.Ticker{
   439  			C: ticks,
   440  		}
   441  	}
   442  
   443  	go stream.collectBatch()
   444  
   445  	longline := strings.Repeat("A", maximumBytesPerEvent)
   446  	stream.Log(&logger.Message{
   447  		Line:      []byte(longline + "B"),
   448  		Timestamp: time.Time{},
   449  	})
   450  
   451  	// no ticks
   452  	stream.Close()
   453  
   454  	argument := <-mockClient.putLogEventsArgument
   455  	if argument == nil {
   456  		t.Fatal("Expected non-nil PutLogEventsInput")
   457  	}
   458  	if len(argument.LogEvents) != 2 {
   459  		t.Errorf("Expected LogEvents to contain 2 elements, but contains %d", len(argument.LogEvents))
   460  	}
   461  	if *argument.LogEvents[0].Message != longline {
   462  		t.Errorf("Expected message to be %s but was %s", longline, *argument.LogEvents[0].Message)
   463  	}
   464  	if *argument.LogEvents[1].Message != "B" {
   465  		t.Errorf("Expected message to be %s but was %s", "B", *argument.LogEvents[1].Message)
   466  	}
   467  }
   468  
   469  func TestCollectBatchMaxEvents(t *testing.T) {
   470  	mockClient := newMockClientBuffered(1)
   471  	stream := &logStream{
   472  		client:        mockClient,
   473  		logGroupName:  groupName,
   474  		logStreamName: streamName,
   475  		sequenceToken: aws.String(sequenceToken),
   476  		messages:      make(chan *logger.Message),
   477  	}
   478  	mockClient.putLogEventsResult <- &putLogEventsResult{
   479  		successResult: &cloudwatchlogs.PutLogEventsOutput{
   480  			NextSequenceToken: aws.String(nextSequenceToken),
   481  		},
   482  	}
   483  	var ticks = make(chan time.Time)
   484  	newTicker = func(_ time.Duration) *time.Ticker {
   485  		return &time.Ticker{
   486  			C: ticks,
   487  		}
   488  	}
   489  
   490  	go stream.collectBatch()
   491  
   492  	line := "A"
   493  	for i := 0; i <= maximumLogEventsPerPut; i++ {
   494  		stream.Log(&logger.Message{
   495  			Line:      []byte(line),
   496  			Timestamp: time.Time{},
   497  		})
   498  	}
   499  
   500  	// no ticks
   501  	stream.Close()
   502  
   503  	argument := <-mockClient.putLogEventsArgument
   504  	if argument == nil {
   505  		t.Fatal("Expected non-nil PutLogEventsInput")
   506  	}
   507  	if len(argument.LogEvents) != maximumLogEventsPerPut {
   508  		t.Errorf("Expected LogEvents to contain %d elements, but contains %d", maximumLogEventsPerPut, len(argument.LogEvents))
   509  	}
   510  
   511  	argument = <-mockClient.putLogEventsArgument
   512  	if argument == nil {
   513  		t.Fatal("Expected non-nil PutLogEventsInput")
   514  	}
   515  	if len(argument.LogEvents) != 1 {
   516  		t.Errorf("Expected LogEvents to contain %d elements, but contains %d", 1, len(argument.LogEvents))
   517  	}
   518  }
   519  
   520  func TestCollectBatchMaxTotalBytes(t *testing.T) {
   521  	mockClient := newMockClientBuffered(1)
   522  	stream := &logStream{
   523  		client:        mockClient,
   524  		logGroupName:  groupName,
   525  		logStreamName: streamName,
   526  		sequenceToken: aws.String(sequenceToken),
   527  		messages:      make(chan *logger.Message),
   528  	}
   529  	mockClient.putLogEventsResult <- &putLogEventsResult{
   530  		successResult: &cloudwatchlogs.PutLogEventsOutput{
   531  			NextSequenceToken: aws.String(nextSequenceToken),
   532  		},
   533  	}
   534  	var ticks = make(chan time.Time)
   535  	newTicker = func(_ time.Duration) *time.Ticker {
   536  		return &time.Ticker{
   537  			C: ticks,
   538  		}
   539  	}
   540  
   541  	go stream.collectBatch()
   542  
   543  	longline := strings.Repeat("A", maximumBytesPerPut)
   544  	stream.Log(&logger.Message{
   545  		Line:      []byte(longline + "B"),
   546  		Timestamp: time.Time{},
   547  	})
   548  
   549  	// no ticks
   550  	stream.Close()
   551  
   552  	argument := <-mockClient.putLogEventsArgument
   553  	if argument == nil {
   554  		t.Fatal("Expected non-nil PutLogEventsInput")
   555  	}
   556  	bytes := 0
   557  	for _, event := range argument.LogEvents {
   558  		bytes += len(*event.Message)
   559  	}
   560  	if bytes > maximumBytesPerPut {
   561  		t.Errorf("Expected <= %d bytes but was %d", maximumBytesPerPut, bytes)
   562  	}
   563  
   564  	argument = <-mockClient.putLogEventsArgument
   565  	if len(argument.LogEvents) != 1 {
   566  		t.Errorf("Expected LogEvents to contain 1 elements, but contains %d", len(argument.LogEvents))
   567  	}
   568  	message := *argument.LogEvents[0].Message
   569  	if message[len(message)-1:] != "B" {
   570  		t.Errorf("Expected message to be %s but was %s", "B", message[len(message)-1:])
   571  	}
   572  }