github.com/prebid/prebid-server@v0.275.0/endpoints/events/event_test.go (about) 1 package events 2 3 import ( 4 "context" 5 "encoding/base64" 6 "encoding/json" 7 "errors" 8 "io" 9 "net/http" 10 "net/http/httptest" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/prebid/prebid-server/analytics" 16 "github.com/prebid/prebid-server/config" 17 "github.com/prebid/prebid-server/errortypes" 18 "github.com/prebid/prebid-server/metrics" 19 "github.com/prebid/prebid-server/stored_requests" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 // Mock Analytics Module 24 type eventsMockAnalyticsModule struct { 25 Fail bool 26 Error error 27 Invoked bool 28 } 29 30 func (e *eventsMockAnalyticsModule) LogAuctionObject(ao *analytics.AuctionObject) { 31 if e.Fail { 32 panic(e.Error) 33 } 34 return 35 } 36 37 func (e *eventsMockAnalyticsModule) LogVideoObject(vo *analytics.VideoObject) { 38 if e.Fail { 39 panic(e.Error) 40 } 41 return 42 } 43 44 func (e *eventsMockAnalyticsModule) LogCookieSyncObject(cso *analytics.CookieSyncObject) { 45 if e.Fail { 46 panic(e.Error) 47 } 48 return 49 } 50 51 func (e *eventsMockAnalyticsModule) LogSetUIDObject(so *analytics.SetUIDObject) { 52 if e.Fail { 53 panic(e.Error) 54 } 55 return 56 } 57 58 func (e *eventsMockAnalyticsModule) LogAmpObject(ao *analytics.AmpObject) { 59 if e.Fail { 60 panic(e.Error) 61 } 62 return 63 } 64 65 func (e *eventsMockAnalyticsModule) LogNotificationEventObject(ne *analytics.NotificationEvent) { 66 if e.Fail { 67 panic(e.Error) 68 } 69 e.Invoked = true 70 71 return 72 } 73 74 // Mock Account fetcher 75 var mockAccountData = map[string]json.RawMessage{ 76 "events_enabled": json.RawMessage(`{"events": {"enabled":true}}`), 77 "events_disabled": json.RawMessage(`{"events": {"enabled":false}}`), 78 "malformed_acct": json.RawMessage(`{"events": {"enabled":"invalid type"}}`), 79 } 80 81 type mockAccountsFetcher struct { 82 Fail bool 83 Error error 84 DurationMS int 85 } 86 87 func (maf mockAccountsFetcher) FetchAccount(ctx context.Context, defaultAccountJSON json.RawMessage, accountID string) (json.RawMessage, []error) { 88 if maf.DurationMS > 0 { 89 select { 90 case <-time.After(time.Duration(maf.DurationMS) * time.Millisecond): 91 break 92 case <-ctx.Done(): 93 return nil, []error{ctx.Err()} 94 } 95 } 96 97 if account, ok := mockAccountData[accountID]; ok { 98 return account, nil 99 } 100 101 if maf.Fail { 102 return nil, []error{maf.Error} 103 } 104 105 return nil, []error{stored_requests.NotFoundError{accountID, "Account"}} 106 } 107 108 // Tests 109 110 func TestShouldReturnBadRequestWhenTypeIsMissing(t *testing.T) { 111 112 // mock AccountsFetcher 113 mockAccountsFetcher := &mockAccountsFetcher{} 114 115 // mock PBS Analytics Module 116 mockAnalyticsModule := &eventsMockAnalyticsModule{ 117 Fail: false, 118 } 119 120 // mock config 121 cfg := &config.Configuration{ 122 AccountDefaults: config.Account{}, 123 } 124 125 // prepare 126 reqData := "" 127 128 req := httptest.NewRequest("GET", "/event?b=test", strings.NewReader(reqData)) 129 recorder := httptest.NewRecorder() 130 131 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 132 133 // execute 134 e(recorder, req, nil) 135 136 d, err := io.ReadAll(recorder.Result().Body) 137 if err != nil { 138 t.Fatal(err) 139 } 140 141 // validate 142 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with missing type parameter") 143 assert.Equal(t, "invalid request: parameter 't' is required\n", string(d)) 144 } 145 146 func TestShouldReturnBadRequestWhenTypeIsInvalid(t *testing.T) { 147 148 // mock AccountsFetcher 149 mockAccounts := &mockAccountsFetcher{} 150 151 // mock PBS Analytics Module 152 mockAnalyticsModule := &eventsMockAnalyticsModule{ 153 Fail: false, 154 } 155 156 // mock config 157 cfg := &config.Configuration{ 158 AccountDefaults: config.Account{}, 159 } 160 161 // prepare 162 reqData := "" 163 164 req := httptest.NewRequest("GET", "/event?t=test&b=t", strings.NewReader(reqData)) 165 recorder := httptest.NewRecorder() 166 167 e := NewEventEndpoint(cfg, mockAccounts, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 168 169 // execute 170 e(recorder, req, nil) 171 172 d, err := io.ReadAll(recorder.Result().Body) 173 if err != nil { 174 t.Fatal(err) 175 } 176 177 // validate 178 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid type parameter") 179 assert.Equal(t, "invalid request: unknown type: 'test'\n", string(d)) 180 } 181 182 func TestShouldReturnBadRequestWhenBidIdIsMissing(t *testing.T) { 183 184 // mock AccountsFetcher 185 mockAccountsFetcher := &mockAccountsFetcher{} 186 187 // mock PBS Analytics Module 188 mockAnalyticsModule := &eventsMockAnalyticsModule{ 189 Fail: false, 190 } 191 192 // mock config 193 cfg := &config.Configuration{ 194 AccountDefaults: config.Account{}, 195 } 196 197 // prepare 198 reqData := "" 199 200 req := httptest.NewRequest("GET", "/event?t=win", strings.NewReader(reqData)) 201 recorder := httptest.NewRecorder() 202 203 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 204 205 // execute 206 e(recorder, req, nil) 207 208 d, err := io.ReadAll(recorder.Result().Body) 209 if err != nil { 210 t.Fatal(err) 211 } 212 213 // validate 214 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with missing bidid parameter") 215 assert.Equal(t, "invalid request: parameter 'b' is required\n", string(d)) 216 } 217 218 func TestShouldReturnBadRequestWhenTimestampIsInvalid(t *testing.T) { 219 220 // mock AccountsFetcher 221 mockAccountsFetcher := &mockAccountsFetcher{} 222 223 // mock PBS Analytics Module 224 mockAnalyticsModule := &eventsMockAnalyticsModule{ 225 Fail: false, 226 } 227 228 // mock config 229 cfg := &config.Configuration{ 230 AccountDefaults: config.Account{}, 231 } 232 233 // prepare 234 reqData := "" 235 236 req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=q", strings.NewReader(reqData)) 237 recorder := httptest.NewRecorder() 238 239 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 240 241 // execute 242 e(recorder, req, nil) 243 244 d, err := io.ReadAll(recorder.Result().Body) 245 if err != nil { 246 t.Fatal(err) 247 } 248 249 // validate 250 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid timestamp parameter") 251 assert.Equal(t, "invalid request: invalid request: error parsing timestamp 'q'\n", string(d)) 252 } 253 254 func TestShouldReturnUnauthorizedWhenAccountIsMissing(t *testing.T) { 255 256 // mock AccountsFetcher 257 mockAccountsFetcher := &mockAccountsFetcher{} 258 259 // mock PBS Analytics Module 260 mockAnalyticsModule := &eventsMockAnalyticsModule{ 261 Fail: false, 262 } 263 264 // mock config 265 cfg := &config.Configuration{ 266 AccountDefaults: config.Account{}, 267 } 268 269 // prepare 270 reqData := "" 271 272 req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234", strings.NewReader(reqData)) 273 recorder := httptest.NewRecorder() 274 275 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 276 277 // execute 278 e(recorder, req, nil) 279 280 d, err := io.ReadAll(recorder.Result().Body) 281 if err != nil { 282 t.Fatal(err) 283 } 284 285 // validate 286 assert.Equal(t, 401, recorder.Result().StatusCode, "Expected 401 on request with missing account id parameter") 287 assert.Equal(t, "Account 'a' is required query parameter and can't be empty", string(d)) 288 } 289 290 func TestShouldReturnBadRequestWhenFormatValueIsInvalid(t *testing.T) { 291 292 // mock AccountsFetcher 293 mockAccountsFetcher := &mockAccountsFetcher{} 294 295 // mock PBS Analytics Module 296 mockAnalyticsModule := &eventsMockAnalyticsModule{ 297 Fail: false, 298 } 299 300 // mock config 301 cfg := &config.Configuration{ 302 AccountDefaults: config.Account{}, 303 } 304 305 // prepare 306 reqData := "" 307 308 req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=q", strings.NewReader(reqData)) 309 recorder := httptest.NewRecorder() 310 311 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 312 313 // execute 314 e(recorder, req, nil) 315 316 d, err := io.ReadAll(recorder.Result().Body) 317 if err != nil { 318 t.Fatal(err) 319 } 320 321 // validate 322 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid format parameter") 323 assert.Equal(t, "invalid request: unknown format: 'q'\n", string(d)) 324 } 325 326 func TestShouldReturnBadRequestWhenAnalyticsValueIsInvalid(t *testing.T) { 327 328 // mock AccountsFetcher 329 mockAccountsFetcher := &mockAccountsFetcher{} 330 331 // mock PBS Analytics Module 332 mockAnalyticsModule := &eventsMockAnalyticsModule{ 333 Fail: false, 334 } 335 336 // mock config 337 cfg := &config.Configuration{ 338 AccountDefaults: config.Account{}, 339 } 340 341 // prepare 342 reqData := "" 343 344 req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=4", strings.NewReader(reqData)) 345 recorder := httptest.NewRecorder() 346 347 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 348 349 // execute 350 e(recorder, req, nil) 351 352 d, err := io.ReadAll(recorder.Result().Body) 353 if err != nil { 354 t.Fatal(err) 355 } 356 357 // validate 358 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid analytics parameter") 359 assert.Equal(t, "invalid request: unknown analytics: '4'\n", string(d)) 360 } 361 362 func TestShouldNotPassEventToAnalyticsReporterWhenAccountNotFoundAndDefaultIsFalse(t *testing.T) { 363 364 // mock AccountsFetcher 365 mockAccountsFetcher := &mockAccountsFetcher{ 366 Fail: true, 367 Error: stored_requests.NotFoundError{ID: "testacc"}, 368 } 369 370 // mock PBS Analytics Module 371 mockAnalyticsModule := &eventsMockAnalyticsModule{ 372 Fail: false, 373 } 374 375 // mock config 376 cfg := &config.Configuration{ 377 AccountDefaults: config.Account{}, 378 } 379 380 // prepare 381 reqData := "" 382 383 req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=1&a=testacc", strings.NewReader(reqData)) 384 recorder := httptest.NewRecorder() 385 386 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 387 388 // execute 389 e(recorder, req, nil) 390 d, err := io.ReadAll(recorder.Result().Body) 391 if err != nil { 392 t.Fatal(err) 393 } 394 395 // validate 396 assert.Equal(t, 401, recorder.Result().StatusCode, "Expected 401 on account not found") 397 assert.Equal(t, "Account 'testacc' doesn't support events", string(d)) 398 } 399 400 func TestShouldReturnBadRequestWhenIntegrationValueIsInvalid(t *testing.T) { 401 // mock AccountsFetcher 402 mockAccountsFetcher := &mockAccountsFetcher{} 403 404 // mock PBS Analytics Module 405 mockAnalyticsModule := &eventsMockAnalyticsModule{ 406 Fail: false, 407 } 408 409 // mock config 410 cfg := &config.Configuration{ 411 AccountDefaults: config.Account{}, 412 } 413 414 // prepare 415 reqData := "" 416 417 req := httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=Te$tIntegrationType", strings.NewReader(reqData)) 418 recorder := httptest.NewRecorder() 419 420 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 421 422 // execute 423 e(recorder, req, nil) 424 425 d, err := io.ReadAll(recorder.Result().Body) 426 if err != nil { 427 t.Fatal(err) 428 } 429 430 // validate 431 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid integration type parameter") 432 assert.Equal(t, "invalid request: integration type can only contain numbers, letters and these characters '-', '_'\n", string(d)) 433 } 434 435 func TestShouldNotPassEventToAnalyticsReporterWhenAccountEventNotEnabled(t *testing.T) { 436 437 // mock AccountsFetcher 438 mockAccountsFetcher := &mockAccountsFetcher{ 439 Fail: false, 440 } 441 442 // mock PBS Analytics Module 443 mockAnalyticsModule := &eventsMockAnalyticsModule{ 444 Fail: false, 445 } 446 447 // mock config 448 cfg := &config.Configuration{ 449 AccountDefaults: config.Account{}, 450 } 451 cfg.MarshalAccountDefaults() 452 453 // prepare 454 reqData := "" 455 456 req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=1&a=events_disabled", strings.NewReader(reqData)) 457 recorder := httptest.NewRecorder() 458 459 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 460 461 // execute 462 e(recorder, req, nil) 463 d, err := io.ReadAll(recorder.Result().Body) 464 if err != nil { 465 t.Fatal(err) 466 } 467 468 // validate 469 assert.Equal(t, 401, recorder.Result().StatusCode, "Expected 401 on account with events disabled") 470 assert.Equal(t, "Account 'events_disabled' doesn't support events", string(d)) 471 } 472 473 func TestShouldPassEventToAnalyticsReporterWhenAccountEventEnabled(t *testing.T) { 474 475 // mock AccountsFetcher 476 mockAccountsFetcher := &mockAccountsFetcher{ 477 Fail: false, 478 } 479 480 // mock PBS Analytics Module 481 mockAnalyticsModule := &eventsMockAnalyticsModule{ 482 Fail: false, 483 } 484 485 // mock config 486 cfg := &config.Configuration{ 487 AccountDefaults: config.Account{}, 488 } 489 cfg.MarshalAccountDefaults() 490 491 // prepare 492 reqData := "" 493 494 req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=1&a=events_enabled", strings.NewReader(reqData)) 495 recorder := httptest.NewRecorder() 496 497 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 498 499 // execute 500 e(recorder, req, nil) 501 502 // validate 503 assert.Equal(t, 204, recorder.Result().StatusCode, "Expected 204 when account has events enabled") 504 assert.Equal(t, true, mockAnalyticsModule.Invoked) 505 } 506 507 func TestShouldNotPassEventToAnalyticsReporterWhenAnalyticsValueIsZero(t *testing.T) { 508 509 // mock AccountsFetcher 510 mockAccountsFetcher := &mockAccountsFetcher{ 511 Fail: false, 512 } 513 514 // mock PBS Analytics Module 515 mockAnalyticsModule := &eventsMockAnalyticsModule{ 516 Fail: false, 517 } 518 519 // mock config 520 cfg := &config.Configuration{ 521 AccountDefaults: config.Account{}, 522 } 523 cfg.MarshalAccountDefaults() 524 525 // prepare 526 reqData := "" 527 528 req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=b&x=0&a=events_enabled", strings.NewReader(reqData)) 529 recorder := httptest.NewRecorder() 530 531 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 532 533 // execute 534 e(recorder, req, nil) 535 536 // validate 537 assert.Equal(t, 204, recorder.Result().StatusCode) 538 assert.Equal(t, true, mockAnalyticsModule.Invoked != true) 539 } 540 541 func TestShouldRespondWithPixelAndContentTypeWhenRequestFormatIsImage(t *testing.T) { 542 543 // mock AccountsFetcher 544 mockAccountsFetcher := &mockAccountsFetcher{ 545 Fail: false, 546 } 547 548 // mock PBS Analytics Module 549 mockAnalyticsModule := &eventsMockAnalyticsModule{ 550 Fail: false, 551 } 552 553 // mock config 554 cfg := &config.Configuration{ 555 AccountDefaults: config.Account{}, 556 } 557 cfg.MarshalAccountDefaults() 558 559 // prepare 560 reqData := "" 561 562 req := httptest.NewRequest("GET", "/event?t=win&b=test&ts=1234&f=i&x=1&a=events_enabled", strings.NewReader(reqData)) 563 recorder := httptest.NewRecorder() 564 565 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 566 567 // execute 568 e(recorder, req, nil) 569 570 d, err := io.ReadAll(recorder.Result().Body) 571 if err != nil { 572 t.Fatal(err) 573 } 574 575 // validate 576 assert.Equal(t, 200, recorder.Result().StatusCode, "Expected 200 with tracking pixel when format is imp") 577 assert.Equal(t, true, mockAnalyticsModule.Invoked) 578 assert.Equal(t, "image/png", recorder.Header().Get("Content-Type")) 579 assert.Equal(t, "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABHNCSVQICAgIfAhkiAAAAA1JREFUCJljYGBgYAAAAAUAAYehTtQAAAAASUVORK5CYII=", base64.URLEncoding.EncodeToString(d)) 580 } 581 582 func TestShouldRespondWithNoContentWhenRequestFormatIsNotDefined(t *testing.T) { 583 584 // mock AccountsFetcher 585 mockAccountsFetcher := &mockAccountsFetcher{ 586 Fail: false, 587 } 588 589 // mock PBS Analytics Module 590 mockAnalyticsModule := &eventsMockAnalyticsModule{ 591 Fail: false, 592 } 593 594 // mock config 595 cfg := &config.Configuration{ 596 AccountDefaults: config.Account{}, 597 } 598 cfg.MarshalAccountDefaults() 599 600 // prepare 601 reqData := "" 602 603 req := httptest.NewRequest("GET", "/event?t=imp&b=test&ts=1234&x=1&a=events_enabled", strings.NewReader(reqData)) 604 recorder := httptest.NewRecorder() 605 606 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 607 608 // execute 609 e(recorder, req, nil) 610 611 d, err := io.ReadAll(recorder.Result().Body) 612 if err != nil { 613 t.Fatal(err) 614 } 615 616 // validate 617 assert.Equal(t, 204, recorder.Result().StatusCode, "Expected 200 with empty response") 618 assert.Equal(t, true, mockAnalyticsModule.Invoked) 619 assert.Equal(t, "", recorder.Header().Get("Content-Type")) 620 assert.Equal(t, 0, len(d)) 621 } 622 623 func TestShouldParseEventCorrectly(t *testing.T) { 624 625 tests := map[string]struct { 626 req *http.Request 627 expected *analytics.EventRequest 628 }{ 629 "one": { 630 req: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=intType", strings.NewReader("")), 631 expected: &analytics.EventRequest{ 632 Type: analytics.Win, 633 BidID: "bidId", 634 Timestamp: 1000, 635 Bidder: "bidder", 636 AccountID: "", 637 Format: analytics.Blank, 638 Analytics: analytics.Enabled, 639 Integration: "intType", 640 }, 641 }, 642 "two": { 643 req: httptest.NewRequest("GET", "/event?t=win&b=bidId&ts=0&a=accountId", strings.NewReader("")), 644 expected: &analytics.EventRequest{ 645 Type: analytics.Win, 646 BidID: "bidId", 647 Timestamp: 0, 648 Analytics: analytics.Enabled, 649 }, 650 }, 651 "three - vtype = start": { 652 req: httptest.NewRequest("GET", "/event?t=vast&vtype=start&b=bidId&ts=0&a=accountId", strings.NewReader("")), 653 expected: &analytics.EventRequest{ 654 Type: analytics.Vast, 655 VType: analytics.Start, 656 BidID: "bidId", 657 Timestamp: 0, 658 Analytics: analytics.Enabled, 659 }, 660 }, 661 } 662 663 for name, test := range tests { 664 t.Run(name, func(t *testing.T) { 665 666 // execute 667 er, errs := ParseEventRequest(test.req) 668 669 // validate 670 assert.Equal(t, 0, len(errs)) 671 assert.EqualValues(t, test.expected, er) 672 }) 673 } 674 } 675 676 func TestEventRequestToUrl(t *testing.T) { 677 externalUrl := "http://localhost:8000" 678 tests := map[string]struct { 679 er *analytics.EventRequest 680 want string 681 }{ 682 "one": { 683 er: &analytics.EventRequest{ 684 Type: analytics.Imp, 685 BidID: "bidid", 686 AccountID: "accountId", 687 Bidder: "bidder", 688 Timestamp: 1234567, 689 Format: analytics.Blank, 690 Analytics: analytics.Enabled, 691 }, 692 want: "http://localhost:8000/event?t=imp&b=bidid&a=accountId&bidder=bidder&f=b&ts=1234567&x=1", 693 }, 694 "two": { 695 er: &analytics.EventRequest{ 696 Type: analytics.Win, 697 BidID: "bidid", 698 AccountID: "accountId", 699 Bidder: "bidder", 700 Timestamp: 1234567, 701 Format: analytics.Image, 702 Analytics: analytics.Disabled, 703 }, 704 want: "http://localhost:8000/event?t=win&b=bidid&a=accountId&bidder=bidder&f=i&ts=1234567&x=0", 705 }, 706 "three": { 707 er: &analytics.EventRequest{ 708 Type: analytics.Win, 709 BidID: "bidid", 710 AccountID: "accountId", 711 Bidder: "bidder", 712 Timestamp: 1234567, 713 Format: analytics.Image, 714 Analytics: analytics.Disabled, 715 Integration: "integration", 716 }, 717 want: "http://localhost:8000/event?t=win&b=bidid&a=accountId&bidder=bidder&f=i&int=integration&ts=1234567&x=0", 718 }, 719 } 720 721 for name, test := range tests { 722 t.Run(name, func(t *testing.T) { 723 expected := EventRequestToUrl(externalUrl, test.er) 724 // validate 725 assert.Equal(t, test.want, expected) 726 }) 727 } 728 } 729 730 func TestReadIntegrationType(t *testing.T) { 731 testCases := []struct { 732 description string 733 givenHttpRequest *http.Request 734 expectedIntegrationType string 735 expectedError error 736 }{ 737 { 738 description: "Integration type in http request is valid, expect same integration time and no errors", 739 givenHttpRequest: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=TestIntegrationType", strings.NewReader("")), 740 expectedIntegrationType: "TestIntegrationType", 741 expectedError: nil, 742 }, 743 { 744 description: "Integration type in http request is too long, expect too long error", 745 givenHttpRequest: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=TestIntegrationTypeTooLongTestIntegrationTypeTooLongTestIntegrationType", strings.NewReader("")), 746 expectedError: errors.New("integration type length is too long"), 747 }, 748 { 749 description: "Integration type in http request contains invalid character, expect invalid character error", 750 givenHttpRequest: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=Te$tIntegrationType", strings.NewReader("")), 751 expectedError: errors.New("integration type can only contain numbers, letters and these characters '-', '_'"), 752 }, 753 } 754 755 for _, test := range testCases { 756 testEventRequest := &analytics.EventRequest{} 757 err := readIntegrationType(testEventRequest, test.givenHttpRequest) 758 if test.expectedError != nil { 759 assert.Equal(t, test.expectedError, err, test.description) 760 } else { 761 assert.Empty(t, err, test.description) 762 assert.Equalf(t, test.expectedIntegrationType, testEventRequest.Integration, test.description) 763 } 764 } 765 } 766 767 func TestShouldReturnBadRequestWhenVTypeIsInvalid(t *testing.T) { 768 769 reqData := "" 770 771 tests := []struct { 772 description string 773 req *http.Request 774 expectedStatusCode int 775 expectedStatus string 776 }{ 777 { 778 description: "vtype parameter is missing", 779 req: httptest.NewRequest("GET", "/event?t=vast&b=bidID", strings.NewReader(reqData)), 780 expectedStatusCode: 400, 781 expectedStatus: "invalid request: parameter 'vtype' is required\n", 782 }, 783 { 784 description: "invalid vtype parameter", 785 req: httptest.NewRequest("GET", "/event?t=vast&vtype=abc&b=bidID", strings.NewReader(reqData)), 786 expectedStatusCode: 400, 787 expectedStatus: "invalid request: unknown vtype: 'abc'\n", 788 }, 789 { 790 description: "vtype is passed when event != vast", 791 req: httptest.NewRequest("GET", "/event?t=win&vtype=startc&b=bidID", strings.NewReader(reqData)), 792 expectedStatusCode: 400, 793 expectedStatus: "invalid request: parameter 'vtype' is only required for t=vast\n", 794 }, 795 } 796 797 for _, test := range tests { 798 mockAccountsFetcher := &mockAccountsFetcher{} 799 800 mockAnalyticsModule := &eventsMockAnalyticsModule{ 801 Fail: false, 802 } 803 804 cfg := &config.Configuration{ 805 AccountDefaults: config.Account{}, 806 } 807 808 recorder := httptest.NewRecorder() 809 810 e := NewEventEndpoint(cfg, mockAccountsFetcher, mockAnalyticsModule, &metrics.MetricsEngineMock{}) 811 e(recorder, test.req, nil) 812 813 d, err := io.ReadAll(recorder.Result().Body) 814 if err != nil { 815 t.Fatal(err) 816 } 817 818 assert.Equal(t, test.expectedStatusCode, recorder.Result().StatusCode, test.description) 819 assert.Equal(t, test.expectedStatus, string(d), test.description) 820 821 } 822 } 823 824 func TestReadVType(t *testing.T) { 825 type args struct { 826 er *analytics.EventRequest 827 req *http.Request 828 } 829 tests := []struct { 830 name string 831 args args 832 expectedError error 833 expectedVType analytics.VastType 834 }{ 835 { 836 name: "vtype = start", 837 args: args{ 838 er: &analytics.EventRequest{ 839 Type: analytics.Vast, 840 }, 841 req: httptest.NewRequest("GET", "/event?t=vast&vtype=start&b=bidId&ts=0&a=accountId", strings.NewReader("")), 842 }, 843 expectedError: nil, 844 expectedVType: analytics.Start, 845 }, 846 { 847 name: "vtype = firstQuartile", 848 args: args{ 849 er: &analytics.EventRequest{ 850 Type: analytics.Vast, 851 }, 852 req: httptest.NewRequest("GET", "/event?t=vast&vtype=firstQuartile&b=bidId&ts=0&a=accountId", strings.NewReader("")), 853 }, 854 expectedError: nil, 855 expectedVType: analytics.FirstQuartile, 856 }, 857 { 858 name: "vtype = midPoint", 859 args: args{ 860 er: &analytics.EventRequest{ 861 Type: analytics.Vast, 862 }, 863 req: httptest.NewRequest("GET", "/event?t=vast&vtype=midPoint&b=bidId&ts=0&a=accountId", strings.NewReader("")), 864 }, 865 expectedError: nil, 866 expectedVType: analytics.MidPoint, 867 }, 868 { 869 name: "vtype = thirdQuartile", 870 args: args{ 871 er: &analytics.EventRequest{ 872 Type: analytics.Vast, 873 }, 874 req: httptest.NewRequest("GET", "/event?t=vast&vtype=thirdQuartile&b=bidId&ts=0&a=accountId", strings.NewReader("")), 875 }, 876 expectedError: nil, 877 expectedVType: analytics.ThirdQuartile, 878 }, 879 { 880 name: "vtype = complete", 881 args: args{ 882 er: &analytics.EventRequest{ 883 Type: analytics.Vast, 884 }, 885 req: httptest.NewRequest("GET", "/event?t=vast&vtype=complete&b=bidId&ts=0&a=accountId", strings.NewReader("")), 886 }, 887 expectedError: nil, 888 expectedVType: analytics.Complete, 889 }, 890 { 891 name: "unknown vtype", 892 args: args{ 893 er: &analytics.EventRequest{ 894 Type: analytics.Vast, 895 }, 896 req: httptest.NewRequest("GET", "/event?t=vast&vtype=test&b=bidId&ts=0&a=accountId", strings.NewReader("")), 897 }, 898 expectedError: &errortypes.BadInput{Message: "unknown vtype: 'test'"}, 899 expectedVType: "", 900 }, 901 } 902 for _, tt := range tests { 903 t.Run(tt.name, func(t *testing.T) { 904 err := readVType(tt.args.er, tt.args.req) 905 assert.Equal(t, tt.expectedError, err, tt.name) 906 assert.Equal(t, tt.expectedVType, tt.args.er.VType, tt.name) 907 }) 908 } 909 }