github.com/prebid/prebid-server/v2@v2.18.0/privacy/ccpa/policy_test.go (about) 1 package ccpa 2 3 import ( 4 "encoding/json" 5 "errors" 6 "testing" 7 8 gpplib "github.com/prebid/go-gpp" 9 gppConstants "github.com/prebid/go-gpp/constants" 10 "github.com/prebid/openrtb/v20/openrtb2" 11 "github.com/prebid/prebid-server/v2/openrtb_ext" 12 "github.com/stretchr/testify/assert" 13 ) 14 15 func TestReadFromRequestWrapper(t *testing.T) { 16 testCases := []struct { 17 description string 18 request *openrtb2.BidRequest 19 giveGPP gpplib.GppContainer 20 expectedPolicy Policy 21 expectedError bool 22 }{ 23 { 24 description: "Success", 25 request: &openrtb2.BidRequest{ 26 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 27 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 28 }, 29 expectedPolicy: Policy{ 30 Consent: "ABC", 31 NoSaleBidders: []string{"a", "b"}, 32 }, 33 }, 34 { 35 description: "Nil Request", 36 request: nil, 37 expectedPolicy: Policy{ 38 Consent: "", 39 NoSaleBidders: nil, 40 }, 41 }, 42 { 43 description: "Nil Regs", 44 request: &openrtb2.BidRequest{ 45 Regs: nil, 46 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 47 }, 48 expectedPolicy: Policy{ 49 Consent: "", 50 NoSaleBidders: []string{"a", "b"}, 51 }, 52 }, 53 { 54 description: "Nil Regs.Ext", 55 request: &openrtb2.BidRequest{ 56 Regs: &openrtb2.Regs{}, 57 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 58 }, 59 expectedPolicy: Policy{ 60 Consent: "", 61 NoSaleBidders: []string{"a", "b"}, 62 }, 63 }, 64 { 65 description: "Empty Regs.Ext", 66 request: &openrtb2.BidRequest{ 67 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{}`)}, 68 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 69 }, 70 expectedPolicy: Policy{ 71 Consent: "", 72 NoSaleBidders: []string{"a", "b"}, 73 }, 74 }, 75 { 76 description: "Missing Regs.Ext USPrivacy Value", 77 request: &openrtb2.BidRequest{ 78 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"anythingElse":"42"}`)}, 79 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 80 }, 81 expectedPolicy: Policy{ 82 Consent: "", 83 NoSaleBidders: []string{"a", "b"}, 84 }, 85 }, 86 { 87 description: "Malformed Regs.Ext", 88 request: &openrtb2.BidRequest{ 89 Regs: &openrtb2.Regs{Ext: json.RawMessage(`malformed`)}, 90 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 91 }, 92 expectedError: true, 93 }, 94 { 95 description: "Invalid Regs.Ext Type", 96 request: &openrtb2.BidRequest{ 97 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":123`)}, 98 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 99 }, 100 expectedError: true, 101 }, 102 { 103 description: "Nil Ext", 104 request: &openrtb2.BidRequest{ 105 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 106 Ext: nil, 107 }, 108 expectedPolicy: Policy{ 109 Consent: "ABC", 110 NoSaleBidders: nil, 111 }, 112 }, 113 { 114 description: "Empty Ext", 115 request: &openrtb2.BidRequest{ 116 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 117 Ext: json.RawMessage(`{}`), 118 }, 119 expectedPolicy: Policy{ 120 Consent: "ABC", 121 NoSaleBidders: nil, 122 }, 123 }, 124 { 125 description: "Missing Ext.Prebid No Sale Value", 126 request: &openrtb2.BidRequest{ 127 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 128 Ext: json.RawMessage(`{"anythingElse":"42"}`), 129 }, 130 expectedPolicy: Policy{ 131 Consent: "ABC", 132 NoSaleBidders: nil, 133 }, 134 }, 135 { 136 description: "Malformed Ext", 137 request: &openrtb2.BidRequest{ 138 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 139 Ext: json.RawMessage(`malformed`), 140 }, 141 expectedError: true, 142 }, 143 { 144 description: "Invalid Ext.Prebid.NoSale Type", 145 request: &openrtb2.BidRequest{ 146 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 147 Ext: json.RawMessage(`{"prebid":{"nosale":"wrongtype"}}`), 148 }, 149 expectedError: true, 150 }, 151 { 152 description: "Injection Attack", 153 request: &openrtb2.BidRequest{ 154 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"1YYY\"},\"oops\":\"malicious\",\"p\":{\"p\":\""}`)}, 155 }, 156 expectedPolicy: Policy{ 157 Consent: "1YYY\"},\"oops\":\"malicious\",\"p\":{\"p\":\"", 158 }, 159 }, 160 { 161 description: "GPP Success", 162 request: &openrtb2.BidRequest{ 163 Regs: &openrtb2.Regs{GPP: "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~present", 164 GPPSID: []int8{6}}, 165 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 166 }, 167 giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{6}, Sections: []gpplib.Section{&upsv1Section}}, 168 expectedPolicy: Policy{ 169 Consent: "gppContainerConsent", 170 NoSaleBidders: []string{"a", "b"}, 171 }, 172 }, 173 { 174 description: "GPP Success, has Regs.ext", 175 request: &openrtb2.BidRequest{ 176 Regs: &openrtb2.Regs{GPP: "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~present", 177 GPPSID: []int8{6}, 178 Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 179 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 180 }, 181 giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{6}, Sections: []gpplib.Section{&upsv1Section}}, 182 expectedPolicy: Policy{ 183 Consent: "gppContainerConsent", 184 NoSaleBidders: []string{"a", "b"}, 185 }, 186 }, 187 { 188 description: "GPP Success, has regs.us_privacy", 189 request: &openrtb2.BidRequest{ 190 Regs: &openrtb2.Regs{GPP: "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~present", 191 GPPSID: []int8{6}, 192 USPrivacy: "conflicting"}, 193 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 194 }, 195 giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{6}, Sections: []gpplib.Section{&upsv1Section}}, 196 expectedPolicy: Policy{ 197 Consent: "gppContainerConsent", 198 NoSaleBidders: []string{"a", "b"}, 199 }, 200 expectedError: true, 201 }, 202 { 203 description: "Has regs.us_privacy", 204 request: &openrtb2.BidRequest{ 205 Regs: &openrtb2.Regs{USPrivacy: "present"}, 206 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 207 }, 208 expectedPolicy: Policy{ 209 Consent: "present", 210 NoSaleBidders: []string{"a", "b"}, 211 }, 212 expectedError: false, 213 }, 214 { 215 description: "GPP Success, no USPV1", 216 request: &openrtb2.BidRequest{ 217 Regs: &openrtb2.Regs{GPP: "DBABMA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA", 218 GPPSID: []int8{6}}, 219 }, 220 giveGPP: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{2}, Sections: []gpplib.Section{&tcf1Section}}, 221 expectedPolicy: Policy{ 222 Consent: "", 223 }, 224 }, 225 } 226 227 for _, test := range testCases { 228 t.Run(test.description, func(t *testing.T) { 229 reqWrapper := &openrtb_ext.RequestWrapper{BidRequest: test.request} 230 result, err := ReadFromRequestWrapper(reqWrapper, test.giveGPP) 231 assertError(t, test.expectedError, err, test.description) 232 assert.Equal(t, test.expectedPolicy, result) 233 }) 234 } 235 } 236 237 func TestReadFromRequest(t *testing.T) { 238 testCases := []struct { 239 description string 240 request *openrtb2.BidRequest 241 expectedPolicy Policy 242 expectedError bool 243 }{ 244 { 245 description: "Success", 246 request: &openrtb2.BidRequest{ 247 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 248 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 249 }, 250 expectedPolicy: Policy{ 251 Consent: "ABC", 252 NoSaleBidders: []string{"a", "b"}, 253 }, 254 }, 255 { 256 description: "Nil Request", 257 request: nil, 258 expectedPolicy: Policy{ 259 Consent: "", 260 NoSaleBidders: nil, 261 }, 262 }, 263 { 264 description: "Nil Regs", 265 request: &openrtb2.BidRequest{ 266 Regs: nil, 267 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 268 }, 269 expectedPolicy: Policy{ 270 Consent: "", 271 NoSaleBidders: []string{"a", "b"}, 272 }, 273 }, 274 { 275 description: "GPP Success", 276 request: &openrtb2.BidRequest{ 277 Regs: &openrtb2.Regs{GPP: "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN", 278 GPPSID: []int8{6}}, 279 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 280 }, 281 expectedPolicy: Policy{ 282 Consent: "1YNN", 283 NoSaleBidders: []string{"a", "b"}, 284 }, 285 }, 286 { 287 description: "GPP Success, has Regs.ext", 288 request: &openrtb2.BidRequest{ 289 Regs: &openrtb2.Regs{GPP: "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN", 290 GPPSID: []int8{6}, 291 Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 292 Ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 293 }, 294 expectedPolicy: Policy{ 295 Consent: "1YNN", 296 NoSaleBidders: []string{"a", "b"}, 297 }, 298 }, 299 { 300 description: "GPP Success, no USPV1", 301 request: &openrtb2.BidRequest{ 302 Regs: &openrtb2.Regs{GPP: "DBABMA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA", 303 GPPSID: []int8{6}}}, 304 expectedPolicy: Policy{ 305 Consent: "", 306 }, 307 }, 308 { 309 description: "GPP Success, no signal", 310 request: &openrtb2.BidRequest{ 311 Regs: &openrtb2.Regs{GPP: "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN", 312 GPPSID: []int8{}}}, 313 expectedPolicy: Policy{ 314 Consent: "", 315 }, 316 }, 317 { 318 description: "GPP Success, wrong signal", 319 request: &openrtb2.BidRequest{ 320 Regs: &openrtb2.Regs{GPP: "DBACNYA~CPXxRfAPXxRfAAfKABENB-CgAAAAAAAAAAYgAAAAAAAA~1YNN", 321 GPPSID: []int8{2}}}, 322 expectedPolicy: Policy{ 323 Consent: "", 324 }, 325 }, 326 } 327 328 for _, test := range testCases { 329 t.Run(test.description, func(t *testing.T) { 330 result, err := ReadFromRequest(test.request) 331 assertError(t, test.expectedError, err, test.description) 332 assert.Equal(t, test.expectedPolicy, result) 333 }) 334 } 335 } 336 337 func TestWrite(t *testing.T) { 338 testCases := []struct { 339 description string 340 policy Policy 341 request *openrtb2.BidRequest 342 expected *openrtb2.BidRequest 343 expectedError bool 344 }{ 345 { 346 description: "Nil Request", 347 policy: Policy{Consent: "anyConsent", NoSaleBidders: []string{"a", "b"}}, 348 request: nil, 349 expected: nil, 350 }, 351 { 352 description: "Success", 353 policy: Policy{Consent: "anyConsent", NoSaleBidders: []string{"a", "b"}}, 354 request: &openrtb2.BidRequest{}, 355 expected: &openrtb2.BidRequest{ 356 Regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"anyConsent"}`)}, 357 Ext: json.RawMessage(`{"prebid":{"nosale":["a","b"]}}`), 358 }, 359 }, 360 { 361 description: "Error Regs.Ext - No Partial Update To Request", 362 policy: Policy{Consent: "anyConsent", NoSaleBidders: []string{"a", "b"}}, 363 request: &openrtb2.BidRequest{ 364 Regs: &openrtb2.Regs{Ext: json.RawMessage(`malformed}`)}, 365 }, 366 expectedError: true, 367 expected: &openrtb2.BidRequest{ 368 Regs: &openrtb2.Regs{Ext: json.RawMessage(`malformed}`)}, 369 }, 370 }, 371 { 372 description: "Error Ext - No Partial Update To Request", 373 policy: Policy{Consent: "anyConsent", NoSaleBidders: []string{"a", "b"}}, 374 request: &openrtb2.BidRequest{ 375 Ext: json.RawMessage(`malformed}`), 376 }, 377 expectedError: true, 378 expected: &openrtb2.BidRequest{ 379 Ext: json.RawMessage(`malformed}`), 380 }, 381 }, 382 } 383 384 for _, test := range testCases { 385 reqWrapper := &openrtb_ext.RequestWrapper{BidRequest: test.request} 386 var err error 387 _, err = reqWrapper.GetRegExt() 388 if err == nil { 389 _, err = reqWrapper.GetRequestExt() 390 if err == nil { 391 err = test.policy.Write(reqWrapper) 392 if err == nil && reqWrapper.BidRequest != nil { 393 err = reqWrapper.RebuildRequest() 394 } 395 } 396 } 397 assertError(t, test.expectedError, err, test.description) 398 assert.Equal(t, test.expected, reqWrapper.BidRequest, test.description) 399 } 400 } 401 402 func TestBuildRegs(t *testing.T) { 403 testCases := []struct { 404 description string 405 consent string 406 regs *openrtb2.Regs 407 expected *openrtb2.Regs 408 expectedError bool 409 }{ 410 { 411 description: "Clear", 412 consent: "", 413 regs: &openrtb2.Regs{ 414 Ext: json.RawMessage(`{"us_privacy":"ABC"}`), 415 }, 416 expected: &openrtb2.Regs{}, 417 }, 418 { 419 description: "Clear - Error", 420 consent: "", 421 regs: &openrtb2.Regs{ 422 Ext: json.RawMessage(`malformed`), 423 }, 424 expected: &openrtb2.Regs{ 425 Ext: json.RawMessage(`malformed`), 426 }, 427 expectedError: true, 428 }, 429 { 430 description: "Write", 431 consent: "anyConsent", 432 regs: nil, 433 expected: &openrtb2.Regs{ 434 Ext: json.RawMessage(`{"us_privacy":"anyConsent"}`), 435 }, 436 }, 437 { 438 description: "Write - Error", 439 consent: "anyConsent", 440 regs: &openrtb2.Regs{ 441 Ext: json.RawMessage(`malformed`), 442 }, 443 expected: &openrtb2.Regs{ 444 Ext: json.RawMessage(`malformed`), 445 }, 446 expectedError: true, 447 }, 448 } 449 450 for _, test := range testCases { 451 request := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{Regs: test.regs}} 452 regsExt, err := request.GetRegExt() 453 if err == nil { 454 regsExt.SetUSPrivacy(test.consent) 455 request.RebuildRequest() 456 } 457 assertError(t, test.expectedError, err, test.description) 458 assert.Equal(t, test.expected, request.Regs, test.description) 459 } 460 } 461 462 func TestBuildRegsClear(t *testing.T) { 463 testCases := []struct { 464 description string 465 regs *openrtb2.Regs 466 expected *openrtb2.Regs 467 expectedError bool 468 }{ 469 { 470 description: "Nil Regs", 471 regs: nil, 472 expected: nil, 473 }, 474 { 475 description: "Nil Regs.Ext", 476 regs: &openrtb2.Regs{Ext: nil}, 477 expected: &openrtb2.Regs{Ext: nil}, 478 }, 479 { 480 description: "Empty Regs.Ext", 481 regs: &openrtb2.Regs{Ext: json.RawMessage(`{}`)}, 482 expected: &openrtb2.Regs{}, 483 }, 484 { 485 description: "Removes Regs.Ext Entirely", 486 regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 487 expected: &openrtb2.Regs{}, 488 }, 489 { 490 description: "Leaves Other Regs.Ext Values", 491 regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC", "other":"any"}`)}, 492 expected: &openrtb2.Regs{Ext: json.RawMessage(`{"other":"any"}`)}, 493 }, 494 { 495 description: "Invalid Regs.Ext Type - Returns Error, doesn't clear", 496 regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":123}`)}, 497 expected: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":123}`)}, 498 expectedError: true, 499 }, 500 { 501 description: "Malformed Regs.Ext", 502 regs: &openrtb2.Regs{Ext: json.RawMessage(`malformed`)}, 503 expected: &openrtb2.Regs{Ext: json.RawMessage(`malformed`)}, 504 expectedError: true, 505 }, 506 } 507 508 for _, test := range testCases { 509 request := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{Regs: test.regs}} 510 regsExt, err := request.GetRegExt() 511 if err == nil { 512 regsExt.SetUSPrivacy("") 513 request.RebuildRequest() 514 } 515 assertError(t, test.expectedError, err, test.description) 516 assert.Equal(t, test.expected, request.Regs, test.description) 517 } 518 } 519 520 func TestBuildRegsWrite(t *testing.T) { 521 testCases := []struct { 522 description string 523 consent string 524 regs *openrtb2.Regs 525 expected *openrtb2.Regs 526 expectedError bool 527 }{ 528 { 529 description: "Nil Regs", 530 consent: "anyConsent", 531 regs: nil, 532 expected: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"anyConsent"}`)}, 533 }, 534 { 535 description: "Nil Regs.Ext", 536 consent: "anyConsent", 537 regs: &openrtb2.Regs{Ext: nil}, 538 expected: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"anyConsent"}`)}, 539 }, 540 { 541 description: "Empty Regs.Ext", 542 consent: "anyConsent", 543 regs: &openrtb2.Regs{Ext: json.RawMessage(`{}`)}, 544 expected: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"anyConsent"}`)}, 545 }, 546 { 547 description: "Overwrites Existing", 548 consent: "anyConsent", 549 regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"ABC"}`)}, 550 expected: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":"anyConsent"}`)}, 551 }, 552 { 553 description: "Leaves Other Ext Values", 554 consent: "anyConsent", 555 regs: &openrtb2.Regs{Ext: json.RawMessage(`{"other":"any"}`)}, 556 expected: &openrtb2.Regs{Ext: json.RawMessage(`{"other":"any","us_privacy":"anyConsent"}`)}, 557 }, 558 { 559 description: "Invalid Regs.Ext Type - Doesn't Overwrite", 560 consent: "anyConsent", 561 regs: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":123}`)}, 562 expected: &openrtb2.Regs{Ext: json.RawMessage(`{"us_privacy":123}`)}, 563 expectedError: true, 564 }, 565 { 566 description: "Malformed Regs.Ext", 567 consent: "anyConsent", 568 regs: &openrtb2.Regs{Ext: json.RawMessage(`malformed`)}, 569 expected: &openrtb2.Regs{Ext: json.RawMessage(`malformed`)}, 570 expectedError: true, 571 }, 572 } 573 574 for _, test := range testCases { 575 request := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{Regs: test.regs}} 576 regsExt, err := request.GetRegExt() 577 if err == nil { 578 regsExt.SetUSPrivacy(test.consent) 579 request.RebuildRequest() 580 } 581 assertError(t, test.expectedError, err, test.description) 582 assert.Equal(t, test.expected, request.Regs, test.description) 583 } 584 } 585 586 func TestBuildExt(t *testing.T) { 587 testCases := []struct { 588 description string 589 noSaleBidders []string 590 ext json.RawMessage 591 expected json.RawMessage 592 expectedError bool 593 }{ 594 { 595 description: "Clear - Nil", 596 noSaleBidders: nil, 597 ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 598 expected: nil, 599 }, 600 { 601 description: "Clear - Empty", 602 noSaleBidders: []string{}, 603 ext: json.RawMessage(`{"prebid":{"nosale":["a", "b"]}}`), 604 expected: nil, 605 }, 606 { 607 description: "Clear - Error", 608 noSaleBidders: []string{}, 609 ext: json.RawMessage(`malformed`), 610 expectedError: true, 611 }, 612 { 613 description: "Write", 614 noSaleBidders: []string{"a", "b"}, 615 ext: nil, 616 expected: json.RawMessage(`{"prebid":{"nosale":["a","b"]}}`), 617 }, 618 { 619 description: "Write - Error", 620 noSaleBidders: []string{"a", "b"}, 621 ext: json.RawMessage(`malformed`), 622 expectedError: true, 623 }, 624 } 625 626 for _, test := range testCases { 627 request := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{Ext: test.ext}} 628 reqExt, err := request.GetRequestExt() 629 var result json.RawMessage 630 if err == nil { 631 setPrebidNoSale(test.noSaleBidders, reqExt) 632 err = request.RebuildRequest() 633 result = request.Ext 634 } 635 assertError(t, test.expectedError, err, test.description) 636 assert.Equal(t, test.expected, result, test.description) 637 } 638 } 639 640 func TestBuildExtClear(t *testing.T) { 641 testCases := []struct { 642 description string 643 ext json.RawMessage 644 expected json.RawMessage 645 expectedError bool 646 }{ 647 { 648 description: "Nil Ext", 649 ext: nil, 650 expected: nil, 651 }, 652 { 653 description: "Empty Ext", 654 ext: json.RawMessage(``), 655 expected: json.RawMessage(``), 656 }, 657 { 658 description: "Empty Ext Object", 659 ext: json.RawMessage(`{}`), 660 expected: json.RawMessage(`{}`), 661 }, 662 { 663 description: "Empty Ext.Prebid", 664 ext: json.RawMessage(`{"prebid":{}}`), 665 expected: nil, 666 }, 667 { 668 description: "Removes Ext Entirely", 669 ext: json.RawMessage(`{"prebid":{"nosale":["a","b"]}}`), 670 expected: nil, 671 }, 672 { 673 description: "Leaves Other Ext Values", 674 ext: json.RawMessage(`{"other":"any","prebid":{"nosale":["a","b"]}}`), 675 expected: json.RawMessage(`{"other":"any"}`), 676 }, 677 { 678 description: "Leaves Other Ext.Prebid Values", 679 ext: json.RawMessage(`{"prebid":{"nosale":["a","b"],"aliases":{"a":"b"}}}`), 680 expected: json.RawMessage(`{"prebid":{"aliases":{"a":"b"}}}`), 681 }, 682 { 683 description: "Leaves All Other Values", 684 ext: json.RawMessage(`{"other":"ABC","prebid":{"nosale":["a","b"],"supportdeals":true}}`), 685 expected: json.RawMessage(`{"other":"ABC","prebid":{"supportdeals":true}}`), 686 }, 687 { 688 description: "Malformed Ext", 689 ext: json.RawMessage(`malformed`), 690 expectedError: true, 691 }, 692 { 693 description: "Malformed Ext.Prebid", 694 ext: json.RawMessage(`{"prebid":malformed}`), 695 expectedError: true, 696 }, 697 { 698 description: "Invalid Ext.Prebid Type", 699 ext: json.RawMessage(`{"prebid":123}`), 700 expectedError: true, 701 }, 702 } 703 704 for _, test := range testCases { 705 request := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{Ext: test.ext}} 706 reqExt, err := request.GetRequestExt() 707 var result json.RawMessage 708 if err == nil { 709 setPrebidNoSaleClear(reqExt) 710 err = request.RebuildRequest() 711 result = request.Ext 712 } 713 assertError(t, test.expectedError, err, test.description) 714 assert.Equal(t, test.expected, result, test.description) 715 } 716 } 717 718 func TestBuildExtWrite(t *testing.T) { 719 testCases := []struct { 720 description string 721 noSaleBidders []string 722 ext json.RawMessage 723 expected json.RawMessage 724 expectedError bool 725 }{ 726 { 727 description: "Nil Ext", 728 noSaleBidders: []string{"a", "b"}, 729 ext: nil, 730 expected: json.RawMessage(`{"prebid":{"nosale":["a","b"]}}`), 731 }, 732 { 733 description: "Empty Ext", 734 noSaleBidders: []string{"a", "b"}, 735 ext: json.RawMessage(``), 736 expected: json.RawMessage(`{"prebid":{"nosale":["a","b"]}}`), 737 }, 738 { 739 description: "Empty Ext Object", 740 noSaleBidders: []string{"a", "b"}, 741 ext: json.RawMessage(`{}`), 742 expected: json.RawMessage(`{"prebid":{"nosale":["a","b"]}}`), 743 }, 744 { 745 description: "Empty Ext.Prebid", 746 noSaleBidders: []string{"a", "b"}, 747 ext: json.RawMessage(`{"prebid":{}}`), 748 expected: json.RawMessage(`{"prebid":{"nosale":["a","b"]}}`), 749 }, 750 { 751 description: "Overwrites Existing", 752 noSaleBidders: []string{"a", "b"}, 753 ext: json.RawMessage(`{"prebid":{"nosale":["x","y"]}}`), 754 expected: json.RawMessage(`{"prebid":{"nosale":["a","b"]}}`), 755 }, 756 { 757 description: "Leaves Other Ext Values", 758 noSaleBidders: []string{"a", "b"}, 759 ext: json.RawMessage(`{"other":"any"}`), 760 expected: json.RawMessage(`{"other":"any","prebid":{"nosale":["a","b"]}}`), 761 }, 762 { 763 description: "Leaves Other Ext.Prebid Values", 764 noSaleBidders: []string{"a", "b"}, 765 ext: json.RawMessage(`{"prebid":{"supportdeals":true}}`), 766 expected: json.RawMessage(`{"prebid":{"supportdeals":true,"nosale":["a","b"]}}`), 767 }, 768 { 769 description: "Leaves All Other Values", 770 noSaleBidders: []string{"a", "b"}, 771 ext: json.RawMessage(`{"other":"ABC","prebid":{"aliases":{"a":"b"}}}`), 772 expected: json.RawMessage(`{"other":"ABC","prebid":{"aliases":{"a":"b"},"nosale":["a","b"]}}`), 773 }, 774 { 775 description: "Invalid Ext.Prebid No Sale Type - Still Overrides", 776 noSaleBidders: []string{"a", "b"}, 777 ext: json.RawMessage(`{"prebid":{"nosale":123}}`), 778 expected: json.RawMessage(`{"prebid":{"nosale":123}}`), 779 expectedError: true, 780 }, 781 { 782 description: "Invalid Ext.Prebid Type ", 783 noSaleBidders: []string{"a", "b"}, 784 ext: json.RawMessage(`{"prebid":"wrongtype"}`), 785 expected: json.RawMessage(`{"prebid":"wrongtype"}`), 786 expectedError: true, 787 }, 788 { 789 description: "Malformed Ext", 790 noSaleBidders: []string{"a", "b"}, 791 ext: json.RawMessage(`{malformed`), 792 expected: json.RawMessage(`{malformed`), 793 expectedError: true, 794 }, 795 { 796 description: "Malformed Ext.Prebid", 797 noSaleBidders: []string{"a", "b"}, 798 ext: json.RawMessage(`{"prebid":malformed}`), 799 expected: json.RawMessage(`{"prebid":malformed}`), 800 expectedError: true, 801 }, 802 } 803 804 for _, test := range testCases { 805 request := &openrtb_ext.RequestWrapper{BidRequest: &openrtb2.BidRequest{Ext: test.ext}} 806 reqExt, err := request.GetRequestExt() 807 var result json.RawMessage 808 if err == nil { 809 setPrebidNoSaleWrite(test.noSaleBidders, reqExt) 810 err = request.RebuildRequest() 811 result = request.Ext 812 } else { 813 result = test.ext 814 } 815 assertError(t, test.expectedError, err, test.description) 816 assert.Equal(t, test.expected, result, test.description) 817 } 818 } 819 820 func TestSelectCCPAConsent(t *testing.T) { 821 type testInput struct { 822 requestUSPrivacy string 823 gpp gpplib.GppContainer 824 gppSIDs []int8 825 } 826 testCases := []struct { 827 desc string 828 in testInput 829 expectedCCPA string 830 expectedErr error 831 }{ 832 { 833 desc: "SectionUSPV1 in both GPP_SID and GPP container. Consent equal to request US_Privacy. Expect valid string and nil error", 834 in: testInput{ 835 requestUSPrivacy: "gppContainerConsent", 836 gpp: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{gppConstants.SectionUSPV1}, Sections: []gpplib.Section{upsv1Section}}, 837 gppSIDs: []int8{int8(6)}, 838 }, 839 expectedCCPA: "gppContainerConsent", 840 expectedErr: nil, 841 }, 842 { 843 desc: "No SectionUSPV1 in GPP_SID array expect request US_Privacy", 844 in: testInput{ 845 requestUSPrivacy: "requestConsent", 846 gpp: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{gppConstants.SectionUSPV1}, Sections: []gpplib.Section{upsv1Section}}, 847 gppSIDs: []int8{int8(2), int8(4)}, 848 }, 849 expectedCCPA: "requestConsent", 850 expectedErr: nil, 851 }, 852 { 853 desc: "No SectionUSPV1 in gpp.SectionTypes array expect request US_Privacy", 854 in: testInput{ 855 requestUSPrivacy: "requestConsent", 856 gpp: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{}, Sections: []gpplib.Section{upsv1Section}}, 857 gppSIDs: []int8{int8(6)}, 858 }, 859 expectedCCPA: "requestConsent", 860 expectedErr: nil, 861 }, 862 { 863 desc: "No SectionUSPV1 in GPP_SID array, blank request US_Privacy, expect blank consent", 864 in: testInput{ 865 requestUSPrivacy: "", 866 gpp: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{gppConstants.SectionUSPV1}, Sections: []gpplib.Section{upsv1Section}}, 867 gppSIDs: []int8{int8(2), int8(4)}, 868 }, 869 expectedCCPA: "", 870 expectedErr: nil, 871 }, 872 { 873 desc: "No SectionUSPV1 in gpp.SectionTypes array, blank request US_Privacy, expect blank consent", 874 in: testInput{ 875 requestUSPrivacy: "", 876 gpp: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{}, Sections: []gpplib.Section{upsv1Section}}, 877 gppSIDs: []int8{int8(6)}, 878 }, 879 expectedCCPA: "", 880 expectedErr: nil, 881 }, 882 { 883 desc: "SectionUSPV1 in both GPP_SID and GPP container. Consent equal to request US_Privacy. Expect valid string and nil error", 884 in: testInput{ 885 requestUSPrivacy: "requestConsent", 886 gpp: gpplib.GppContainer{Version: 1, SectionTypes: []gppConstants.SectionID{gppConstants.SectionUSPV1}, Sections: []gpplib.Section{upsv1Section}}, 887 gppSIDs: []int8{int8(6)}, 888 }, 889 expectedCCPA: "gppContainerConsent", 890 expectedErr: errors.New("request.us_privacy consent does not match uspv1"), 891 }, 892 } 893 for _, tc := range testCases { 894 out, outErr := SelectCCPAConsent(tc.in.requestUSPrivacy, tc.in.gpp, tc.in.gppSIDs) 895 896 assert.Equal(t, tc.expectedCCPA, out, tc.desc) 897 assert.Equal(t, tc.expectedErr, outErr, tc.desc) 898 } 899 } 900 901 func assertError(t *testing.T, expectError bool, err error, description string) { 902 t.Helper() 903 if expectError { 904 assert.Error(t, err, description) 905 } else { 906 assert.NoError(t, err, description) 907 } 908 } 909 910 var upsv1Section mockGPPSection = mockGPPSection{sectionID: 6, value: "gppContainerConsent"} 911 var tcf1Section mockGPPSection = mockGPPSection{sectionID: 2, value: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA"} 912 913 type mockGPPSection struct { 914 sectionID gppConstants.SectionID 915 value string 916 } 917 918 func (ms mockGPPSection) GetID() gppConstants.SectionID { 919 return ms.sectionID 920 } 921 922 func (ms mockGPPSection) GetValue() string { 923 return ms.value 924 } 925 926 func (ms mockGPPSection) Encode(bool) []byte { 927 return nil 928 }