github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/datastream/stream_test.go (about) 1 package datastream 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "net/http" 8 "net/http/httptest" 9 "reflect" 10 "testing" 11 12 "github.com/akamai/AkamaiOPEN-edgegrid-golang/v2/pkg/tools" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func TestDs_GetStream(t *testing.T) { 18 tests := map[string]struct { 19 request GetStreamRequest 20 responseStatus int 21 responseBody string 22 expectedPath string 23 expectedResponse *DetailedStreamVersion 24 withError func(*testing.T, error) 25 }{ 26 "200 OK": { 27 request: GetStreamRequest{ 28 StreamID: 1, 29 }, 30 responseStatus: http.StatusOK, 31 responseBody: ` 32 { 33 "streamId":1, 34 "streamVersionId":2, 35 "streamName":"ds2-sample-name", 36 "datasets":[ 37 { 38 "datasetGroupName":"group_name_1", 39 "datasetGroupDescription":"group_desc_1", 40 "datasetFields":[ 41 { 42 "datasetFieldId":1000, 43 "datasetFieldName":"dataset_field_name_1", 44 "datasetFieldDescription":"dataset_field_desc_1", 45 "order":0 46 }, 47 { 48 "datasetFieldId":1002, 49 "datasetFieldName":"dataset_field_name_2", 50 "datasetFieldDescription":"dataset_field_desc_2", 51 "order":1 52 } 53 ] 54 }, 55 { 56 "datasetGroupName":"group_name_2", 57 "datasetFields":[ 58 { 59 "datasetFieldId":1082, 60 "datasetFieldName":"dataset_field_name_3", 61 "datasetFieldDescription":"dataset_field_desc_3", 62 "order":32 63 } 64 ] 65 } 66 ], 67 "connectors":[ 68 { 69 "connectorType":"S3", 70 "connectorId":13174, 71 "bucket":"amzdemods2", 72 "path":"/sample_path", 73 "compressLogs":true, 74 "connectorName":"aws_ds2_amz_demo", 75 "region":"us-east-1" 76 } 77 ], 78 "productName":"Adaptive Media Delivery", 79 "productId":"Adaptive_Media_Delivery", 80 "templateName":"EDGE_LOGS", 81 "config":{ 82 "delimiter":"SPACE", 83 "uploadFilePrefix":"ak", 84 "uploadFileSuffix":"ds", 85 "frequency":{ 86 "timeInSec":30 87 }, 88 "useStaticPublicIP":false, 89 "format":"STRUCTURED" 90 }, 91 "groupId":171647, 92 "groupName":"Akamai Data Delivery-P-132NZF456", 93 "contractId":"P-132NZF456", 94 "properties":[ 95 { 96 "propertyId":678154, 97 "propertyName":"amz.demo.com" 98 } 99 ], 100 "streamType":"RAW_LOGS", 101 "activationStatus":"ACTIVATED", 102 "createdBy":"sample_username", 103 "createdDate":"08-07-2021 06:00:27 GMT", 104 "modifiedBy":"sample_username2", 105 "modifiedDate":"08-07-2021 16:00:27 GMT", 106 "emailIds":"sample_username@akamai.com" 107 } 108 `, 109 expectedPath: "/datastream-config-api/v1/log/streams/1", 110 expectedResponse: &DetailedStreamVersion{ 111 ActivationStatus: ActivationStatusActivated, 112 Config: Config{ 113 Delimiter: DelimiterTypePtr(DelimiterTypeSpace), 114 Format: FormatTypeStructured, 115 Frequency: Frequency{ 116 TimeInSec: TimeInSec30, 117 }, 118 UploadFilePrefix: "ak", 119 UploadFileSuffix: "ds", 120 }, 121 Connectors: []ConnectorDetails{ 122 { 123 ConnectorID: 13174, 124 CompressLogs: true, 125 ConnectorName: "aws_ds2_amz_demo", 126 ConnectorType: ConnectorTypeS3, 127 Path: "/sample_path", 128 Bucket: "amzdemods2", 129 Region: "us-east-1", 130 }, 131 }, 132 ContractID: "P-132NZF456", 133 CreatedBy: "sample_username", 134 CreatedDate: "08-07-2021 06:00:27 GMT", 135 Datasets: []DataSets{ 136 { 137 DatasetGroupName: "group_name_1", 138 DatasetGroupDescription: "group_desc_1", 139 DatasetFields: []DatasetFields{ 140 { 141 DatasetFieldID: 1000, 142 DatasetFieldName: "dataset_field_name_1", 143 DatasetFieldDescription: "dataset_field_desc_1", 144 Order: 0, 145 }, 146 { 147 DatasetFieldID: 1002, 148 DatasetFieldName: "dataset_field_name_2", 149 DatasetFieldDescription: "dataset_field_desc_2", 150 Order: 1, 151 }, 152 }, 153 }, 154 { 155 DatasetGroupName: "group_name_2", 156 DatasetFields: []DatasetFields{ 157 { 158 DatasetFieldID: 1082, 159 DatasetFieldName: "dataset_field_name_3", 160 DatasetFieldDescription: "dataset_field_desc_3", 161 Order: 32, 162 }, 163 }, 164 }, 165 }, 166 EmailIDs: "sample_username@akamai.com", 167 GroupID: 171647, 168 GroupName: "Akamai Data Delivery-P-132NZF456", 169 ModifiedBy: "sample_username2", 170 ModifiedDate: "08-07-2021 16:00:27 GMT", 171 ProductID: "Adaptive_Media_Delivery", 172 ProductName: "Adaptive Media Delivery", 173 Properties: []Property{ 174 { 175 PropertyID: 678154, 176 PropertyName: "amz.demo.com", 177 }, 178 }, 179 StreamID: 1, 180 StreamName: "ds2-sample-name", 181 StreamType: StreamTypeRawLogs, 182 StreamVersionID: 2, 183 TemplateName: TemplateNameEdgeLogs, 184 }, 185 }, 186 "validation error": { 187 request: GetStreamRequest{}, 188 withError: func(t *testing.T, err error) { 189 want := ErrStructValidation 190 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 191 }, 192 }, 193 "400 bad request": { 194 request: GetStreamRequest{StreamID: 12}, 195 responseStatus: http.StatusBadRequest, 196 expectedPath: "/datastream-config-api/v1/log/streams/12", 197 responseBody: ` 198 { 199 "type": "bad-request", 200 "title": "Bad Request", 201 "detail": "bad request", 202 "instance": "82b67b97-d98d-4bee-ac1e-ef6eaf7cac82", 203 "statusCode": 400, 204 "errors": [ 205 { 206 "type": "bad-request", 207 "title": "Bad Request", 208 "detail": "Stream does not exist. Please provide valid stream." 209 } 210 ] 211 } 212 `, 213 withError: func(t *testing.T, err error) { 214 want := &Error{ 215 Type: "bad-request", 216 Title: "Bad Request", 217 Detail: "bad request", 218 Instance: "82b67b97-d98d-4bee-ac1e-ef6eaf7cac82", 219 StatusCode: http.StatusBadRequest, 220 Errors: []RequestErrors{ 221 { 222 Type: "bad-request", 223 Title: "Bad Request", 224 Detail: "Stream does not exist. Please provide valid stream.", 225 }, 226 }, 227 } 228 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 229 }, 230 }, 231 } 232 233 for name, test := range tests { 234 t.Run(name, func(t *testing.T) { 235 mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 236 assert.Equal(t, test.expectedPath, r.URL.String()) 237 assert.Equal(t, http.MethodGet, r.Method) 238 w.WriteHeader(test.responseStatus) 239 _, err := w.Write([]byte(test.responseBody)) 240 assert.NoError(t, err) 241 })) 242 client := mockAPIClient(t, mockServer) 243 result, err := client.GetStream(context.Background(), test.request) 244 if test.withError != nil { 245 test.withError(t, err) 246 return 247 } 248 require.NoError(t, err) 249 assert.Equal(t, test.expectedResponse, result) 250 }) 251 } 252 } 253 254 func TestDs_CreateStream(t *testing.T) { 255 createStreamRequest := CreateStreamRequest{ 256 StreamConfiguration: StreamConfiguration{ 257 ActivateNow: true, 258 Config: Config{ 259 Delimiter: DelimiterTypePtr(DelimiterTypeSpace), 260 Format: FormatTypeStructured, 261 Frequency: Frequency{TimeInSec: TimeInSec30}, 262 UploadFilePrefix: "logs", 263 UploadFileSuffix: "ak", 264 }, 265 Connectors: []AbstractConnector{ 266 &S3Connector{ 267 Path: "log/edgelogs/{ %Y/%m/%d }", 268 ConnectorName: "S3Destination", 269 Bucket: "datastream.akamai.com", 270 Region: "ap-south-1", 271 AccessKey: "AKIA6DK7TDQLVGZ3TYP1", 272 SecretAccessKey: "1T2ll1H4dXWx5itGhpc7FlSbvvOvky1098nTtEMg", 273 }, 274 }, 275 ContractID: "2-FGHIJ", 276 DatasetFieldIDs: []int{ 277 1002, 1005, 1006, 1008, 1009, 1011, 1012, 278 1013, 1014, 1015, 1016, 1017, 1101, 279 }, 280 EmailIDs: "useremail@akamai.com", 281 GroupID: tools.IntPtr(21484), 282 PropertyIDs: []int{123123, 123123}, 283 StreamName: "TestStream", 284 StreamType: StreamTypeRawLogs, 285 TemplateName: TemplateNameEdgeLogs, 286 }, 287 } 288 289 modifyRequest := func(r CreateStreamRequest, opt func(r *CreateStreamRequest)) CreateStreamRequest { 290 opt(&r) 291 return r 292 } 293 294 tests := map[string]struct { 295 request CreateStreamRequest 296 responseStatus int 297 responseBody string 298 expectedPath string 299 expectedBody string 300 expectedResponse *StreamUpdate 301 withError error 302 }{ 303 "202 Accepted": { 304 request: createStreamRequest, 305 responseStatus: http.StatusAccepted, 306 responseBody: ` 307 { 308 "streamVersionKey": { 309 "streamId": 7050, 310 "streamVersionId": 1 311 } 312 }`, 313 expectedPath: "/datastream-config-api/v1/log/streams", 314 expectedResponse: &StreamUpdate{ 315 StreamVersionKey: StreamVersionKey{ 316 StreamID: 7050, 317 StreamVersionID: 1, 318 }, 319 }, 320 expectedBody: ` 321 { 322 "streamName": "TestStream", 323 "activateNow": true, 324 "streamType": "RAW_LOGS", 325 "templateName": "EDGE_LOGS", 326 "groupId": 21484, 327 "contractId": "2-FGHIJ", 328 "emailIds": "useremail@akamai.com", 329 "propertyIds": [ 330 123123, 331 123123 332 ], 333 "datasetFieldIds": [ 334 1002, 335 1005, 336 1006, 337 1008, 338 1009, 339 1011, 340 1012, 341 1013, 342 1014, 343 1015, 344 1016, 345 1017, 346 1101 347 ], 348 "config": { 349 "uploadFilePrefix": "logs", 350 "uploadFileSuffix": "ak", 351 "delimiter": "SPACE", 352 "format": "STRUCTURED", 353 "frequency": { 354 "timeInSec": 30 355 } 356 }, 357 "connectors": [ 358 { 359 "path": "log/edgelogs/{ %Y/%m/%d }", 360 "connectorName": "S3Destination", 361 "bucket": "datastream.akamai.com", 362 "region": "ap-south-1", 363 "accessKey": "AKIA6DK7TDQLVGZ3TYP1", 364 "secretAccessKey": "1T2ll1H4dXWx5itGhpc7FlSbvvOvky1098nTtEMg", 365 "connectorType": "S3" 366 } 367 ] 368 }`, 369 }, 370 "validation error - empty request": { 371 request: CreateStreamRequest{}, 372 withError: ErrStructValidation, 373 }, 374 "validation error - empty connectors list": { 375 request: modifyRequest(createStreamRequest, func(r *CreateStreamRequest) { 376 r.StreamConfiguration.Connectors = []AbstractConnector{} 377 }), 378 withError: ErrStructValidation, 379 }, 380 "validation error - delimiter with JSON format": { 381 request: modifyRequest(createStreamRequest, func(r *CreateStreamRequest) { 382 r.StreamConfiguration.Config = Config{ 383 Delimiter: DelimiterTypePtr(DelimiterTypeSpace), 384 Format: FormatTypeJson, 385 Frequency: Frequency{TimeInSec: TimeInSec30}, 386 UploadFilePrefix: "logs", 387 UploadFileSuffix: "ak", 388 } 389 }), 390 withError: ErrStructValidation, 391 }, 392 "validation error - no delimiter with STRUCTURED format": { 393 request: modifyRequest(createStreamRequest, func(r *CreateStreamRequest) { 394 r.StreamConfiguration.Config = Config{ 395 Format: FormatTypeStructured, 396 Frequency: Frequency{TimeInSec: TimeInSec30}, 397 UploadFilePrefix: "logs", 398 UploadFileSuffix: "ak", 399 } 400 }), 401 withError: ErrStructValidation, 402 }, 403 "validation error - missing connector configuration fields": { 404 request: modifyRequest(createStreamRequest, func(r *CreateStreamRequest) { 405 r.StreamConfiguration.Connectors = []AbstractConnector{ 406 &S3Connector{ 407 Path: "log/edgelogs/{ %Y/%m/%d }", 408 ConnectorName: "S3Destination", 409 Bucket: "datastream.akamai.com", 410 Region: "ap-south-1", 411 }, 412 } 413 }), 414 withError: ErrStructValidation, 415 }, 416 "403 forbidden": { 417 request: createStreamRequest, 418 responseStatus: http.StatusForbidden, 419 responseBody: ` 420 { 421 "type": "forbidden", 422 "title": "Forbidden", 423 "detail": "forbidden", 424 "instance": "72a7654e-3f95-454f-a174-104bc946be52", 425 "statusCode": 403, 426 "errors": [ 427 { 428 "type": "forbidden", 429 "title": "Forbidden", 430 "detail": "User is not having access for the group. Access denied, please contact support." 431 } 432 ] 433 } 434 `, 435 expectedPath: "/datastream-config-api/v1/log/streams", 436 withError: &Error{ 437 Type: "forbidden", 438 Title: "Forbidden", 439 Detail: "forbidden", 440 Instance: "72a7654e-3f95-454f-a174-104bc946be52", 441 StatusCode: http.StatusForbidden, 442 Errors: []RequestErrors{ 443 { 444 Type: "forbidden", 445 Title: "Forbidden", 446 Detail: "User is not having access for the group. Access denied, please contact support.", 447 }, 448 }, 449 }, 450 }, 451 "400 bad request": { 452 request: createStreamRequest, 453 responseStatus: http.StatusBadRequest, 454 responseBody: ` 455 { 456 "type": "bad-request", 457 "title": "Bad Request", 458 "detail": "bad-request", 459 "instance": "d0d2497e-ed93-4685-b44c-93a8eb8f3dea", 460 "statusCode": 400, 461 "errors": [ 462 { 463 "type": "bad-request", 464 "title": "Bad Request", 465 "detail": "The credentials provided don’t give you write access to the bucket. Check your AWS credentials or bucket permissions in the S3 account and try again." 466 } 467 ] 468 } 469 `, 470 expectedPath: "/datastream-config-api/v1/log/streams", 471 withError: &Error{ 472 Type: "bad-request", 473 Title: "Bad Request", 474 Detail: "bad-request", 475 Instance: "d0d2497e-ed93-4685-b44c-93a8eb8f3dea", 476 StatusCode: http.StatusBadRequest, 477 Errors: []RequestErrors{ 478 { 479 Type: "bad-request", 480 Title: "Bad Request", 481 Detail: "The credentials provided don’t give you write access to the bucket. Check your AWS credentials or bucket permissions in the S3 account and try again.", 482 }, 483 }, 484 }, 485 }, 486 } 487 488 for name, test := range tests { 489 t.Run(name, func(t *testing.T) { 490 mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 491 assert.Equal(t, test.expectedPath, r.URL.String()) 492 assert.Equal(t, http.MethodPost, r.Method) 493 w.WriteHeader(test.responseStatus) 494 _, err := w.Write([]byte(test.responseBody)) 495 assert.NoError(t, err) 496 497 //check request body only if we aren't testing errors 498 if test.withError == nil { 499 var reqBody interface{} 500 err = json.NewDecoder(r.Body).Decode(&reqBody) 501 require.NoError(t, err, "Error while decoding request body") 502 503 var expectedBody interface{} 504 err = json.Unmarshal([]byte(test.expectedBody), &expectedBody) 505 require.NoError(t, err, "Error while parsing expected body to JSON") 506 507 assert.Equal(t, expectedBody, reqBody) 508 } 509 })) 510 client := mockAPIClient(t, mockServer) 511 result, err := client.CreateStream(context.Background(), test.request) 512 if test.withError != nil { 513 assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) 514 return 515 } 516 require.NoError(t, err) 517 assert.Equal(t, test.expectedResponse, result) 518 }) 519 } 520 } 521 522 func TestDs_UpdateStream(t *testing.T) { 523 updateRequest := UpdateStreamRequest{ 524 StreamID: 7050, 525 StreamConfiguration: StreamConfiguration{ 526 ActivateNow: true, 527 Config: Config{ 528 Delimiter: DelimiterTypePtr(DelimiterTypeSpace), 529 Format: "STRUCTURED", 530 Frequency: Frequency{TimeInSec: TimeInSec30}, 531 UploadFilePrefix: "logs", 532 UploadFileSuffix: "ak", 533 }, 534 Connectors: []AbstractConnector{}, 535 ContractID: "P-132NZF456", 536 DatasetFieldIDs: []int{1, 2, 3}, 537 EmailIDs: "test@aka.mai", 538 PropertyIDs: []int{123123, 123123}, 539 StreamName: "TestStream", 540 StreamType: "RAW_LOGS", 541 TemplateName: "EDGE_LOGS", 542 }, 543 } 544 545 modifyRequest := func(r UpdateStreamRequest, opt func(r *UpdateStreamRequest)) UpdateStreamRequest { 546 opt(&r) 547 return r 548 } 549 550 tests := map[string]struct { 551 request UpdateStreamRequest 552 responseStatus int 553 responseBody string 554 expectedPath string 555 expectedResponse *StreamUpdate 556 withError error 557 }{ 558 "202 Accepted": { 559 request: updateRequest, 560 responseStatus: http.StatusAccepted, 561 responseBody: ` 562 { 563 "streamVersionKey": { 564 "streamId": 7050, 565 "streamVersionId": 2 566 } 567 } 568 `, 569 expectedPath: "/datastream-config-api/v1/log/streams/7050", 570 expectedResponse: &StreamUpdate{ 571 StreamVersionKey: StreamVersionKey{ 572 StreamID: 7050, 573 StreamVersionID: 2, 574 }, 575 }, 576 }, 577 "validation error - empty request": { 578 request: UpdateStreamRequest{}, 579 withError: ErrStructValidation, 580 }, 581 "validation error - delimiter with JSON format": { 582 request: modifyRequest(updateRequest, func(r *UpdateStreamRequest) { 583 r.StreamConfiguration.Config = Config{ 584 Delimiter: DelimiterTypePtr(DelimiterTypeSpace), 585 Format: FormatTypeJson, 586 Frequency: Frequency{TimeInSec: TimeInSec30}, 587 UploadFilePrefix: "logs", 588 UploadFileSuffix: "ak", 589 } 590 }), 591 withError: ErrStructValidation, 592 }, 593 "validation error - no delimiter with STRUCTURED format": { 594 request: modifyRequest(updateRequest, func(r *UpdateStreamRequest) { 595 r.StreamConfiguration.Config = Config{ 596 Format: FormatTypeStructured, 597 Frequency: Frequency{TimeInSec: TimeInSec60}, 598 UploadFilePrefix: "logs", 599 UploadFileSuffix: "ak", 600 } 601 }), 602 withError: ErrStructValidation, 603 }, 604 "validation error - groupId modification": { 605 request: modifyRequest(updateRequest, func(r *UpdateStreamRequest) { 606 r.StreamConfiguration.GroupID = tools.IntPtr(1337) 607 }), 608 withError: ErrStructValidation, 609 }, 610 "validation error - missing contractId": { 611 request: modifyRequest(updateRequest, func(r *UpdateStreamRequest) { 612 r.StreamConfiguration.ContractID = "" 613 }), 614 withError: ErrStructValidation, 615 }, 616 "400 bad request": { 617 request: updateRequest, 618 responseStatus: http.StatusBadRequest, 619 responseBody: ` 620 { 621 "type": "bad-request", 622 "title": "Bad Request", 623 "detail": "bad request", 624 "instance": "a42cc1e6-fea4-4e3a-91ce-9da9819e089a", 625 "statusCode": 400, 626 "errors": [ 627 { 628 "type": "bad-request", 629 "title": "Bad Request", 630 "detail": "Stream does not exist. Please provide valid stream." 631 } 632 ] 633 } 634 `, 635 expectedPath: "/datastream-config-api/v1/log/streams/7050", 636 withError: &Error{ 637 Type: "bad-request", 638 Title: "Bad Request", 639 Detail: "bad request", 640 Instance: "a42cc1e6-fea4-4e3a-91ce-9da9819e089a", 641 StatusCode: http.StatusBadRequest, 642 Errors: []RequestErrors{ 643 { 644 Type: "bad-request", 645 Title: "Bad Request", 646 Detail: "Stream does not exist. Please provide valid stream.", 647 }, 648 }, 649 }, 650 }, 651 } 652 653 for name, test := range tests { 654 t.Run(name, func(t *testing.T) { 655 mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 656 assert.Equal(t, test.expectedPath, r.URL.String()) 657 assert.Equal(t, http.MethodPut, r.Method) 658 w.WriteHeader(test.responseStatus) 659 _, err := w.Write([]byte(test.responseBody)) 660 assert.NoError(t, err) 661 })) 662 client := mockAPIClient(t, mockServer) 663 result, err := client.UpdateStream(context.Background(), test.request) 664 if test.withError != nil { 665 assert.True(t, errors.Is(err, test.withError), "want: %s; got: %s", test.withError, err) 666 return 667 } 668 require.NoError(t, err) 669 assert.Equal(t, test.expectedResponse, result) 670 }) 671 } 672 } 673 674 func TestDs_DeleteStream(t *testing.T) { 675 tests := map[string]struct { 676 request DeleteStreamRequest 677 responseStatus int 678 responseBody string 679 expectedPath string 680 expectedResponse *DeleteStreamResponse 681 withError func(*testing.T, error) 682 }{ 683 "200 OK": { 684 request: DeleteStreamRequest{ 685 StreamID: 1, 686 }, 687 responseStatus: http.StatusOK, 688 responseBody: ` 689 { 690 "message": "Success" 691 } 692 `, 693 expectedPath: "/datastream-config-api/v1/log/streams/1", 694 expectedResponse: &DeleteStreamResponse{ 695 Message: "Success", 696 }, 697 }, 698 "validation error": { 699 request: DeleteStreamRequest{}, 700 withError: func(t *testing.T, err error) { 701 want := ErrStructValidation 702 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 703 }, 704 }, 705 "400 bad request": { 706 request: DeleteStreamRequest{StreamID: 12}, 707 responseStatus: http.StatusBadRequest, 708 expectedPath: "/datastream-config-api/v1/log/streams/12", 709 responseBody: ` 710 { 711 "type": "bad-request", 712 "title": "Bad Request", 713 "detail": "bad request", 714 "instance": "82b67b97-d98d-4bee-ac1e-ef6eaf7cac82", 715 "statusCode": 400, 716 "errors": [ 717 { 718 "type": "bad-request", 719 "title": "Bad Request", 720 "detail": "Stream does not exist. Please provide valid stream." 721 } 722 ] 723 } 724 `, 725 withError: func(t *testing.T, err error) { 726 want := &Error{ 727 Type: "bad-request", 728 Title: "Bad Request", 729 Detail: "bad request", 730 Instance: "82b67b97-d98d-4bee-ac1e-ef6eaf7cac82", 731 StatusCode: 400, 732 Errors: []RequestErrors{ 733 { 734 Type: "bad-request", 735 Title: "Bad Request", 736 Detail: "Stream does not exist. Please provide valid stream.", 737 }, 738 }, 739 } 740 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 741 }, 742 }, 743 } 744 745 for name, test := range tests { 746 t.Run(name, func(t *testing.T) { 747 mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 748 assert.Equal(t, test.expectedPath, r.URL.String()) 749 assert.Equal(t, http.MethodDelete, r.Method) 750 w.WriteHeader(test.responseStatus) 751 _, err := w.Write([]byte(test.responseBody)) 752 assert.NoError(t, err) 753 })) 754 client := mockAPIClient(t, mockServer) 755 result, err := client.DeleteStream(context.Background(), test.request) 756 if test.withError != nil { 757 test.withError(t, err) 758 return 759 } 760 require.NoError(t, err) 761 assert.Equal(t, test.expectedResponse, result) 762 }) 763 } 764 } 765 766 func TestDs_Connectors(t *testing.T) { 767 tests := map[string]struct { 768 connector AbstractConnector 769 expectedJSON string 770 }{ 771 "S3Connector": { 772 connector: &S3Connector{ 773 Path: "testPath", 774 ConnectorName: "testConnectorName", 775 Bucket: "testBucket", 776 Region: "testRegion", 777 AccessKey: "testAccessKey", 778 SecretAccessKey: "testSecretKey", 779 }, 780 expectedJSON: ` 781 [{ 782 "path": "testPath", 783 "connectorName": "testConnectorName", 784 "bucket": "testBucket", 785 "region": "testRegion", 786 "accessKey": "testAccessKey", 787 "secretAccessKey": "testSecretKey", 788 "connectorType": "S3" 789 }] 790 `, 791 }, 792 "AzureConnector": { 793 connector: &AzureConnector{ 794 AccountName: "testAccountName", 795 AccessKey: "testAccessKey", 796 ConnectorName: "testConnectorName", 797 ContainerName: "testContainerName", 798 Path: "testPath", 799 }, 800 expectedJSON: ` 801 [{ 802 "accountName": "testAccountName", 803 "accessKey": "testAccessKey", 804 "connectorName": "testConnectorName", 805 "containerName": "testContainerName", 806 "path": "testPath", 807 "connectorType": "AZURE" 808 }] 809 `, 810 }, 811 "DatadogConnector": { 812 connector: &DatadogConnector{ 813 Service: "testService", 814 AuthToken: "testAuthToken", 815 ConnectorName: "testConnectorName", 816 URL: "testURL", 817 Source: "testSource", 818 Tags: "testTags", 819 CompressLogs: false, 820 }, 821 expectedJSON: ` 822 [{ 823 "service": "testService", 824 "authToken": "testAuthToken", 825 "connectorName": "testConnectorName", 826 "url": "testURL", 827 "source": "testSource", 828 "tags": "testTags", 829 "connectorType": "DATADOG", 830 "compressLogs": false 831 }] 832 `, 833 }, 834 "SplunkConnector": { 835 connector: &SplunkConnector{ 836 ConnectorName: "testConnectorName", 837 URL: "testURL", 838 EventCollectorToken: "testEventCollector", 839 CompressLogs: true, 840 CustomHeaderName: "custom-header", 841 CustomHeaderValue: "custom-header-value", 842 }, 843 expectedJSON: ` 844 [{ 845 "connectorName": "testConnectorName", 846 "url": "testURL", 847 "eventCollectorToken": "testEventCollector", 848 "connectorType": "SPLUNK", 849 "compressLogs": true, 850 "customHeaderName": "custom-header", 851 "customHeaderValue": "custom-header-value" 852 }] 853 `, 854 }, 855 "GCSConnector": { 856 connector: &GCSConnector{ 857 ConnectorName: "testConnectorName", 858 Bucket: "testBucket", 859 Path: "testPath", 860 ProjectID: "testProjectID", 861 ServiceAccountName: "testServiceAccountName", 862 PrivateKey: "testPrivateKey", 863 }, 864 expectedJSON: ` 865 [{ 866 "connectorType": "GCS", 867 "connectorName": "testConnectorName", 868 "bucket": "testBucket", 869 "path": "testPath", 870 "projectId": "testProjectID", 871 "serviceAccountName": "testServiceAccountName", 872 "privateKey": "testPrivateKey" 873 }] 874 `, 875 }, 876 "CustomHTTPSConnector": { 877 connector: &CustomHTTPSConnector{ 878 AuthenticationType: AuthenticationTypeBasic, 879 ConnectorName: "testConnectorName", 880 URL: "testURL", 881 UserName: "testUserName", 882 Password: "testPassword", 883 CompressLogs: true, 884 CustomHeaderName: "custom-header", 885 CustomHeaderValue: "custom-header-value", 886 ContentType: "application/json", 887 }, 888 expectedJSON: ` 889 [{ 890 "authenticationType": "BASIC", 891 "connectorName": "testConnectorName", 892 "url": "testURL", 893 "userName": "testUserName", 894 "password": "testPassword", 895 "connectorType": "HTTPS", 896 "compressLogs": true, 897 "customHeaderName": "custom-header", 898 "customHeaderValue": "custom-header-value", 899 "contentType": "application/json" 900 }] 901 `, 902 }, 903 "SumoLogicConnector": { 904 connector: &SumoLogicConnector{ 905 ConnectorName: "testConnectorName", 906 Endpoint: "testEndpoint", 907 CollectorCode: "testCollectorCode", 908 CompressLogs: true, 909 CustomHeaderName: "custom-header", 910 CustomHeaderValue: "custom-header-value", 911 ContentType: "application/json", 912 }, 913 expectedJSON: ` 914 [{ 915 "connectorType": "SUMO_LOGIC", 916 "connectorName": "testConnectorName", 917 "endpoint": "testEndpoint", 918 "collectorCode": "testCollectorCode", 919 "compressLogs": true, 920 "customHeaderName": "custom-header", 921 "customHeaderValue": "custom-header-value", 922 "contentType": "application/json" 923 }] 924 `, 925 }, 926 "OracleCloudStorageConnector": { 927 connector: &OracleCloudStorageConnector{ 928 AccessKey: "testAccessKey", 929 ConnectorName: "testConnectorName", 930 Path: "testPath", 931 Bucket: "testBucket", 932 Region: "testRegion", 933 SecretAccessKey: "testSecretAccessKey", 934 Namespace: "testNamespace", 935 }, 936 expectedJSON: ` 937 [{ 938 "accessKey": "testAccessKey", 939 "connectorName": "testConnectorName", 940 "path": "testPath", 941 "bucket": "testBucket", 942 "region": "testRegion", 943 "secretAccessKey": "testSecretAccessKey", 944 "connectorType": "Oracle_Cloud_Storage", 945 "namespace": "testNamespace" 946 }] 947 `, 948 }, 949 "LogglyConnector": { 950 connector: &LogglyConnector{ 951 ConnectorName: "testConnectorName", 952 Endpoint: "testEndpoint", 953 AuthToken: "testAuthToken", 954 Tags: "testTags", 955 ContentType: "testContentType", 956 CustomHeaderName: "testCustomHeaderName", 957 CustomHeaderValue: "testCustomHeaderValue", 958 }, 959 expectedJSON: ` 960 [{ 961 "connectorType": "LOGGLY", 962 "connectorName": "testConnectorName", 963 "endpoint": "testEndpoint", 964 "authToken": "testAuthToken", 965 "tags": "testTags", 966 "contentType": "testContentType", 967 "customHeaderName": "testCustomHeaderName", 968 "customHeaderValue": "testCustomHeaderValue" 969 }] 970 `, 971 }, 972 "NewRelicConnector": { 973 connector: &NewRelicConnector{ 974 ConnectorName: "testConnectorName", 975 Endpoint: "testEndpoint", 976 AuthToken: "testAuthToken", 977 ContentType: "testContentType", 978 CustomHeaderName: "testCustomHeaderName", 979 CustomHeaderValue: "testCustomHeaderValue", 980 }, 981 expectedJSON: ` 982 [{ 983 "connectorType": "NEWRELIC", 984 "connectorName": "testConnectorName", 985 "endpoint": "testEndpoint", 986 "authToken": "testAuthToken", 987 "contentType": "testContentType", 988 "customHeaderName": "testCustomHeaderName", 989 "customHeaderValue": "testCustomHeaderValue" 990 }] 991 `, 992 }, 993 "ElasticsearchConnector": { 994 connector: &ElasticsearchConnector{ 995 ConnectorName: "testConnectorName", 996 Endpoint: "testEndpoint", 997 IndexName: "testIndexName", 998 UserName: "testUserName", 999 Password: "testPassword", 1000 ContentType: "testContentType", 1001 CustomHeaderName: "testCustomHeaderName", 1002 CustomHeaderValue: "testCustomHeaderValue", 1003 TLSHostname: "testTLSHostname", 1004 CACert: "testCACert", 1005 ClientCert: "testClientCert", 1006 ClientKey: "testClientKey", 1007 }, 1008 expectedJSON: ` 1009 [{ 1010 "connectorType": "ELASTICSEARCH", 1011 "connectorName": "testConnectorName", 1012 "endpoint": "testEndpoint", 1013 "indexName": "testIndexName", 1014 "userName": "testUserName", 1015 "password": "testPassword", 1016 "contentType": "testContentType", 1017 "customHeaderName": "testCustomHeaderName", 1018 "customHeaderValue": "testCustomHeaderValue", 1019 "tlsHostname": "testTLSHostname", 1020 "caCert": "testCACert", 1021 "clientCert": "testClientCert", 1022 "clientKey": "testClientKey" 1023 }] 1024 `, 1025 }, 1026 } 1027 1028 request := CreateStreamRequest{ 1029 StreamConfiguration: StreamConfiguration{ 1030 ActivateNow: true, 1031 Config: Config{ 1032 Delimiter: DelimiterTypePtr(DelimiterTypeSpace), 1033 Format: FormatTypeStructured, 1034 Frequency: Frequency{TimeInSec: TimeInSec30}, 1035 UploadFilePrefix: "logs", 1036 UploadFileSuffix: "ak", 1037 }, 1038 Connectors: nil, 1039 ContractID: "P-132NZF456", 1040 DatasetFieldIDs: []int{1, 2, 3}, 1041 EmailIDs: "test@aka.mai", 1042 GroupID: tools.IntPtr(123231), 1043 PropertyIDs: []int{123123, 123123}, 1044 StreamName: "TestStream", 1045 StreamType: StreamTypeRawLogs, 1046 TemplateName: TemplateNameEdgeLogs, 1047 }, 1048 } 1049 1050 for name, test := range tests { 1051 t.Run(name, func(t *testing.T) { 1052 request.StreamConfiguration.Connectors = []AbstractConnector{test.connector} 1053 1054 mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1055 var connectorMap map[string]interface{} 1056 err := json.NewDecoder(r.Body).Decode(&connectorMap) 1057 require.NoError(t, err) 1058 1059 var expectedMap interface{} 1060 err = json.Unmarshal([]byte(test.expectedJSON), &expectedMap) 1061 require.NoError(t, err) 1062 1063 res := reflect.DeepEqual(expectedMap, connectorMap["connectors"]) 1064 assert.True(t, res) 1065 })) 1066 1067 client := mockAPIClient(t, mockServer) 1068 _, _ = client.CreateStream(context.Background(), request) 1069 }) 1070 } 1071 } 1072 1073 type mockConnector struct { 1074 Called bool 1075 } 1076 1077 func (c *mockConnector) SetConnectorType() { 1078 c.Called = true 1079 } 1080 1081 func (c *mockConnector) Validate() error { 1082 return nil 1083 } 1084 1085 func TestDs_setConnectorTypes(t *testing.T) { 1086 mockConnector := mockConnector{Called: false} 1087 1088 request := CreateStreamRequest{ 1089 StreamConfiguration: StreamConfiguration{ 1090 ActivateNow: true, 1091 Config: Config{ 1092 Delimiter: DelimiterTypePtr(DelimiterTypeSpace), 1093 Format: FormatTypeStructured, 1094 Frequency: Frequency{TimeInSec: TimeInSec30}, 1095 UploadFilePrefix: "logs", 1096 UploadFileSuffix: "ak", 1097 }, 1098 Connectors: []AbstractConnector{ 1099 &mockConnector, 1100 }, 1101 ContractID: "P-132NZF456", 1102 DatasetFieldIDs: []int{1, 2, 3}, 1103 EmailIDs: "test@aka.mai", 1104 GroupID: tools.IntPtr(123231), 1105 PropertyIDs: []int{123123, 123123}, 1106 StreamName: "TestStream", 1107 StreamType: StreamTypeRawLogs, 1108 TemplateName: TemplateNameEdgeLogs, 1109 }, 1110 } 1111 1112 mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1113 w.WriteHeader(http.StatusAccepted) 1114 _, err := w.Write([]byte("{}")) 1115 require.NoError(t, err) 1116 })) 1117 client := mockAPIClient(t, mockServer) 1118 _, err := client.CreateStream(context.Background(), request) 1119 require.NoError(t, err) 1120 1121 assert.True(t, mockConnector.Called) 1122 } 1123 1124 func TestDs_ListStreams(t *testing.T) { 1125 tests := map[string]struct { 1126 request ListStreamsRequest 1127 responseStatus int 1128 responseBody string 1129 expectedPath string 1130 expectedResponse []StreamDetails 1131 withError func(*testing.T, error) 1132 }{ 1133 "200 OK": { 1134 request: ListStreamsRequest{}, 1135 responseStatus: http.StatusOK, 1136 responseBody: ` 1137 [ 1138 { 1139 "streamId": 1, 1140 "streamName": "Stream1", 1141 "streamVersionId": 2, 1142 "createdBy": "user1", 1143 "createdDate": "14-07-2020 07:07:40 GMT", 1144 "currentVersionId": 2, 1145 "archived": false, 1146 "activationStatus": "DEACTIVATED", 1147 "groupId": 1234, 1148 "groupName": "Default Group", 1149 "contractId": "1-ABCDE", 1150 "connectors": "S3-S1", 1151 "streamTypeName": "Logs - Raw", 1152 "properties": [ 1153 { 1154 "propertyId": 13371337, 1155 "propertyName": "property_name_1" 1156 } 1157 ], 1158 "errors": [ 1159 { 1160 "type": "ACTIVATION_ERROR", 1161 "title": "Activation/Deactivation Error", 1162 "detail": "Contact technical support." 1163 } 1164 ] 1165 }, 1166 { 1167 "streamId": 2, 1168 "streamName": "Stream2", 1169 "streamVersionId": 3, 1170 "createdBy": "user2", 1171 "createdDate": "24-07-2020 07:07:40 GMT", 1172 "currentVersionId": 3, 1173 "archived": true, 1174 "activationStatus": "ACTIVATED", 1175 "groupId": 4321, 1176 "groupName": "Default Group", 1177 "contractId": "2-ABCDE", 1178 "connectors": "S3-S2", 1179 "streamTypeName": "Logs - Raw", 1180 "properties": [ 1181 { 1182 "propertyId": 23372337, 1183 "propertyName": "property_name_2" 1184 }, 1185 { 1186 "propertyId": 33373337, 1187 "propertyName": "property_name_3" 1188 } 1189 ] 1190 } 1191 ] 1192 `, 1193 expectedPath: "/datastream-config-api/v1/log/streams", 1194 expectedResponse: []StreamDetails{ 1195 { 1196 ActivationStatus: ActivationStatusDeactivated, 1197 Archived: false, 1198 Connectors: "S3-S1", 1199 ContractID: "1-ABCDE", 1200 CreatedBy: "user1", 1201 CreatedDate: "14-07-2020 07:07:40 GMT", 1202 CurrentVersionID: 2, 1203 Errors: []Errors{ 1204 { 1205 Detail: "Contact technical support.", 1206 Title: "Activation/Deactivation Error", 1207 Type: "ACTIVATION_ERROR", 1208 }, 1209 }, 1210 GroupID: 1234, 1211 GroupName: "Default Group", 1212 Properties: []Property{ 1213 { 1214 PropertyID: 13371337, 1215 PropertyName: "property_name_1", 1216 }, 1217 }, 1218 StreamID: 1, 1219 StreamName: "Stream1", 1220 StreamTypeName: "Logs - Raw", 1221 StreamVersionID: 2, 1222 }, 1223 { 1224 ActivationStatus: ActivationStatusActivated, 1225 Archived: true, 1226 Connectors: "S3-S2", 1227 ContractID: "2-ABCDE", 1228 CreatedBy: "user2", 1229 CreatedDate: "24-07-2020 07:07:40 GMT", 1230 CurrentVersionID: 3, 1231 Errors: nil, 1232 GroupID: 4321, 1233 GroupName: "Default Group", 1234 Properties: []Property{ 1235 { 1236 PropertyID: 23372337, 1237 PropertyName: "property_name_2", 1238 }, 1239 { 1240 PropertyID: 33373337, 1241 PropertyName: "property_name_3", 1242 }, 1243 }, 1244 StreamID: 2, 1245 StreamName: "Stream2", 1246 StreamTypeName: "Logs - Raw", 1247 StreamVersionID: 3, 1248 }, 1249 }, 1250 }, 1251 "200 OK - with groupId": { 1252 request: ListStreamsRequest{ 1253 GroupID: tools.IntPtr(1234), 1254 }, 1255 responseStatus: http.StatusOK, 1256 responseBody: ` 1257 [ 1258 { 1259 "streamId": 2, 1260 "streamName": "Stream2", 1261 "streamVersionId": 3, 1262 "createdBy": "user2", 1263 "createdDate": "24-07-2020 07:07:40 GMT", 1264 "currentVersionId": 3, 1265 "archived": true, 1266 "activationStatus": "ACTIVATED", 1267 "groupId": 1234, 1268 "groupName": "Default Group", 1269 "contractId": "2-ABCDE", 1270 "connectors": "S3-S2", 1271 "streamTypeName": "Logs - Raw", 1272 "properties": [ 1273 { 1274 "propertyId": 23372337, 1275 "propertyName": "property_name_2" 1276 }, 1277 { 1278 "propertyId": 33373337, 1279 "propertyName": "property_name_3" 1280 } 1281 ] 1282 } 1283 ] 1284 `, 1285 expectedPath: "/datastream-config-api/v1/log/streams?groupId=1234", 1286 expectedResponse: []StreamDetails{ 1287 { 1288 ActivationStatus: ActivationStatusActivated, 1289 Archived: true, 1290 Connectors: "S3-S2", 1291 ContractID: "2-ABCDE", 1292 CreatedBy: "user2", 1293 CreatedDate: "24-07-2020 07:07:40 GMT", 1294 CurrentVersionID: 3, 1295 Errors: nil, 1296 GroupID: 1234, 1297 GroupName: "Default Group", 1298 Properties: []Property{ 1299 { 1300 PropertyID: 23372337, 1301 PropertyName: "property_name_2", 1302 }, 1303 { 1304 PropertyID: 33373337, 1305 PropertyName: "property_name_3", 1306 }, 1307 }, 1308 StreamID: 2, 1309 StreamName: "Stream2", 1310 StreamTypeName: "Logs - Raw", 1311 StreamVersionID: 3, 1312 }, 1313 }, 1314 }, 1315 "400 bad request": { 1316 request: ListStreamsRequest{}, 1317 responseStatus: http.StatusBadRequest, 1318 expectedPath: "/datastream-config-api/v1/log/streams", 1319 responseBody: ` 1320 { 1321 "type": "bad-request", 1322 "title": "Bad Request", 1323 "detail": "bad request", 1324 "instance": "82b67b97-d98d-4bee-ac1e-ef6eaf7cac82", 1325 "statusCode": 400, 1326 "errors": [ 1327 { 1328 "type": "bad-request", 1329 "title": "Bad Request", 1330 "detail": "Stream does not exist. Please provide valid stream." 1331 } 1332 ] 1333 } 1334 `, 1335 withError: func(t *testing.T, err error) { 1336 want := &Error{ 1337 Type: "bad-request", 1338 Title: "Bad Request", 1339 Detail: "bad request", 1340 Instance: "82b67b97-d98d-4bee-ac1e-ef6eaf7cac82", 1341 StatusCode: http.StatusBadRequest, 1342 Errors: []RequestErrors{ 1343 { 1344 Type: "bad-request", 1345 Title: "Bad Request", 1346 Detail: "Stream does not exist. Please provide valid stream.", 1347 }, 1348 }, 1349 } 1350 assert.True(t, errors.Is(err, want), "want: %s; got: %s", want, err) 1351 }, 1352 }, 1353 } 1354 1355 for name, test := range tests { 1356 t.Run(name, func(t *testing.T) { 1357 mockServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1358 assert.Equal(t, test.expectedPath, r.URL.String()) 1359 assert.Equal(t, http.MethodGet, r.Method) 1360 w.WriteHeader(test.responseStatus) 1361 _, err := w.Write([]byte(test.responseBody)) 1362 assert.NoError(t, err) 1363 })) 1364 client := mockAPIClient(t, mockServer) 1365 result, err := client.ListStreams(context.Background(), test.request) 1366 if test.withError != nil { 1367 test.withError(t, err) 1368 return 1369 } 1370 require.NoError(t, err) 1371 assert.Equal(t, test.expectedResponse, result) 1372 }) 1373 } 1374 }