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 }