github.com/prebid/prebid-server/v2@v2.18.0/ortb/default_test.go (about) 1 package ortb 2 3 import ( 4 "encoding/json" 5 "testing" 6 7 "github.com/prebid/openrtb/v20/openrtb2" 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/prebid/prebid-server/v2/errortypes" 12 "github.com/prebid/prebid-server/v2/openrtb_ext" 13 "github.com/prebid/prebid-server/v2/util/jsonutil" 14 "github.com/prebid/prebid-server/v2/util/ptrutil" 15 ) 16 17 func TestSetDefaults(t *testing.T) { 18 secure0 := int8(0) 19 secure1 := int8(1) 20 21 testCases := []struct { 22 name string 23 givenRequest openrtb2.BidRequest 24 expectedRequest openrtb2.BidRequest 25 expectedErr string 26 }{ 27 { 28 name: "empty", 29 givenRequest: openrtb2.BidRequest{}, 30 expectedRequest: openrtb2.BidRequest{}, 31 }, 32 { 33 name: "malformed request.ext", 34 givenRequest: openrtb2.BidRequest{Ext: json.RawMessage(`malformed`)}, 35 expectedRequest: openrtb2.BidRequest{Ext: json.RawMessage(`malformed`)}, 36 expectedErr: "expect { or n, but found m", 37 }, 38 { 39 name: "targeting", // tests integration with setDefaultsTargeting 40 givenRequest: openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"targeting":{}}}`)}, 41 expectedRequest: openrtb2.BidRequest{Ext: json.RawMessage(`{"prebid":{"targeting":{"pricegranularity":{"precision":2,"ranges":[{"min":0,"max":20,"increment":0.1}]},"mediatypepricegranularity":{},"includewinners":true,"includebidderkeys":true}}}`)}, 42 }, 43 { 44 name: "imp", // tests integration with setDefaultsImp 45 givenRequest: openrtb2.BidRequest{Imp: []openrtb2.Imp{{Secure: &secure0}, {Secure: nil}}}, 46 expectedRequest: openrtb2.BidRequest{Imp: []openrtb2.Imp{{Secure: &secure0}, {Secure: &secure1}}}, 47 }, 48 } 49 50 for _, test := range testCases { 51 t.Run(test.name, func(t *testing.T) { 52 wrapper := &openrtb_ext.RequestWrapper{BidRequest: &test.givenRequest} 53 54 // run 55 err := SetDefaults(wrapper) 56 57 // assert error 58 if len(test.expectedErr) > 0 { 59 assert.EqualError(t, err, test.expectedErr, "Error") 60 assert.IsType(t, &errortypes.FailedToUnmarshal{}, err) 61 } 62 63 // rebuild request 64 require.NoError(t, wrapper.RebuildRequest(), "Rebuild Request") 65 66 // assert 67 if len(test.expectedErr) > 0 { 68 assert.EqualError(t, err, test.expectedErr, "Error") 69 assert.Equal(t, &test.expectedRequest, wrapper.BidRequest, "Request") 70 } else { 71 // assert request as json to ignore order in ext fields 72 expectedRequestJSON, err := jsonutil.Marshal(test.expectedRequest) 73 require.NoError(t, err, "Marshal Expected Request") 74 75 actualRequestJSON, err := jsonutil.Marshal(wrapper.BidRequest) 76 require.NoError(t, err, "Marshal Actual Request") 77 78 assert.JSONEq(t, string(expectedRequestJSON), string(actualRequestJSON), "Request") 79 } 80 }) 81 } 82 } 83 84 func TestSetDefaultsTargeting(t *testing.T) { 85 defaultGranularity := openrtb_ext.PriceGranularity{ 86 Precision: ptrutil.ToPtr(DefaultPriceGranularityPrecision), 87 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 20, Increment: 0.1}}, 88 } 89 90 testCases := []struct { 91 name string 92 givenTargeting *openrtb_ext.ExtRequestTargeting 93 expectedTargeting *openrtb_ext.ExtRequestTargeting 94 expectedModified bool 95 }{ 96 { 97 name: "nil", 98 givenTargeting: nil, 99 expectedTargeting: nil, 100 }, 101 { 102 name: "empty-targeting", 103 givenTargeting: &openrtb_ext.ExtRequestTargeting{}, 104 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 105 PriceGranularity: &defaultGranularity, 106 IncludeWinners: ptrutil.ToPtr(DefaultTargetingIncludeWinners), 107 IncludeBidderKeys: ptrutil.ToPtr(DefaultTargetingIncludeBidderKeys), 108 }, 109 expectedModified: true, 110 }, 111 { 112 name: "populated-partial", // precision and includewinners defaults set 113 givenTargeting: &openrtb_ext.ExtRequestTargeting{ 114 PriceGranularity: &openrtb_ext.PriceGranularity{ 115 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 116 }, 117 IncludeBidderKeys: ptrutil.ToPtr(false), 118 }, 119 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 120 PriceGranularity: &openrtb_ext.PriceGranularity{ 121 Precision: ptrutil.ToPtr(DefaultPriceGranularityPrecision), 122 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 123 }, 124 IncludeWinners: ptrutil.ToPtr(DefaultTargetingIncludeWinners), 125 IncludeBidderKeys: ptrutil.ToPtr(false), 126 }, 127 expectedModified: true, 128 }, 129 { 130 name: "populated-no-granularity", 131 givenTargeting: &openrtb_ext.ExtRequestTargeting{ 132 PriceGranularity: &openrtb_ext.PriceGranularity{}, 133 IncludeWinners: ptrutil.ToPtr(false), 134 IncludeBidderKeys: ptrutil.ToPtr(false), 135 }, 136 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 137 PriceGranularity: &defaultGranularity, 138 IncludeWinners: ptrutil.ToPtr(false), 139 IncludeBidderKeys: ptrutil.ToPtr(false), 140 }, 141 expectedModified: true, 142 }, 143 { 144 name: "populated-ranges-nil", 145 givenTargeting: &openrtb_ext.ExtRequestTargeting{ 146 PriceGranularity: &openrtb_ext.PriceGranularity{ 147 Precision: ptrutil.ToPtr(4), 148 Ranges: nil, 149 }, 150 }, 151 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 152 PriceGranularity: &defaultGranularity, 153 IncludeWinners: ptrutil.ToPtr(DefaultTargetingIncludeWinners), 154 IncludeBidderKeys: ptrutil.ToPtr(DefaultTargetingIncludeBidderKeys), 155 }, 156 expectedModified: true, 157 }, 158 { 159 name: "populated-ranges-nil-mediatypepricegranularity-video-banner-native", 160 givenTargeting: &openrtb_ext.ExtRequestTargeting{ 161 PriceGranularity: &openrtb_ext.PriceGranularity{ 162 Precision: ptrutil.ToPtr(4), 163 Ranges: nil, 164 }, 165 MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{ 166 Video: &openrtb_ext.PriceGranularity{ 167 Precision: ptrutil.ToPtr(4), 168 Ranges: nil, 169 }, 170 Banner: &openrtb_ext.PriceGranularity{ 171 Precision: ptrutil.ToPtr(4), 172 Ranges: nil, 173 }, 174 Native: &openrtb_ext.PriceGranularity{ 175 Precision: ptrutil.ToPtr(4), 176 Ranges: nil, 177 }, 178 }, 179 }, 180 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 181 PriceGranularity: &defaultGranularity, 182 MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{ 183 Video: &defaultGranularity, 184 Banner: &defaultGranularity, 185 Native: &defaultGranularity, 186 }, 187 IncludeWinners: ptrutil.ToPtr(DefaultTargetingIncludeWinners), 188 IncludeBidderKeys: ptrutil.ToPtr(DefaultTargetingIncludeBidderKeys), 189 }, 190 expectedModified: true, 191 }, 192 { 193 name: "populated-ranges-empty", 194 givenTargeting: &openrtb_ext.ExtRequestTargeting{ 195 PriceGranularity: &openrtb_ext.PriceGranularity{ 196 Precision: ptrutil.ToPtr(4), 197 Ranges: []openrtb_ext.GranularityRange{}, 198 }, 199 }, 200 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 201 PriceGranularity: &defaultGranularity, 202 IncludeWinners: ptrutil.ToPtr(DefaultTargetingIncludeWinners), 203 IncludeBidderKeys: ptrutil.ToPtr(DefaultTargetingIncludeBidderKeys), 204 }, 205 expectedModified: true, 206 }, 207 { 208 name: "populated-ranges-empty-mediatypepricegranularity-video-banner-native", 209 givenTargeting: &openrtb_ext.ExtRequestTargeting{ 210 PriceGranularity: &openrtb_ext.PriceGranularity{ 211 Precision: ptrutil.ToPtr(4), 212 Ranges: []openrtb_ext.GranularityRange{}, 213 }, 214 MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{ 215 Video: &openrtb_ext.PriceGranularity{ 216 Precision: ptrutil.ToPtr(4), 217 Ranges: []openrtb_ext.GranularityRange{}, 218 }, 219 Banner: &openrtb_ext.PriceGranularity{ 220 Precision: ptrutil.ToPtr(4), 221 Ranges: []openrtb_ext.GranularityRange{}, 222 }, 223 Native: &openrtb_ext.PriceGranularity{ 224 Precision: ptrutil.ToPtr(4), 225 Ranges: []openrtb_ext.GranularityRange{}, 226 }, 227 }, 228 }, 229 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 230 PriceGranularity: &defaultGranularity, 231 MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{ 232 Video: &defaultGranularity, 233 Banner: &defaultGranularity, 234 Native: &defaultGranularity, 235 }, 236 IncludeWinners: ptrutil.ToPtr(DefaultTargetingIncludeWinners), 237 IncludeBidderKeys: ptrutil.ToPtr(DefaultTargetingIncludeBidderKeys), 238 }, 239 expectedModified: true, 240 }, 241 { 242 name: "populated-full", // no defaults set 243 givenTargeting: &openrtb_ext.ExtRequestTargeting{ 244 PriceGranularity: &openrtb_ext.PriceGranularity{ 245 Precision: ptrutil.ToPtr(4), 246 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 247 }, 248 IncludeWinners: ptrutil.ToPtr(false), 249 IncludeBidderKeys: ptrutil.ToPtr(false), 250 }, 251 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 252 PriceGranularity: &openrtb_ext.PriceGranularity{ 253 Precision: ptrutil.ToPtr(4), 254 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 255 }, 256 IncludeWinners: ptrutil.ToPtr(false), 257 IncludeBidderKeys: ptrutil.ToPtr(false), 258 }, 259 expectedModified: false, 260 }, 261 { 262 name: "populated-full-mediatypepricegranularity-video-banner", // no defaults set 263 givenTargeting: &openrtb_ext.ExtRequestTargeting{ 264 PriceGranularity: &openrtb_ext.PriceGranularity{ 265 Precision: ptrutil.ToPtr(4), 266 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 267 }, 268 MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{ 269 Video: &openrtb_ext.PriceGranularity{ 270 Precision: ptrutil.ToPtr(4), 271 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 272 }, 273 Banner: &openrtb_ext.PriceGranularity{ 274 Precision: ptrutil.ToPtr(4), 275 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 276 }, 277 Native: &openrtb_ext.PriceGranularity{ 278 Precision: ptrutil.ToPtr(4), 279 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 280 }, 281 }, 282 IncludeWinners: ptrutil.ToPtr(false), 283 IncludeBidderKeys: ptrutil.ToPtr(false), 284 }, 285 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 286 PriceGranularity: &openrtb_ext.PriceGranularity{ 287 Precision: ptrutil.ToPtr(4), 288 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 289 }, 290 MediaTypePriceGranularity: openrtb_ext.MediaTypePriceGranularity{ 291 Video: &openrtb_ext.PriceGranularity{ 292 Precision: ptrutil.ToPtr(4), 293 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}}, 294 Banner: &openrtb_ext.PriceGranularity{ 295 Precision: ptrutil.ToPtr(4), 296 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}}, 297 Native: &openrtb_ext.PriceGranularity{ 298 Precision: ptrutil.ToPtr(4), 299 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}}, 300 }, 301 IncludeWinners: ptrutil.ToPtr(false), 302 IncludeBidderKeys: ptrutil.ToPtr(false), 303 }, 304 expectedModified: false, 305 }, 306 { 307 name: "setDefaultsPriceGranularity-integration", 308 givenTargeting: &openrtb_ext.ExtRequestTargeting{ 309 PriceGranularity: &openrtb_ext.PriceGranularity{ 310 Precision: ptrutil.ToPtr(4), 311 Ranges: []openrtb_ext.GranularityRange{{Min: 5, Max: 10, Increment: 1}}, 312 }, 313 IncludeWinners: ptrutil.ToPtr(false), 314 IncludeBidderKeys: ptrutil.ToPtr(false), 315 }, 316 expectedTargeting: &openrtb_ext.ExtRequestTargeting{ 317 PriceGranularity: &openrtb_ext.PriceGranularity{ 318 Precision: ptrutil.ToPtr(4), 319 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 320 }, 321 IncludeWinners: ptrutil.ToPtr(false), 322 IncludeBidderKeys: ptrutil.ToPtr(false), 323 }, 324 expectedModified: true, 325 }, 326 } 327 328 for _, test := range testCases { 329 t.Run(test.name, func(t *testing.T) { 330 actualModified := setDefaultsTargeting(test.givenTargeting) 331 assert.Equal(t, test.expectedModified, actualModified) 332 assert.Equal(t, test.expectedTargeting, test.givenTargeting) 333 }) 334 } 335 } 336 337 func TestSetDefaultsPriceGranularity(t *testing.T) { 338 testCases := []struct { 339 name string 340 givenGranularity *openrtb_ext.PriceGranularity 341 expectedGranularity *openrtb_ext.PriceGranularity 342 expectedModified bool 343 }{ 344 { 345 name: "no-precision", 346 givenGranularity: &openrtb_ext.PriceGranularity{ 347 Precision: nil, 348 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 349 }, 350 expectedGranularity: &openrtb_ext.PriceGranularity{ 351 Precision: ptrutil.ToPtr(2), 352 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 353 }, 354 expectedModified: true, 355 }, 356 { 357 name: "incomplete-range", 358 givenGranularity: &openrtb_ext.PriceGranularity{ 359 Precision: ptrutil.ToPtr(2), 360 Ranges: []openrtb_ext.GranularityRange{{Min: 5, Max: 10, Increment: 1}}, 361 }, 362 expectedGranularity: &openrtb_ext.PriceGranularity{ 363 Precision: ptrutil.ToPtr(2), 364 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 365 }, 366 expectedModified: true, 367 }, 368 { 369 name: "no-precision+incomplete-range", 370 givenGranularity: &openrtb_ext.PriceGranularity{ 371 Precision: nil, 372 Ranges: []openrtb_ext.GranularityRange{{Min: 5, Max: 10, Increment: 1}}, 373 }, 374 expectedGranularity: &openrtb_ext.PriceGranularity{ 375 Precision: ptrutil.ToPtr(2), 376 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 377 }, 378 expectedModified: true, 379 }, 380 { 381 name: "all-set", 382 givenGranularity: &openrtb_ext.PriceGranularity{ 383 Precision: ptrutil.ToPtr(2), 384 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 385 }, 386 expectedGranularity: &openrtb_ext.PriceGranularity{ 387 Precision: ptrutil.ToPtr(2), 388 Ranges: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 389 }, 390 expectedModified: false, 391 }, 392 } 393 394 for _, test := range testCases { 395 t.Run(test.name, func(t *testing.T) { 396 pg, actualModified := setDefaultsPriceGranularity(test.givenGranularity) 397 assert.Equal(t, test.expectedModified, actualModified) 398 assert.Equal(t, test.expectedGranularity, pg) 399 }) 400 } 401 } 402 403 func TestSetDefaultsPriceGranularityRange(t *testing.T) { 404 testCases := []struct { 405 name string 406 givenRange []openrtb_ext.GranularityRange 407 expectedRange []openrtb_ext.GranularityRange 408 expectedModified bool 409 }{ 410 { 411 name: "nil", 412 givenRange: nil, 413 expectedRange: nil, 414 expectedModified: false, 415 }, 416 { 417 name: "empty", 418 givenRange: []openrtb_ext.GranularityRange{}, 419 expectedRange: []openrtb_ext.GranularityRange{}, 420 expectedModified: false, 421 }, 422 { 423 name: "one-ok", 424 givenRange: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 425 expectedRange: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 426 expectedModified: false, 427 }, 428 { 429 name: "one-fixed", 430 givenRange: []openrtb_ext.GranularityRange{{Min: 5, Max: 10, Increment: 1}}, 431 expectedRange: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}}, 432 expectedModified: true, 433 }, 434 { 435 name: "many-ok", 436 givenRange: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}, {Min: 10, Max: 20, Increment: 1}}, 437 expectedRange: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}, {Min: 10, Max: 20, Increment: 1}}, 438 expectedModified: false, 439 }, 440 { 441 name: "many-fixed", 442 givenRange: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}, {Min: 15, Max: 20, Increment: 1}}, 443 expectedRange: []openrtb_ext.GranularityRange{{Min: 0, Max: 10, Increment: 1}, {Min: 10, Max: 20, Increment: 1}}, 444 expectedModified: true, 445 }, 446 } 447 448 for _, test := range testCases { 449 t.Run(test.name, func(t *testing.T) { 450 actualModified := setDefaultsPriceGranularityRange(test.givenRange) 451 assert.Equal(t, test.expectedModified, actualModified) 452 assert.Equal(t, test.expectedRange, test.givenRange) 453 }) 454 } 455 } 456 457 func TestSetDefaultsImp(t *testing.T) { 458 secure0 := int8(0) 459 secure1 := int8(1) 460 461 testCases := []struct { 462 name string 463 givenImps []*openrtb_ext.ImpWrapper 464 expectedImps []*openrtb_ext.ImpWrapper 465 expectedModified bool 466 }{ 467 { 468 name: "nil", 469 givenImps: nil, 470 expectedImps: nil, 471 expectedModified: false, 472 }, 473 { 474 name: "empty", 475 givenImps: []*openrtb_ext.ImpWrapper{}, 476 expectedImps: []*openrtb_ext.ImpWrapper{}, 477 expectedModified: false, 478 }, 479 { 480 name: "one-nil", 481 givenImps: []*openrtb_ext.ImpWrapper{nil}, 482 expectedImps: []*openrtb_ext.ImpWrapper{nil}, 483 expectedModified: false, 484 }, 485 { 486 name: "one-imp-nil", 487 givenImps: []*openrtb_ext.ImpWrapper{{Imp: nil}}, 488 expectedImps: []*openrtb_ext.ImpWrapper{{Imp: nil}}, 489 expectedModified: false, 490 }, 491 { 492 name: "one-imp-secure-0", 493 givenImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: &secure0}}}, 494 expectedImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: &secure0}}}, 495 expectedModified: false, 496 }, 497 { 498 name: "one-imp-secure-1", 499 givenImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: &secure1}}}, 500 expectedImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: &secure1}}}, 501 expectedModified: false, 502 }, 503 { 504 name: "one-imp-secure-nil", 505 givenImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: nil}}}, 506 expectedImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: &secure1}}}, 507 expectedModified: true, 508 }, 509 { 510 name: "one-imp-many-notmodified", 511 givenImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: &secure0}}, {Imp: &openrtb2.Imp{Secure: &secure1}}}, 512 expectedImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: &secure0}}, {Imp: &openrtb2.Imp{Secure: &secure1}}}, 513 expectedModified: false, 514 }, 515 { 516 name: "one-imp-many-modified", 517 givenImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: &secure0}}, {Imp: &openrtb2.Imp{Secure: nil}}}, 518 expectedImps: []*openrtb_ext.ImpWrapper{{Imp: &openrtb2.Imp{Secure: &secure0}}, {Imp: &openrtb2.Imp{Secure: &secure1}}}, 519 expectedModified: true, 520 }, 521 } 522 523 for _, test := range testCases { 524 t.Run(test.name, func(t *testing.T) { 525 actualModified := setDefaultsImp(test.givenImps) 526 assert.Equal(t, test.expectedModified, actualModified) 527 assert.ElementsMatch(t, test.expectedImps, test.givenImps) 528 }) 529 } 530 }