github.com/prebid/prebid-server/v2@v2.18.0/endpoints/events/vtrack_test.go (about) 1 package events 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "errors" 8 "fmt" 9 "io" 10 "net/http" 11 "net/http/httptest" 12 "strings" 13 "testing" 14 15 "github.com/prebid/prebid-server/v2/config" 16 "github.com/prebid/prebid-server/v2/openrtb_ext" 17 "github.com/prebid/prebid-server/v2/prebid_cache_client" 18 "github.com/prebid/prebid-server/v2/stored_requests" 19 "github.com/prebid/prebid-server/v2/util/jsonutil" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 const ( 24 maxSize = 1024 * 256 25 26 vastXmlWithImpressionWithContent = "<VAST version=\"3.0\"><Ad><Wrapper><AdSystem>prebid.org wrapper</AdSystem><VASTAdTagURI><![CDATA[adm2]]></VASTAdTagURI><Impression>content</Impression><Creatives></Creatives></Wrapper></Ad></VAST>" 27 vastXmlWithImpressionWithoutContent = "<VAST version=\"3.0\"><Ad><Wrapper><AdSystem>prebid.org wrapper</AdSystem><VASTAdTagURI><![CDATA[adm2]]></VASTAdTagURI><Impression></Impression><Creatives></Creatives></Wrapper></Ad></VAST>" 28 vastXmlWithoutImpression = "<VAST version=\"3.0\"><Ad><Wrapper><AdSystem>prebid.org wrapper</AdSystem><VASTAdTagURI><![CDATA[adm2]]></VASTAdTagURI><Creatives></Creatives></Wrapper></Ad></VAST>" 29 ) 30 31 // Mock pbs cache client 32 type vtrackMockCacheClient struct { 33 Fail bool 34 Error error 35 Uuids []string 36 Values []prebid_cache_client.Cacheable 37 } 38 39 func (m *vtrackMockCacheClient) PutJson(ctx context.Context, values []prebid_cache_client.Cacheable) ([]string, []error) { 40 if m.Fail { 41 return []string{}, []error{m.Error} 42 } 43 m.Values = values 44 return m.Uuids, []error{} 45 } 46 func (m *vtrackMockCacheClient) GetExtCacheData() (scheme string, host string, path string) { 47 return 48 } 49 50 // Test 51 func TestShouldRespondWithBadRequestWhenAccountParameterIsMissing(t *testing.T) { 52 // mock pbs cache client 53 mockCacheClient := &vtrackMockCacheClient{} 54 55 // mock AccountsFetcher 56 mockAccountsFetcher := &mockAccountsFetcher{} 57 58 // mock config 59 cfg := &config.Configuration{ 60 AccountDefaults: config.Account{}, 61 } 62 cfg.MarshalAccountDefaults() 63 64 // prepare 65 reqData := "" 66 67 req := httptest.NewRequest("POST", "/vtrack", strings.NewReader(reqData)) 68 recorder := httptest.NewRecorder() 69 70 e := vtrackEndpoint{ 71 Cfg: cfg, 72 BidderInfos: nil, 73 Cache: mockCacheClient, 74 Accounts: mockAccountsFetcher, 75 normalizeBidderName: openrtb_ext.NormalizeBidderName, 76 } 77 78 // execute 79 e.Handle(recorder, req, nil) 80 81 d, err := io.ReadAll(recorder.Result().Body) 82 if err != nil { 83 t.Fatal(err) 84 } 85 86 // validate 87 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with missing account parameter") 88 assert.Equal(t, "Account 'a' is required query parameter and can't be empty", string(d)) 89 } 90 91 func TestShouldRespondWithBadRequestWhenRequestBodyIsEmpty(t *testing.T) { 92 // mock pbs cache client 93 mockCacheClient := &vtrackMockCacheClient{} 94 95 // mock AccountsFetcher 96 mockAccountsFetcher := &mockAccountsFetcher{} 97 98 // config 99 cfg := &config.Configuration{ 100 MaxRequestSize: maxSize, 101 AccountDefaults: config.Account{}, 102 } 103 cfg.MarshalAccountDefaults() 104 105 // prepare 106 reqData := "" 107 108 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(reqData)) 109 110 recorder := httptest.NewRecorder() 111 112 e := vtrackEndpoint{ 113 Cfg: cfg, 114 BidderInfos: nil, 115 Cache: mockCacheClient, 116 Accounts: mockAccountsFetcher, 117 normalizeBidderName: openrtb_ext.NormalizeBidderName, 118 } 119 120 // execute 121 e.Handle(recorder, req, nil) 122 123 d, err := io.ReadAll(recorder.Result().Body) 124 if err != nil { 125 t.Fatal(err) 126 } 127 128 // validate 129 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with empty body") 130 assert.Equal(t, "Invalid request: request body is empty\n", string(d)) 131 } 132 133 func TestShouldRespondWithBadRequestWhenRequestBodyIsInvalid(t *testing.T) { 134 // mock pbs cache client 135 mockCacheClient := &vtrackMockCacheClient{} 136 137 // mock AccountsFetcher 138 mockAccountsFetcher := &mockAccountsFetcher{} 139 140 // config 141 cfg := &config.Configuration{ 142 MaxRequestSize: maxSize, 143 AccountDefaults: config.Account{}, 144 } 145 cfg.MarshalAccountDefaults() 146 147 // prepare 148 reqData := "invalid" 149 150 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(reqData)) 151 152 recorder := httptest.NewRecorder() 153 154 e := vtrackEndpoint{ 155 Cfg: cfg, 156 BidderInfos: nil, 157 Cache: mockCacheClient, 158 Accounts: mockAccountsFetcher, 159 normalizeBidderName: openrtb_ext.NormalizeBidderName, 160 } 161 162 // execute 163 e.Handle(recorder, req, nil) 164 165 // validate 166 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with invalid body") 167 } 168 169 func TestShouldRespondWithBadRequestWhenBidIdIsMissing(t *testing.T) { 170 // mock pbs cache client 171 mockCacheClient := &vtrackMockCacheClient{} 172 173 // mock AccountsFetcher 174 mockAccountsFetcher := &mockAccountsFetcher{} 175 176 // config 177 cfg := &config.Configuration{ 178 MaxRequestSize: maxSize, 179 AccountDefaults: config.Account{}, 180 } 181 cfg.MarshalAccountDefaults() 182 183 // prepare 184 data := &BidCacheRequest{ 185 Puts: []prebid_cache_client.Cacheable{ 186 {}, 187 }, 188 } 189 190 reqData, err := jsonutil.Marshal(data) 191 if err != nil { 192 t.Fatal(err) 193 } 194 195 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(string(reqData))) 196 197 recorder := httptest.NewRecorder() 198 199 e := vtrackEndpoint{ 200 Cfg: cfg, 201 BidderInfos: nil, 202 Cache: mockCacheClient, 203 Accounts: mockAccountsFetcher, 204 normalizeBidderName: openrtb_ext.NormalizeBidderName, 205 } 206 207 // execute 208 e.Handle(recorder, req, nil) 209 210 d, err := io.ReadAll(recorder.Result().Body) 211 if err != nil { 212 t.Fatal(err) 213 } 214 215 // validate 216 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with elements missing bidid") 217 assert.Equal(t, "Invalid request: 'bidid' is required field and can't be empty\n", string(d)) 218 } 219 220 func TestShouldRespondWithBadRequestWhenBidderIsMissing(t *testing.T) { 221 // mock pbs cache client 222 mockCacheClient := &vtrackMockCacheClient{} 223 224 // mock AccountsFetcher 225 mockAccountsFetcher := &mockAccountsFetcher{} 226 227 // config 228 cfg := &config.Configuration{ 229 MaxRequestSize: maxSize, 230 AccountDefaults: config.Account{}, 231 } 232 cfg.MarshalAccountDefaults() 233 234 // prepare 235 data := &BidCacheRequest{ 236 Puts: []prebid_cache_client.Cacheable{ 237 { 238 BidID: "test", 239 }, 240 }, 241 } 242 243 reqData, err := jsonutil.Marshal(data) 244 if err != nil { 245 t.Fatal(err) 246 } 247 248 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(string(reqData))) 249 250 recorder := httptest.NewRecorder() 251 252 e := vtrackEndpoint{ 253 Cfg: cfg, 254 BidderInfos: nil, 255 Cache: mockCacheClient, 256 Accounts: mockAccountsFetcher, 257 normalizeBidderName: openrtb_ext.NormalizeBidderName, 258 } 259 260 // execute 261 e.Handle(recorder, req, nil) 262 263 d, err := io.ReadAll(recorder.Result().Body) 264 if err != nil { 265 t.Fatal(err) 266 } 267 268 // validate 269 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 on request with elements missing bidder") 270 assert.Equal(t, "Invalid request: 'bidder' is required field and can't be empty\n", string(d)) 271 } 272 273 func TestShouldRespondWithInternalServerErrorWhenPbsCacheClientFails(t *testing.T) { 274 // mock pbs cache client 275 mockCacheClient := &vtrackMockCacheClient{ 276 Fail: true, 277 Error: fmt.Errorf("pbs cache client failed"), 278 } 279 280 // mock AccountsFetcher 281 mockAccountsFetcher := &mockAccountsFetcher{} 282 283 // config 284 cfg := &config.Configuration{ 285 MaxRequestSize: maxSize, VTrack: config.VTrack{ 286 TimeoutMS: int64(2000), AllowUnknownBidder: true, 287 }, 288 AccountDefaults: config.Account{}, 289 } 290 cfg.MarshalAccountDefaults() 291 292 // prepare 293 data, err := getValidVTrackRequestBody(false, false) 294 if err != nil { 295 t.Fatal(err) 296 } 297 298 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(data)) 299 300 recorder := httptest.NewRecorder() 301 302 e := vtrackEndpoint{ 303 Cfg: cfg, 304 BidderInfos: nil, 305 Cache: mockCacheClient, 306 Accounts: mockAccountsFetcher, 307 normalizeBidderName: openrtb_ext.NormalizeBidderName, 308 } 309 310 // execute 311 e.Handle(recorder, req, nil) 312 313 d, err := io.ReadAll(recorder.Result().Body) 314 if err != nil { 315 t.Fatal(err) 316 } 317 318 // validate 319 assert.Equal(t, 500, recorder.Result().StatusCode, "Expected 500 when pbs cache client fails") 320 assert.Equal(t, "Error(s) updating vast: pbs cache client failed\n", string(d)) 321 } 322 323 func TestShouldTolerateAccountNotFound(t *testing.T) { 324 // mock pbs cache client 325 mockCacheClient := &vtrackMockCacheClient{} 326 327 // mock AccountsFetcher 328 mockAccountsFetcher := &mockAccountsFetcher{ 329 Fail: true, 330 Error: stored_requests.NotFoundError{}, 331 } 332 333 // config 334 cfg := &config.Configuration{ 335 MaxRequestSize: maxSize, VTrack: config.VTrack{ 336 TimeoutMS: int64(2000), AllowUnknownBidder: false, 337 }, 338 AccountDefaults: config.Account{}, 339 } 340 cfg.MarshalAccountDefaults() 341 342 // prepare 343 data, err := getValidVTrackRequestBody(true, false) 344 if err != nil { 345 t.Fatal(err) 346 } 347 348 req := httptest.NewRequest("POST", "/vtrack?a=1235", strings.NewReader(data)) 349 350 recorder := httptest.NewRecorder() 351 352 e := vtrackEndpoint{ 353 Cfg: cfg, 354 BidderInfos: nil, 355 Cache: mockCacheClient, 356 Accounts: mockAccountsFetcher, 357 normalizeBidderName: openrtb_ext.NormalizeBidderName, 358 } 359 360 // execute 361 e.Handle(recorder, req, nil) 362 363 // validate 364 assert.Equal(t, 200, recorder.Result().StatusCode, "Expected 200 when account is not found and request is valid") 365 assert.Equal(t, "application/json", recorder.Header().Get("Content-Type")) 366 } 367 368 func TestShouldSendToCacheExpectedPutsAndUpdatableBiddersWhenBidderVastNotAllowed(t *testing.T) { 369 // mock pbs cache client 370 mockCacheClient := &vtrackMockCacheClient{ 371 Fail: false, 372 Uuids: []string{"uuid1"}, 373 } 374 375 // mock AccountsFetcher 376 mockAccountsFetcher := &mockAccountsFetcher{ 377 Fail: false, 378 } 379 380 // config 381 cfg := &config.Configuration{ 382 MaxRequestSize: maxSize, VTrack: config.VTrack{ 383 TimeoutMS: int64(2000), AllowUnknownBidder: false, 384 }, 385 AccountDefaults: config.Account{}, 386 } 387 cfg.MarshalAccountDefaults() 388 389 // bidder info 390 bidderInfos := make(config.BidderInfos) 391 bidderInfos["bidder"] = config.BidderInfo{ 392 Disabled: false, 393 ModifyingVastXmlAllowed: false, 394 } 395 bidderInfos["updatable_bidder"] = config.BidderInfo{ 396 Disabled: false, 397 ModifyingVastXmlAllowed: true, 398 } 399 400 // prepare 401 data, err := getValidVTrackRequestBody(false, false) 402 if err != nil { 403 t.Fatal(err) 404 } 405 406 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(data)) 407 408 recorder := httptest.NewRecorder() 409 410 e := vtrackEndpoint{ 411 Cfg: cfg, 412 BidderInfos: bidderInfos, 413 Cache: mockCacheClient, 414 Accounts: mockAccountsFetcher, 415 normalizeBidderName: openrtb_ext.NormalizeBidderName, 416 } 417 418 // execute 419 e.Handle(recorder, req, nil) 420 421 d, err := io.ReadAll(recorder.Result().Body) 422 if err != nil { 423 t.Fatal(err) 424 } 425 426 // validate 427 assert.Equal(t, 200, recorder.Result().StatusCode, "Expected 200 when account is not found and request is valid") 428 assert.Equal(t, "{\"responses\":[{\"uuid\":\"uuid1\"}]}", string(d), "Expected 200 when account is found and request is valid") 429 assert.Equal(t, "application/json", recorder.Header().Get("Content-Type")) 430 } 431 432 func TestShouldSendToCacheExpectedPutsAndUpdatableBiddersWhenBidderVastAllowed(t *testing.T) { 433 // mock pbs cache client 434 mockCacheClient := &vtrackMockCacheClient{ 435 Fail: false, 436 Uuids: []string{"uuid1", "uuid2"}, 437 } 438 439 // mock AccountsFetcher 440 mockAccountsFetcher := &mockAccountsFetcher{ 441 Fail: false, 442 } 443 444 // config 445 cfg := &config.Configuration{ 446 MaxRequestSize: maxSize, VTrack: config.VTrack{ 447 TimeoutMS: int64(2000), AllowUnknownBidder: false, 448 }, 449 AccountDefaults: config.Account{}, 450 } 451 cfg.MarshalAccountDefaults() 452 453 // bidder info 454 bidderInfos := make(config.BidderInfos) 455 bidderInfos["bidder"] = config.BidderInfo{ 456 Disabled: false, 457 ModifyingVastXmlAllowed: true, 458 } 459 bidderInfos["updatable_bidder"] = config.BidderInfo{ 460 Disabled: false, 461 ModifyingVastXmlAllowed: true, 462 } 463 464 // prepare 465 data, err := getValidVTrackRequestBody(true, true) 466 if err != nil { 467 t.Fatal(err) 468 } 469 470 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(data)) 471 472 recorder := httptest.NewRecorder() 473 474 var mockNormalizeBidderName normalizeBidderName = func(name string) (openrtb_ext.BidderName, bool) { 475 return openrtb_ext.BidderName(name), true 476 } 477 e := vtrackEndpoint{ 478 Cfg: cfg, 479 BidderInfos: bidderInfos, 480 Cache: mockCacheClient, 481 Accounts: mockAccountsFetcher, 482 normalizeBidderName: mockNormalizeBidderName, 483 } 484 485 // execute 486 e.Handle(recorder, req, nil) 487 488 d, err := io.ReadAll(recorder.Result().Body) 489 if err != nil { 490 t.Fatal(err) 491 } 492 493 // validate 494 assert.Equal(t, 200, recorder.Result().StatusCode, "Expected 200 when account is not found and request is valid") 495 assert.Equal(t, "{\"responses\":[{\"uuid\":\"uuid1\"},{\"uuid\":\"uuid2\"}]}", string(d), "Expected 200 when account is found and request is valid") 496 assert.Equal(t, "application/json", recorder.Header().Get("Content-Type")) 497 assert.Len(t, mockCacheClient.Values, 2) 498 assert.Contains(t, string(mockCacheClient.Values[0].Data), "bidder=bidder") 499 assert.Contains(t, string(mockCacheClient.Values[1].Data), "bidder=updatable_bidder") 500 } 501 502 func TestShouldSendToCacheExpectedPutsAndUpdatableCaseSensitiveBiddersWhenBidderVastAllowed(t *testing.T) { 503 // mock pbs cache client 504 mockCacheClient := &vtrackMockCacheClient{ 505 Fail: false, 506 Uuids: []string{"uuid1", "uuid2"}, 507 } 508 509 // mock AccountsFetcher 510 mockAccountsFetcher := &mockAccountsFetcher{ 511 Fail: false, 512 } 513 514 // config 515 cfg := &config.Configuration{ 516 MaxRequestSize: maxSize, VTrack: config.VTrack{ 517 TimeoutMS: int64(2000), AllowUnknownBidder: false, 518 }, 519 AccountDefaults: config.Account{}, 520 } 521 cfg.MarshalAccountDefaults() 522 523 // bidder info 524 bidderInfos := make(config.BidderInfos) 525 bidderInfos["appnexus"] = config.BidderInfo{ 526 Disabled: false, 527 ModifyingVastXmlAllowed: true, 528 } 529 530 d, err := getVTrackRequestData(true, true) 531 assert.NoError(t, err) 532 533 cacheReq := &BidCacheRequest{ 534 Puts: []prebid_cache_client.Cacheable{ 535 { 536 Type: prebid_cache_client.TypeXML, 537 BidID: "bidId1", 538 Bidder: "APPNEXUS", // case sensitive name 539 Data: d, 540 TTLSeconds: 3600, 541 Timestamp: 1000, 542 }, 543 { 544 Type: prebid_cache_client.TypeXML, 545 BidID: "bidId2", 546 Bidder: "ApPnExUs", // case sensitive name 547 Data: d, 548 TTLSeconds: 3600, 549 Timestamp: 1000, 550 }, 551 }, 552 } 553 buf := &bytes.Buffer{} 554 enc := json.NewEncoder(buf) 555 enc.SetEscapeHTML(false) 556 err = enc.Encode(cacheReq) 557 assert.NoError(t, err) 558 data := buf.String() 559 560 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(data)) 561 562 recorder := httptest.NewRecorder() 563 e := vtrackEndpoint{ 564 Cfg: cfg, 565 BidderInfos: bidderInfos, 566 Cache: mockCacheClient, 567 Accounts: mockAccountsFetcher, 568 normalizeBidderName: openrtb_ext.NormalizeBidderName, 569 } 570 571 // execute 572 e.Handle(recorder, req, nil) 573 574 d, err = io.ReadAll(recorder.Result().Body) 575 if err != nil { 576 t.Fatal(err) 577 } 578 579 // validate 580 assert.Equal(t, 200, recorder.Result().StatusCode, "Expected 200 when account is not found and request is valid") 581 assert.Equal(t, "{\"responses\":[{\"uuid\":\"uuid1\"},{\"uuid\":\"uuid2\"}]}", string(d), "Expected 200 when account is found and request is valid") 582 assert.Equal(t, "application/json", recorder.Header().Get("Content-Type")) 583 assert.Len(t, mockCacheClient.Values, 2) 584 assert.Contains(t, string(mockCacheClient.Values[0].Data), "bidder=APPNEXUS") 585 assert.Contains(t, string(mockCacheClient.Values[1].Data), "bidder=ApPnExUs") 586 } 587 588 func TestShouldSendToCacheExpectedPutsAndUpdatableUnknownBiddersWhenUnknownBidderIsAllowed(t *testing.T) { 589 // mock pbs cache client 590 mockCacheClient := &vtrackMockCacheClient{ 591 Fail: false, 592 Uuids: []string{"uuid1", "uuid2"}, 593 } 594 595 // mock AccountsFetcher 596 mockAccountsFetcher := &mockAccountsFetcher{ 597 Fail: false, 598 } 599 600 // config 601 cfg := &config.Configuration{ 602 MaxRequestSize: maxSize, VTrack: config.VTrack{ 603 TimeoutMS: int64(2000), AllowUnknownBidder: true, 604 }, 605 AccountDefaults: config.Account{}, 606 } 607 cfg.MarshalAccountDefaults() 608 609 // bidder info 610 bidderInfos := make(config.BidderInfos) 611 612 // prepare 613 data, err := getValidVTrackRequestBody(true, false) 614 if err != nil { 615 t.Fatal(err) 616 } 617 618 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(data)) 619 620 recorder := httptest.NewRecorder() 621 622 e := vtrackEndpoint{ 623 Cfg: cfg, 624 BidderInfos: bidderInfos, 625 Cache: mockCacheClient, 626 Accounts: mockAccountsFetcher, 627 normalizeBidderName: openrtb_ext.NormalizeBidderName, 628 } 629 630 // execute 631 e.Handle(recorder, req, nil) 632 633 d, err := io.ReadAll(recorder.Result().Body) 634 if err != nil { 635 t.Fatal(err) 636 } 637 638 // validate 639 assert.Equal(t, 200, recorder.Result().StatusCode, "Expected 200 when account is not found and request is valid") 640 assert.Equal(t, "{\"responses\":[{\"uuid\":\"uuid1\"},{\"uuid\":\"uuid2\"}]}", string(d), "Expected 200 when account is found, request has unknown bidders but allowUnknownBidders is enabled") 641 assert.Equal(t, "application/json", recorder.Header().Get("Content-Type")) 642 } 643 644 func TestShouldReturnBadRequestWhenRequestExceedsMaxRequestSize(t *testing.T) { 645 // mock pbs cache client 646 mockCacheClient := &vtrackMockCacheClient{ 647 Fail: false, 648 Uuids: []string{"uuid1", "uuid2"}, 649 } 650 651 // mock AccountsFetcher 652 mockAccountsFetcher := &mockAccountsFetcher{ 653 Fail: false, 654 } 655 656 // config 657 cfg := &config.Configuration{ 658 MaxRequestSize: 1, 659 VTrack: config.VTrack{ 660 TimeoutMS: int64(2000), AllowUnknownBidder: true, 661 }, 662 AccountDefaults: config.Account{}, 663 } 664 cfg.MarshalAccountDefaults() 665 666 // bidder info 667 bidderInfos := make(config.BidderInfos) 668 669 // prepare 670 data, err := getValidVTrackRequestBody(true, false) 671 if err != nil { 672 t.Fatal(err) 673 } 674 675 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(data)) 676 677 recorder := httptest.NewRecorder() 678 679 e := vtrackEndpoint{ 680 Cfg: cfg, 681 BidderInfos: bidderInfos, 682 Cache: mockCacheClient, 683 Accounts: mockAccountsFetcher, 684 normalizeBidderName: openrtb_ext.NormalizeBidderName, 685 } 686 687 // execute 688 e.Handle(recorder, req, nil) 689 690 d, err := io.ReadAll(recorder.Result().Body) 691 if err != nil { 692 t.Fatal(err) 693 } 694 695 // validate 696 assert.Equal(t, 400, recorder.Result().StatusCode, "Expected 400 when request exceeds max request size") 697 assert.Equal(t, "Invalid request: request size exceeded max size of 1 bytes\n", string(d)) 698 } 699 700 func TestShouldRespondWithInternalErrorPbsCacheIsNotConfigured(t *testing.T) { 701 // mock AccountsFetcher 702 mockAccountsFetcher := &mockAccountsFetcher{ 703 Fail: false, 704 } 705 706 // config 707 cfg := &config.Configuration{ 708 MaxRequestSize: maxSize, VTrack: config.VTrack{ 709 TimeoutMS: int64(2000), AllowUnknownBidder: false, 710 }, 711 AccountDefaults: config.Account{}, 712 } 713 cfg.MarshalAccountDefaults() 714 715 // prepare 716 data, err := getValidVTrackRequestBody(true, true) 717 if err != nil { 718 t.Fatal(err) 719 } 720 721 req := httptest.NewRequest("POST", "/vtrack?a=events_enabled", strings.NewReader(data)) 722 recorder := httptest.NewRecorder() 723 724 e := vtrackEndpoint{ 725 Cfg: cfg, 726 BidderInfos: nil, 727 Cache: nil, 728 Accounts: mockAccountsFetcher, 729 normalizeBidderName: openrtb_ext.NormalizeBidderName, 730 } 731 732 // execute 733 e.Handle(recorder, req, nil) 734 735 d, err := io.ReadAll(recorder.Result().Body) 736 if err != nil { 737 t.Fatal(err) 738 } 739 740 // validate 741 assert.Equal(t, 500, recorder.Result().StatusCode, "Expected 500 when pbs cache is not configured") 742 assert.Equal(t, "PBS Cache client is not configured", string(d)) 743 } 744 745 func TestVastUrlShouldReturnExpectedUrl(t *testing.T) { 746 url := GetVastUrlTracking("http://external-url", "bidId", "bidder", "accountId", 1000, "integrationType") 747 assert.Equal(t, "http://external-url/event?t=imp&b=bidId&a=accountId&bidder=bidder&f=b&int=integrationType&ts=1000", url, "Invalid vast url") 748 } 749 750 func getValidVTrackRequestBody(withImpression bool, withContent bool) (string, error) { 751 d, e := getVTrackRequestData(withImpression, withContent) 752 753 if e != nil { 754 return "", e 755 } 756 757 req := &BidCacheRequest{ 758 Puts: []prebid_cache_client.Cacheable{ 759 { 760 Type: prebid_cache_client.TypeXML, 761 BidID: "bidId1", 762 Bidder: "bidder", 763 Data: d, 764 TTLSeconds: 3600, 765 Timestamp: 1000, 766 }, 767 { 768 Type: prebid_cache_client.TypeXML, 769 BidID: "bidId2", 770 Bidder: "updatable_bidder", 771 Data: d, 772 TTLSeconds: 3600, 773 Timestamp: 1000, 774 }, 775 }, 776 } 777 778 buf := &bytes.Buffer{} 779 enc := json.NewEncoder(buf) 780 enc.SetEscapeHTML(false) 781 782 e = enc.Encode(req) 783 784 return buf.String(), e 785 } 786 787 func getVTrackRequestData(wi bool, wic bool) (db []byte, e error) { 788 data := &bytes.Buffer{} 789 enc := json.NewEncoder(data) 790 enc.SetEscapeHTML(false) 791 792 if wi && wic { 793 e = enc.Encode(vastXmlWithImpressionWithContent) 794 return data.Bytes(), e 795 } else if wi { 796 e = enc.Encode(vastXmlWithImpressionWithoutContent) 797 } else { 798 enc.Encode(vastXmlWithoutImpression) 799 } 800 801 return data.Bytes(), e 802 } 803 804 func TestGetIntegrationType(t *testing.T) { 805 testCases := []struct { 806 description string 807 givenHttpRequest *http.Request 808 expectedIntegrationType string 809 expectedError error 810 }{ 811 { 812 description: "Integration type in http request is valid, expect same integration time and no errors", 813 givenHttpRequest: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=TestIntegrationType", strings.NewReader("")), 814 expectedIntegrationType: "TestIntegrationType", 815 expectedError: nil, 816 }, 817 { 818 description: "Integration type in http request is too long, expect too long error", 819 givenHttpRequest: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=TestIntegrationTypeTooLongTestIntegrationTypeTooLongTestIntegrationType", strings.NewReader("")), 820 expectedError: errors.New("integration type length is too long"), 821 }, 822 { 823 description: "Integration type in http request contains invalid character, expect invalid character error", 824 givenHttpRequest: httptest.NewRequest("GET", "/event?t=win&b=bidId&f=b&ts=1000&x=1&a=accountId&bidder=bidder&int=Te$tIntegrationType", strings.NewReader("")), 825 expectedError: errors.New("integration type can only contain numbers, letters and these characters '-', '_'"), 826 }, 827 } 828 829 for _, test := range testCases { 830 integrationType, err := getIntegrationType(test.givenHttpRequest) 831 if test.expectedError != nil { 832 assert.Equal(t, test.expectedError, err, test.description) 833 } else { 834 assert.Empty(t, err, test.description) 835 assert.Equalf(t, test.expectedIntegrationType, integrationType, test.description) 836 } 837 } 838 }