github.com/prebid/prebid-server/v2@v2.18.0/usersync/cookie_test.go (about) 1 package usersync 2 3 import ( 4 "errors" 5 "net/http" 6 "net/http/httptest" 7 "testing" 8 "time" 9 10 "github.com/prebid/prebid-server/v2/config" 11 "github.com/prebid/prebid-server/v2/openrtb_ext" 12 "github.com/stretchr/testify/assert" 13 ) 14 15 func TestReadCookie(t *testing.T) { 16 testCases := []struct { 17 name string 18 givenRequest *http.Request 19 givenHttpCookie *http.Cookie 20 givenCookie *Cookie 21 givenDecoder Decoder 22 expectedCookie *Cookie 23 }{ 24 { 25 name: "simple-cookie", 26 givenRequest: httptest.NewRequest("POST", "http://www.prebid.com", nil), 27 givenCookie: &Cookie{ 28 uids: map[string]UIDEntry{ 29 "adnxs": { 30 UID: "UID", 31 Expires: time.Time{}, 32 }, 33 }, 34 optOut: false, 35 }, 36 expectedCookie: &Cookie{ 37 uids: map[string]UIDEntry{ 38 "adnxs": { 39 UID: "UID", 40 }, 41 }, 42 optOut: false, 43 }, 44 }, 45 { 46 name: "empty-cookie", 47 givenRequest: httptest.NewRequest("POST", "http://www.prebid.com", nil), 48 givenCookie: &Cookie{}, 49 expectedCookie: &Cookie{ 50 uids: map[string]UIDEntry{}, 51 optOut: false, 52 }, 53 }, 54 { 55 name: "nil-cookie", 56 givenRequest: httptest.NewRequest("POST", "http://www.prebid.com", nil), 57 givenCookie: nil, 58 expectedCookie: &Cookie{ 59 uids: map[string]UIDEntry{}, 60 optOut: false, 61 }, 62 }, 63 { 64 name: "corruptted-http-cookie", 65 givenRequest: httptest.NewRequest("POST", "http://www.prebid.com", nil), 66 givenHttpCookie: &http.Cookie{ 67 Name: "uids", 68 Value: "bad base64 encoding", 69 }, 70 givenCookie: nil, 71 expectedCookie: &Cookie{ 72 uids: map[string]UIDEntry{}, 73 optOut: false, 74 }, 75 }, 76 } 77 78 for _, test := range testCases { 79 t.Run(test.name, func(t *testing.T) { 80 if test.givenCookie != nil { 81 httpCookie, err := ToHTTPCookie(test.givenCookie) 82 assert.NoError(t, err) 83 test.givenRequest.AddCookie(httpCookie) 84 } else if test.givenCookie == nil && test.givenHttpCookie != nil { 85 test.givenRequest.AddCookie(test.givenHttpCookie) 86 } 87 actualCookie := ReadCookie(test.givenRequest, Base64Decoder{}, &config.HostCookie{}) 88 assert.Equal(t, test.expectedCookie.uids, actualCookie.uids) 89 assert.Equal(t, test.expectedCookie.optOut, actualCookie.optOut) 90 }) 91 } 92 } 93 94 func TestWriteCookie(t *testing.T) { 95 encoder := Base64Encoder{} 96 decoder := Base64Decoder{} 97 98 testCases := []struct { 99 name string 100 givenCookie *Cookie 101 givenSetSiteCookie bool 102 expectedCookie *Cookie 103 }{ 104 { 105 name: "simple-cookie", 106 givenCookie: &Cookie{ 107 uids: map[string]UIDEntry{ 108 "adnxs": { 109 UID: "UID", 110 Expires: time.Time{}, 111 }, 112 }, 113 optOut: false, 114 }, 115 givenSetSiteCookie: false, 116 expectedCookie: &Cookie{ 117 uids: map[string]UIDEntry{ 118 "adnxs": { 119 UID: "UID", 120 Expires: time.Time{}, 121 }, 122 }, 123 optOut: false, 124 }, 125 }, 126 { 127 name: "simple-cookie-opt-out", 128 givenCookie: &Cookie{ 129 uids: map[string]UIDEntry{ 130 "adnxs": { 131 UID: "UID", 132 Expires: time.Time{}, 133 }, 134 }, 135 optOut: true, 136 }, 137 givenSetSiteCookie: true, 138 expectedCookie: &Cookie{ 139 uids: map[string]UIDEntry{}, 140 optOut: true, 141 }, 142 }, 143 { 144 name: "cookie-multiple-uids", 145 givenCookie: &Cookie{ 146 uids: map[string]UIDEntry{ 147 "adnxs": { 148 UID: "UID", 149 Expires: time.Time{}, 150 }, 151 "rubicon": { 152 UID: "UID2", 153 Expires: time.Time{}, 154 }, 155 }, 156 optOut: false, 157 }, 158 givenSetSiteCookie: true, 159 expectedCookie: &Cookie{ 160 uids: map[string]UIDEntry{ 161 "adnxs": { 162 UID: "UID", 163 Expires: time.Time{}, 164 }, 165 "rubicon": { 166 UID: "UID2", 167 Expires: time.Time{}, 168 }, 169 }, 170 optOut: false, 171 }, 172 }, 173 } 174 175 for _, test := range testCases { 176 t.Run(test.name, func(t *testing.T) { 177 // Write Cookie 178 w := httptest.NewRecorder() 179 encodedCookie, err := encoder.Encode(test.givenCookie) 180 assert.NoError(t, err) 181 WriteCookie(w, encodedCookie, &config.HostCookie{}, test.givenSetSiteCookie) 182 writtenCookie := w.Header().Get("Set-Cookie") 183 184 // Read Cookie 185 header := http.Header{} 186 header.Add("Cookie", writtenCookie) 187 r := &http.Request{Header: header} 188 actualCookie := ReadCookie(r, decoder, &config.HostCookie{}) 189 190 assert.Equal(t, test.expectedCookie, actualCookie) 191 }) 192 } 193 } 194 195 func TestSync(t *testing.T) { 196 testCases := []struct { 197 name string 198 givenCookie *Cookie 199 givenSyncerKey string 200 givenUID string 201 expectedCookie *Cookie 202 expectedError error 203 }{ 204 { 205 name: "simple-sync", 206 givenCookie: &Cookie{ 207 uids: map[string]UIDEntry{}, 208 }, 209 givenSyncerKey: "adnxs", 210 givenUID: "123", 211 expectedCookie: &Cookie{ 212 uids: map[string]UIDEntry{ 213 "adnxs": { 214 UID: "123", 215 }, 216 }, 217 }, 218 }, 219 { 220 name: "dont-allow-syncs", 221 givenCookie: &Cookie{ 222 uids: map[string]UIDEntry{}, 223 optOut: true, 224 }, 225 givenSyncerKey: "adnxs", 226 givenUID: "123", 227 expectedCookie: &Cookie{ 228 uids: map[string]UIDEntry{}, 229 }, 230 expectedError: errors.New("the user has opted out of prebid server cookie syncs"), 231 }, 232 { 233 name: "audienceNetwork", 234 givenCookie: &Cookie{ 235 uids: map[string]UIDEntry{}, 236 }, 237 givenSyncerKey: string(openrtb_ext.BidderAudienceNetwork), 238 givenUID: "0", 239 expectedError: errors.New("audienceNetwork uses a UID of 0 as \"not yet recognized\""), 240 }, 241 } 242 243 for _, test := range testCases { 244 t.Run(test.name, func(t *testing.T) { 245 err := test.givenCookie.Sync(test.givenSyncerKey, test.givenUID) 246 if test.expectedError != nil { 247 assert.Equal(t, test.expectedError, err) 248 } else { 249 assert.NoError(t, err) 250 assert.Equal(t, test.expectedCookie.uids[test.givenSyncerKey].UID, test.givenCookie.uids[test.givenSyncerKey].UID) 251 } 252 }) 253 } 254 } 255 256 func TestGetUIDs(t *testing.T) { 257 testCases := []struct { 258 name string 259 givenCookie *Cookie 260 expectedCookie *Cookie 261 expectedLen int 262 }{ 263 { 264 name: "two-uids", 265 givenCookie: &Cookie{ 266 uids: map[string]UIDEntry{ 267 "adnxs": { 268 UID: "123", 269 }, 270 "rubicon": { 271 UID: "456", 272 }, 273 }, 274 }, 275 expectedLen: 2, 276 }, 277 { 278 name: "one-uid", 279 givenCookie: &Cookie{ 280 uids: map[string]UIDEntry{ 281 "adnxs": { 282 UID: "123", 283 }, 284 }, 285 }, 286 expectedLen: 1, 287 }, 288 { 289 name: "empty", 290 givenCookie: &Cookie{}, 291 expectedLen: 0, 292 }, 293 { 294 name: "nil", 295 givenCookie: nil, 296 expectedLen: 0, 297 }, 298 } 299 300 for _, test := range testCases { 301 t.Run(test.name, func(t *testing.T) { 302 uids := test.givenCookie.GetUIDs() 303 assert.Len(t, uids, test.expectedLen) 304 for key, value := range uids { 305 assert.Equal(t, test.givenCookie.uids[key].UID, value) 306 } 307 308 }) 309 } 310 } 311 312 func TestWriteCookieUserAgent(t *testing.T) { 313 encoder := Base64Encoder{} 314 315 testCases := []struct { 316 name string 317 givenUserAgent string 318 givenCookie *Cookie 319 givenHostCookie config.HostCookie 320 givenSetSiteCookie bool 321 expectedContains string 322 expectedNotContains string 323 }{ 324 { 325 name: "same-site-none", 326 givenUserAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36", 327 givenCookie: &Cookie{ 328 uids: map[string]UIDEntry{ 329 "adnxs": { 330 UID: "UID", 331 Expires: time.Time{}, 332 }, 333 }, 334 optOut: false, 335 }, 336 givenHostCookie: config.HostCookie{}, 337 givenSetSiteCookie: true, 338 expectedContains: "; Secure;", 339 }, 340 { 341 name: "older-chrome-version", 342 givenUserAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3770.142 Safari/537.36", 343 givenCookie: &Cookie{ 344 uids: map[string]UIDEntry{ 345 "adnxs": { 346 UID: "UID", 347 Expires: time.Time{}, 348 }, 349 }, 350 optOut: false, 351 }, 352 givenHostCookie: config.HostCookie{}, 353 givenSetSiteCookie: true, 354 expectedNotContains: "SameSite=none", 355 }, 356 } 357 358 for _, test := range testCases { 359 t.Run(test.name, func(t *testing.T) { 360 // Set Up 361 req := httptest.NewRequest("GET", "http://www.prebid.com", nil) 362 req.Header.Set("User-Agent", test.givenUserAgent) 363 364 // Write Cookie 365 w := httptest.NewRecorder() 366 encodedCookie, err := encoder.Encode(test.givenCookie) 367 assert.NoError(t, err) 368 WriteCookie(w, encodedCookie, &test.givenHostCookie, test.givenSetSiteCookie) 369 writtenCookie := w.Header().Get("Set-Cookie") 370 371 if test.expectedContains == "" { 372 assert.NotContains(t, writtenCookie, test.expectedNotContains) 373 } else { 374 assert.Contains(t, writtenCookie, test.expectedContains) 375 } 376 }) 377 } 378 } 379 380 func TestPrepareCookieForWrite(t *testing.T) { 381 encoder := Base64Encoder{} 382 decoder := Base64Decoder{} 383 384 mainCookie := &Cookie{ 385 uids: map[string]UIDEntry{ 386 "mainUID": newTempId("1234567890123456789012345678901234567890123456", 7), 387 "2": newTempId("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 6), 388 "3": newTempId("123456789012345678901234567896123456789012345678", 5), 389 "4": newTempId("aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ", 4), 390 "5": newTempId("12345678901234567890123456789012345678901234567890", 3), 391 "6": newTempId("abcdefghij", 2), 392 "7": newTempId("abcdefghijklmnopqrstuvwxy", 1), 393 }, 394 optOut: false, 395 } 396 397 errorCookie := &Cookie{ 398 uids: map[string]UIDEntry{ 399 "syncerNotPriority": newTempId("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 7), 400 "2": newTempId("1234567890123456789012345678901234567890123456", 7), // Priority Element 401 }, 402 optOut: false, 403 } 404 405 ejector := &PriorityBidderEjector{ 406 PriorityGroups: [][]string{ 407 {"mainUID"}, 408 {"2", "3"}, 409 {"4", "5", "6"}, 410 {"7"}, 411 }, 412 SyncersByBidder: map[string]Syncer{ 413 "mainUID": fakeSyncer{ 414 key: "mainUID", 415 }, 416 "2": fakeSyncer{ 417 key: "2", 418 }, 419 "3": fakeSyncer{ 420 key: "3", 421 }, 422 "4": fakeSyncer{ 423 key: "4", 424 }, 425 "5": fakeSyncer{ 426 key: "5", 427 }, 428 "6": fakeSyncer{ 429 key: "6", 430 }, 431 "mistmatchedBidder": fakeSyncer{ 432 key: "7", 433 }, 434 }, 435 TieEjector: &OldestEjector{}, 436 } 437 438 testCases := []struct { 439 name string 440 givenMaxCookieSize int 441 givenCookieToSend *Cookie 442 givenIsSyncerPriority bool 443 expectedRemainingUidKeys []string 444 expectedError error 445 }{ 446 { 447 name: "no-uids-ejected", 448 givenMaxCookieSize: 2000, 449 givenCookieToSend: mainCookie, 450 givenIsSyncerPriority: true, 451 expectedRemainingUidKeys: []string{ 452 "mainUID", "2", "3", "4", "5", "6", "7", 453 }, 454 }, 455 { 456 name: "invalid-max-size", 457 givenMaxCookieSize: -100, 458 givenCookieToSend: mainCookie, 459 expectedRemainingUidKeys: []string{ 460 "mainUID", "2", "3", "4", "5", "6", "7", 461 }, 462 }, 463 { 464 name: "syncer-is-not-priority", 465 givenMaxCookieSize: 100, 466 givenCookieToSend: errorCookie, 467 givenIsSyncerPriority: false, 468 expectedError: errors.New("syncer key is not a priority, and there are only priority elements left"), 469 }, 470 { 471 name: "no-uids-ejected-2", 472 givenMaxCookieSize: 0, 473 givenCookieToSend: mainCookie, 474 givenIsSyncerPriority: true, 475 expectedRemainingUidKeys: []string{ 476 "mainUID", "2", "3", "4", "5", "6", "7", 477 }, 478 }, 479 { 480 name: "one-uid-ejected", 481 givenMaxCookieSize: 900, 482 givenCookieToSend: mainCookie, 483 givenIsSyncerPriority: true, 484 expectedRemainingUidKeys: []string{ 485 "mainUID", "2", "3", "4", "5", "6", 486 }, 487 }, 488 { 489 name: "four-uids-ejected", 490 givenMaxCookieSize: 500, 491 givenCookieToSend: mainCookie, 492 givenIsSyncerPriority: true, 493 expectedRemainingUidKeys: []string{ 494 "mainUID", "2", "3", 495 }, 496 }, 497 { 498 name: "all-but-one-uids-ejected", 499 givenMaxCookieSize: 300, 500 givenCookieToSend: mainCookie, 501 givenIsSyncerPriority: true, 502 expectedRemainingUidKeys: []string{ 503 "mainUID", 504 }, 505 }, 506 { 507 name: "only-main-uid-left", 508 givenMaxCookieSize: 100, 509 givenCookieToSend: mainCookie, 510 expectedError: errors.New("uid that's trying to be synced is bigger than MaxCookieSize"), 511 expectedRemainingUidKeys: []string{}, 512 }, 513 } 514 515 for _, test := range testCases { 516 t.Run(test.name, func(t *testing.T) { 517 ejector.IsSyncerPriority = test.givenIsSyncerPriority 518 encodedCookie, err := test.givenCookieToSend.PrepareCookieForWrite(&config.HostCookie{MaxCookieSizeBytes: test.givenMaxCookieSize}, encoder, ejector) 519 520 if test.expectedError != nil { 521 assert.Equal(t, test.expectedError, err) 522 } else { 523 assert.NoError(t, err) 524 decodedCookie := decoder.Decode(encodedCookie) 525 526 for _, key := range test.expectedRemainingUidKeys { 527 _, ok := decodedCookie.uids[key] 528 assert.Equal(t, true, ok) 529 } 530 assert.Equal(t, len(decodedCookie.uids), len(test.expectedRemainingUidKeys)) 531 } 532 }) 533 } 534 } 535 536 func TestSyncHostCookie(t *testing.T) { 537 testCases := []struct { 538 name string 539 givenCookie *Cookie 540 givenUID string 541 givenHostCookie *config.HostCookie 542 expectedCookie *Cookie 543 expectedError error 544 }{ 545 { 546 name: "simple-sync", 547 givenCookie: &Cookie{ 548 uids: map[string]UIDEntry{}, 549 }, 550 givenHostCookie: &config.HostCookie{ 551 Family: "syncer", 552 CookieName: "adnxs", 553 }, 554 expectedCookie: &Cookie{ 555 uids: map[string]UIDEntry{ 556 "syncer": { 557 UID: "some-user-id", 558 }, 559 }, 560 }, 561 }, 562 { 563 name: "uids-already-present", 564 givenCookie: &Cookie{ 565 uids: map[string]UIDEntry{ 566 "some-syncer": { 567 UID: "some-other-user-id", 568 }, 569 }, 570 }, 571 givenHostCookie: &config.HostCookie{ 572 Family: "syncer", 573 CookieName: "adnxs", 574 }, 575 expectedCookie: &Cookie{ 576 uids: map[string]UIDEntry{ 577 "syncer": { 578 UID: "some-user-id", 579 }, 580 "some-syncer": { 581 UID: "some-other-user-id", 582 }, 583 }, 584 }, 585 }, 586 { 587 name: "host-already-synced", 588 givenCookie: &Cookie{ 589 uids: map[string]UIDEntry{ 590 "syncer": { 591 UID: "some-user-id", 592 }, 593 }, 594 }, 595 givenHostCookie: &config.HostCookie{ 596 Family: "syncer", 597 CookieName: "adnxs", 598 }, 599 expectedCookie: &Cookie{ 600 uids: map[string]UIDEntry{ 601 "syncer": { 602 UID: "some-user-id", 603 }, 604 }, 605 }, 606 }, 607 } 608 609 for _, test := range testCases { 610 t.Run(test.name, func(t *testing.T) { 611 r := httptest.NewRequest("POST", "http://www.prebid.com", nil) 612 r.AddCookie(&http.Cookie{ 613 Name: test.givenHostCookie.CookieName, 614 Value: "some-user-id", 615 }) 616 617 SyncHostCookie(r, test.givenCookie, test.givenHostCookie) 618 for key, value := range test.expectedCookie.uids { 619 assert.Equal(t, value.UID, test.givenCookie.uids[key].UID) 620 } 621 }) 622 } 623 } 624 625 func TestBidderNameGets(t *testing.T) { 626 cookie := newSampleCookie() 627 id, exists, _ := cookie.GetUID("adnxs") 628 if !exists { 629 t.Errorf("Cookie missing expected Appnexus ID") 630 } 631 if id != "123" { 632 t.Errorf("Bad appnexus id. Expected %s, got %s", "123", id) 633 } 634 635 id, exists, _ = cookie.GetUID("rubicon") 636 if !exists { 637 t.Errorf("Cookie missing expected Rubicon ID") 638 } 639 if id != "456" { 640 t.Errorf("Bad rubicon id. Expected %s, got %s", "456", id) 641 } 642 } 643 644 func TestReadCookieOptOut(t *testing.T) { 645 optOutCookieName := "optOutCookieName" 646 optOutCookieValue := "optOutCookieValue" 647 decoder := Base64Decoder{} 648 649 cookie := *(&Cookie{ 650 uids: map[string]UIDEntry{ 651 "foo": newTempId("fooID", 1), 652 "bar": newTempId("barID", 2), 653 }, 654 optOut: false, 655 }) 656 657 existingCookie, _ := ToHTTPCookie(&cookie) 658 659 testCases := []struct { 660 description string 661 givenExistingCookies []*http.Cookie 662 expectedEmpty bool 663 expectedSetOptOut bool 664 }{ 665 { 666 description: "Opt Out Cookie", 667 givenExistingCookies: []*http.Cookie{ 668 existingCookie, 669 {Name: optOutCookieName, Value: optOutCookieValue}}, 670 expectedEmpty: true, 671 expectedSetOptOut: true, 672 }, 673 { 674 description: "No Opt Out Cookie", 675 givenExistingCookies: []*http.Cookie{ 676 existingCookie}, 677 expectedEmpty: false, 678 expectedSetOptOut: false, 679 }, 680 { 681 description: "Opt Out Cookie - Wrong Value", 682 givenExistingCookies: []*http.Cookie{ 683 existingCookie, 684 {Name: optOutCookieName, Value: "wrong"}}, 685 expectedEmpty: false, 686 expectedSetOptOut: false, 687 }, 688 { 689 description: "Opt Out Cookie - Wrong Name", 690 givenExistingCookies: []*http.Cookie{ 691 existingCookie, 692 {Name: "wrong", Value: optOutCookieValue}}, 693 expectedEmpty: false, 694 expectedSetOptOut: false, 695 }, 696 { 697 description: "Opt Out Cookie - No Host Cookies", 698 givenExistingCookies: []*http.Cookie{ 699 {Name: optOutCookieName, Value: optOutCookieValue}}, 700 expectedEmpty: true, 701 expectedSetOptOut: true, 702 }, 703 } 704 705 for _, test := range testCases { 706 req := httptest.NewRequest("POST", "http://www.prebid.com", nil) 707 708 for _, c := range test.givenExistingCookies { 709 req.AddCookie(c) 710 } 711 712 parsed := ReadCookie(req, decoder, &config.HostCookie{ 713 Family: "foo", 714 OptOutCookie: config.Cookie{ 715 Name: optOutCookieName, 716 Value: optOutCookieValue, 717 }, 718 }) 719 720 if test.expectedEmpty { 721 assert.Empty(t, parsed.uids, test.description+":empty") 722 } else { 723 assert.NotEmpty(t, parsed.uids, test.description+":not-empty") 724 } 725 assert.Equal(t, parsed.optOut, test.expectedSetOptOut, test.description+":opt-out") 726 } 727 } 728 729 func TestOptIn(t *testing.T) { 730 cookie := &Cookie{ 731 uids: make(map[string]UIDEntry), 732 optOut: true, 733 } 734 735 cookie.SetOptOut(false) 736 if !cookie.AllowSyncs() { 737 t.Error("After SetOptOut(false), a cookie should allow more user syncs.") 738 } 739 ensureConsistency(t, cookie) 740 } 741 742 func TestOptOutReset(t *testing.T) { 743 cookie := newSampleCookie() 744 745 cookie.SetOptOut(true) 746 if cookie.AllowSyncs() { 747 t.Error("After SetOptOut(true), a cookie should not allow more user syncs.") 748 } 749 ensureConsistency(t, cookie) 750 } 751 752 func TestOptOutCookie(t *testing.T) { 753 cookie := &Cookie{ 754 uids: make(map[string]UIDEntry), 755 optOut: true, 756 } 757 ensureConsistency(t, cookie) 758 } 759 760 func newTempId(uid string, offset int) UIDEntry { 761 return UIDEntry{ 762 UID: uid, 763 Expires: time.Now().Add(time.Duration(offset) * time.Minute).UTC(), 764 } 765 } 766 767 func newSampleCookie() *Cookie { 768 return &Cookie{ 769 uids: map[string]UIDEntry{ 770 "adnxs": newTempId("123", 10), 771 "rubicon": newTempId("456", 10), 772 }, 773 optOut: false, 774 } 775 } 776 777 func ensureConsistency(t *testing.T, cookie *Cookie) { 778 decoder := Base64Decoder{} 779 780 if cookie.AllowSyncs() { 781 err := cookie.Sync("pulsepoint", "1") 782 if err != nil { 783 t.Errorf("Cookie sync should succeed if the user has opted in.") 784 } 785 if !cookie.HasLiveSync("pulsepoint") { 786 t.Errorf("The PBSCookie should have a usersync after a successful call to TrySync") 787 } 788 savedUID, hadSync, isLive := cookie.GetUID("pulsepoint") 789 if !hadSync { 790 t.Error("The GetUID function should properly report that it has a sync.") 791 } 792 if !isLive { 793 t.Error("The GetUID function should properly report live syncs.") 794 } 795 if savedUID != "1" { 796 t.Errorf("The PBSCookie isn't saving syncs correctly. Expected %s, got %s", "1", savedUID) 797 } 798 cookie.Unsync("pulsepoint") 799 if cookie.HasLiveSync("pulsepoint") { 800 t.Errorf("The PBSCookie should not have have a usersync after a call to Unsync") 801 } 802 if value, hadValue, isLive := cookie.GetUID("pulsepoint"); value != "" || hadValue || isLive { 803 t.Error("PBSCookie.GetUID() should return empty strings if it doesn't have a sync") 804 } 805 } else { 806 if cookie.HasAnyLiveSyncs() { 807 t.Error("If the user opted out, the PBSCookie should have no user syncs.") 808 } 809 810 err := cookie.Sync("adnxs", "123") 811 if err == nil { 812 t.Error("TrySync should fail if the user has opted out of PBSCookie syncs, but it succeeded.") 813 } 814 } 815 httpCookie, err := ToHTTPCookie(cookie) 816 assert.NoError(t, err) 817 copiedCookie := decoder.Decode(httpCookie.Value) 818 if copiedCookie.AllowSyncs() != cookie.AllowSyncs() { 819 t.Error("The PBSCookie interface shouldn't let modifications happen if the user has opted out") 820 } 821 822 if cookie.optOut { 823 assert.Equal(t, 0, len(copiedCookie.uids), "Incorrect sync count on reparsed cookie.") 824 } else { 825 assert.Equal(t, len(cookie.uids), len(copiedCookie.uids), "Incorrect sync count on reparsed cookie.") 826 } 827 828 for family, uid := range copiedCookie.uids { 829 if !cookie.HasLiveSync(family) { 830 t.Errorf("Cookie is missing sync for family %s", family) 831 } 832 savedUID, hadSync, isLive := cookie.GetUID(family) 833 if !hadSync { 834 t.Error("The GetUID function should properly report that it has a sync.") 835 } 836 if !isLive { 837 t.Error("The GetUID function should properly report live syncs.") 838 } 839 if savedUID != uid.UID { 840 t.Errorf("Wrong UID saved for family %s. Expected %s, got %s", family, uid, savedUID) 841 } 842 } 843 } 844 845 func ToHTTPCookie(cookie *Cookie) (*http.Cookie, error) { 846 encoder := Base64Encoder{} 847 encodedCookie, err := encoder.Encode(cookie) 848 if err != nil { 849 return nil, nil 850 } 851 852 return &http.Cookie{ 853 Name: uidCookieName, 854 Value: encodedCookie, 855 Expires: time.Now().Add((90 * 24 * time.Hour)), 856 Path: "/", 857 }, nil 858 }