github.com/prebid/prebid-server/v2@v2.18.0/bidadjustment/apply_test.go (about) 1 package bidadjustment 2 3 import ( 4 "testing" 5 6 "github.com/prebid/openrtb/v20/openrtb2" 7 "github.com/prebid/prebid-server/v2/adapters" 8 "github.com/prebid/prebid-server/v2/openrtb_ext" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/mock" 11 ) 12 13 func TestGetAndApply(t *testing.T) { 14 var ( 15 adjCur string = "EUR" 16 bidCur string = "USA" 17 ) 18 19 testCases := []struct { 20 name string 21 givenRuleToAdjustments map[string][]openrtb_ext.Adjustment 22 givenBidderName openrtb_ext.BidderName 23 givenBidInfo *adapters.TypedBid 24 givenBidType string 25 setMock func(m *mock.Mock) 26 expectedBidPrice float64 27 expectedCurrency string 28 }{ 29 { 30 name: "CpmAdjustment", 31 givenBidInfo: &adapters.TypedBid{ 32 Bid: &openrtb2.Bid{ 33 Price: 10.0, 34 DealID: "dealId", 35 }, 36 }, 37 givenBidType: string(openrtb_ext.BidTypeBanner), 38 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 39 "banner|bidderA|dealId": { 40 { 41 Type: AdjustmentTypeCPM, 42 Value: 1.0, 43 Currency: adjCur, 44 }, 45 }, 46 "banner|bidderA|*": { 47 { 48 Type: AdjustmentTypeMultiplier, 49 Value: 2.0, 50 }, 51 }, 52 }, 53 givenBidderName: "bidderA", 54 setMock: func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) }, 55 expectedBidPrice: 7.5, 56 expectedCurrency: bidCur, 57 }, 58 { 59 name: "StaticAdjustment", 60 givenBidInfo: &adapters.TypedBid{ 61 Bid: &openrtb2.Bid{ 62 Price: 10.0, 63 DealID: "dealId", 64 }, 65 }, 66 givenBidType: string(openrtb_ext.BidTypeBanner), 67 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 68 "*|bidderA|dealId": { 69 { 70 Type: AdjustmentTypeCPM, 71 Value: 1.0, 72 Currency: adjCur, 73 }, 74 }, 75 "banner|bidderA|*": { 76 { 77 Type: AdjustmentTypeStatic, 78 Value: 2.0, 79 Currency: adjCur, 80 }, 81 }, 82 }, 83 givenBidderName: "bidderA", 84 setMock: nil, 85 expectedBidPrice: 2.0, 86 expectedCurrency: adjCur, 87 }, 88 { 89 name: "MultiplierAdjustment", 90 givenBidInfo: &adapters.TypedBid{ 91 Bid: &openrtb2.Bid{ 92 Price: 10.0, 93 DealID: "dealId", 94 }, 95 }, 96 givenBidType: VideoInstream, 97 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 98 "*|*|dealId": { 99 { 100 Type: AdjustmentTypeCPM, 101 Value: 1.0, 102 Currency: adjCur, 103 }, 104 }, 105 "video-instream|*|*": { 106 { 107 Type: AdjustmentTypeMultiplier, 108 Value: 2.0, 109 }, 110 }, 111 }, 112 givenBidderName: "bidderA", 113 setMock: nil, 114 expectedBidPrice: 20.0, 115 expectedCurrency: bidCur, 116 }, 117 { 118 name: "CpmAndMultiplierAdjustments", 119 givenBidInfo: &adapters.TypedBid{ 120 Bid: &openrtb2.Bid{ 121 Price: 10.0, 122 DealID: "dealId", 123 }, 124 }, 125 givenBidType: VideoInstream, 126 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 127 "video-instream|*|*": { 128 { 129 Type: AdjustmentTypeMultiplier, 130 Value: 2.0, 131 }, 132 { 133 Type: AdjustmentTypeCPM, 134 Value: 1.0, 135 Currency: adjCur, 136 }, 137 }, 138 }, 139 givenBidderName: "bidderA", 140 setMock: func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) }, 141 expectedBidPrice: 17.5, 142 expectedCurrency: bidCur, 143 }, 144 { 145 name: "DealIdPresentAndNegativeAdjustedPrice", 146 givenBidInfo: &adapters.TypedBid{ 147 Bid: &openrtb2.Bid{ 148 Price: 1.0, 149 DealID: "dealId", 150 }, 151 }, 152 givenBidType: VideoInstream, 153 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 154 "*|*|dealId": { 155 { 156 Type: AdjustmentTypeCPM, 157 Value: 1.0, 158 Currency: adjCur, 159 }, 160 }, 161 }, 162 givenBidderName: "bidderA", 163 setMock: func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) }, 164 expectedBidPrice: 0.0, 165 expectedCurrency: bidCur, 166 }, 167 { 168 name: "NoDealIdNegativeAdjustedPrice", 169 givenBidInfo: &adapters.TypedBid{ 170 Bid: &openrtb2.Bid{ 171 Price: 1.0, 172 DealID: "", 173 }, 174 }, 175 givenBidType: string(openrtb_ext.BidTypeAudio), 176 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 177 "*|*|*": { 178 { 179 Type: AdjustmentTypeCPM, 180 Value: 1.0, 181 Currency: adjCur, 182 }, 183 }, 184 }, 185 givenBidderName: "bidderA", 186 setMock: func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) }, 187 expectedBidPrice: 0.1, 188 expectedCurrency: bidCur, 189 }, 190 { 191 name: "NilMap", 192 givenBidInfo: &adapters.TypedBid{ 193 Bid: &openrtb2.Bid{ 194 Price: 10.0, 195 DealID: "dealId", 196 }, 197 }, 198 givenBidType: string(openrtb_ext.BidTypeBanner), 199 givenRuleToAdjustments: nil, 200 givenBidderName: "bidderA", 201 setMock: nil, 202 expectedBidPrice: 10.0, 203 expectedCurrency: bidCur, 204 }, 205 } 206 207 for _, test := range testCases { 208 t.Run(test.name, func(t *testing.T) { 209 reqInfo := adapters.ExtraRequestInfo{} 210 if test.setMock != nil { 211 mockConversions := &mockConversions{} 212 test.setMock(&mockConversions.Mock) 213 reqInfo = adapters.NewExtraRequestInfo(mockConversions) 214 } 215 bidPrice, currencyAfterAdjustment := Apply(test.givenRuleToAdjustments, test.givenBidInfo, test.givenBidderName, bidCur, &reqInfo, test.givenBidType) 216 assert.Equal(t, test.expectedBidPrice, bidPrice) 217 assert.Equal(t, test.expectedCurrency, currencyAfterAdjustment) 218 }) 219 } 220 } 221 222 type mockConversions struct { 223 mock.Mock 224 } 225 226 func (m *mockConversions) GetRate(from string, to string) (float64, error) { 227 args := m.Called(from, to) 228 return args.Get(0).(float64), args.Error(1) 229 } 230 231 func (m *mockConversions) GetRates() *map[string]map[string]float64 { 232 args := m.Called() 233 return args.Get(0).(*map[string]map[string]float64) 234 } 235 236 func TestApply(t *testing.T) { 237 var ( 238 adjCur string = "EUR" 239 bidCur string = "USA" 240 ) 241 242 testCases := []struct { 243 name string 244 givenAdjustments []openrtb_ext.Adjustment 245 setMock func(m *mock.Mock) 246 givenBidPrice float64 247 expectedBidPrice float64 248 expectedCurrency string 249 }{ 250 { 251 name: "CpmAdjustment", 252 givenAdjustments: []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 1.0, Currency: adjCur}}, 253 givenBidPrice: 10.58687, 254 setMock: func(m *mock.Mock) { m.On("GetRate", adjCur, bidCur).Return(2.5, nil) }, 255 expectedBidPrice: 8.0869, 256 expectedCurrency: bidCur, 257 }, 258 { 259 name: "StaticAdjustment", 260 givenAdjustments: []openrtb_ext.Adjustment{{Type: AdjustmentTypeStatic, Value: 4.0, Currency: adjCur}}, 261 givenBidPrice: 10.0, 262 setMock: nil, 263 expectedBidPrice: 4.0, 264 expectedCurrency: adjCur, 265 }, 266 { 267 name: "MultiplierAdjustment", 268 givenAdjustments: []openrtb_ext.Adjustment{{Type: AdjustmentTypeMultiplier, Value: 3.0}}, 269 givenBidPrice: 10.0, 270 setMock: nil, 271 expectedBidPrice: 30.0, 272 expectedCurrency: bidCur, 273 }, 274 { 275 name: "NilAdjustment", 276 givenAdjustments: nil, 277 givenBidPrice: 10.0, 278 setMock: nil, 279 expectedBidPrice: 10.0, 280 expectedCurrency: bidCur, 281 }, 282 } 283 284 for _, test := range testCases { 285 t.Run(test.name, func(t *testing.T) { 286 reqInfo := adapters.ExtraRequestInfo{} 287 if test.setMock != nil { 288 mockConversions := &mockConversions{} 289 test.setMock(&mockConversions.Mock) 290 reqInfo = adapters.NewExtraRequestInfo(mockConversions) 291 } 292 293 bidPrice, currencyAfterAdjustment := apply(test.givenAdjustments, test.givenBidPrice, bidCur, &reqInfo) 294 assert.Equal(t, test.expectedBidPrice, bidPrice) 295 assert.Equal(t, test.expectedCurrency, currencyAfterAdjustment) 296 }) 297 } 298 } 299 300 func TestGet(t *testing.T) { 301 testCases := []struct { 302 name string 303 givenRuleToAdjustments map[string][]openrtb_ext.Adjustment 304 givenBidType openrtb_ext.BidType 305 givenBidderName openrtb_ext.BidderName 306 givenDealId string 307 expected []openrtb_ext.Adjustment 308 }{ 309 { 310 name: "Priority1", 311 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 312 "banner|bidderA|dealId": { 313 { 314 Type: AdjustmentTypeMultiplier, 315 Value: 1.1, 316 }, 317 }, 318 "banner|bidderA|*": { 319 { 320 Type: AdjustmentTypeMultiplier, 321 Value: 2.0, 322 }, 323 }, 324 }, 325 givenBidType: openrtb_ext.BidTypeBanner, 326 givenBidderName: "bidderA", 327 givenDealId: "dealId", 328 expected: []openrtb_ext.Adjustment{{Type: AdjustmentTypeMultiplier, Value: 1.1}}, 329 }, 330 { 331 name: "Priority2", 332 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 333 "banner|bidderA|*": { 334 { 335 Type: AdjustmentTypeStatic, 336 Value: 5.0, 337 }, 338 }, 339 "banner|*|dealId": { 340 { 341 Type: AdjustmentTypeMultiplier, 342 Value: 2.0, 343 }, 344 }, 345 }, 346 givenBidType: openrtb_ext.BidTypeBanner, 347 givenBidderName: "bidderA", 348 givenDealId: "dealId", 349 expected: []openrtb_ext.Adjustment{{Type: AdjustmentTypeStatic, Value: 5.0}}, 350 }, 351 { 352 name: "Priority3", 353 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 354 "banner|*|dealId": { 355 { 356 Type: AdjustmentTypeCPM, 357 Value: 3.0, 358 Currency: "USD", 359 }, 360 }, 361 "*|bidderA|dealId": { 362 { 363 Type: AdjustmentTypeMultiplier, 364 Value: 1.1, 365 }, 366 }, 367 }, 368 givenBidType: openrtb_ext.BidTypeBanner, 369 givenBidderName: "bidderA", 370 givenDealId: "dealId", 371 expected: []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}}, 372 }, 373 { 374 name: "Priority4", 375 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 376 "*|bidderA|dealId": { 377 { 378 Type: AdjustmentTypeCPM, 379 Value: 3.0, 380 Currency: "USD", 381 }, 382 }, 383 "banner|*|*": { 384 { 385 Type: AdjustmentTypeMultiplier, 386 Value: 1.1, 387 }, 388 }, 389 }, 390 givenBidType: openrtb_ext.BidTypeBanner, 391 givenBidderName: "bidderA", 392 givenDealId: "dealId", 393 expected: []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}}, 394 }, 395 { 396 name: "Priority5", 397 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 398 "banner|*|*": { 399 { 400 Type: AdjustmentTypeCPM, 401 Value: 3.0, 402 Currency: "USD", 403 }, 404 }, 405 "*|bidderA|*": { 406 { 407 Type: AdjustmentTypeMultiplier, 408 Value: 1.1, 409 }, 410 }, 411 }, 412 givenBidType: openrtb_ext.BidTypeBanner, 413 givenBidderName: "bidderA", 414 givenDealId: "dealId", 415 expected: []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}}, 416 }, 417 { 418 name: "Priority6", 419 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 420 "*|bidderA|*": { 421 { 422 Type: AdjustmentTypeCPM, 423 Value: 3.0, 424 Currency: "USD", 425 }, 426 }, 427 "*|*|dealId": { 428 { 429 Type: AdjustmentTypeMultiplier, 430 Value: 1.1, 431 }, 432 }, 433 }, 434 givenBidType: openrtb_ext.BidTypeBanner, 435 givenBidderName: "bidderA", 436 givenDealId: "dealId", 437 expected: []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}}, 438 }, 439 { 440 name: "Priority7", 441 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 442 "*|*|dealId": { 443 { 444 Type: AdjustmentTypeCPM, 445 Value: 3.0, 446 Currency: "USD", 447 }, 448 }, 449 "*|*|*": { 450 { 451 Type: AdjustmentTypeMultiplier, 452 Value: 1.1, 453 }, 454 }, 455 }, 456 givenBidType: openrtb_ext.BidTypeBanner, 457 givenBidderName: "bidderA", 458 givenDealId: "dealId", 459 expected: []openrtb_ext.Adjustment{{Type: AdjustmentTypeCPM, Value: 3.0, Currency: "USD"}}, 460 }, 461 { 462 name: "Priority8", 463 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 464 "*|*|*": { 465 { 466 Type: AdjustmentTypeMultiplier, 467 Value: 1.1, 468 }, 469 }, 470 "banner|bidderA|dealId": { 471 { 472 Type: AdjustmentTypeMultiplier, 473 Value: 1.1, 474 }, 475 }, 476 }, 477 givenBidType: openrtb_ext.BidTypeBanner, 478 givenBidderName: "bidderB", 479 givenDealId: "dealId", 480 expected: []openrtb_ext.Adjustment{{Type: AdjustmentTypeMultiplier, Value: 1.1}}, 481 }, 482 { 483 name: "NoDealID", 484 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 485 "banner|bidderA|*": { 486 { 487 Type: AdjustmentTypeMultiplier, 488 Value: 1.1, 489 }, 490 }, 491 "banner|*|*": { 492 { 493 Type: AdjustmentTypeMultiplier, 494 Value: 1.1, 495 }, 496 }, 497 }, 498 givenBidType: openrtb_ext.BidTypeBanner, 499 givenBidderName: "bidderA", 500 givenDealId: "", 501 expected: []openrtb_ext.Adjustment{{Type: AdjustmentTypeMultiplier, Value: 1.1}}, 502 }, 503 { 504 name: "NoPriorityRulesMatch", 505 givenRuleToAdjustments: map[string][]openrtb_ext.Adjustment{ 506 "banner|bidderA|dealId": { 507 { 508 Type: AdjustmentTypeMultiplier, 509 Value: 1.1, 510 }, 511 }, 512 "banner|bidderA|*": { 513 { 514 Type: AdjustmentTypeMultiplier, 515 Value: 2.0, 516 }, 517 }, 518 }, 519 givenBidType: openrtb_ext.BidTypeVideo, 520 givenBidderName: "bidderB", 521 givenDealId: "diffDealId", 522 expected: nil, 523 }, 524 } 525 526 for _, test := range testCases { 527 t.Run(test.name, func(t *testing.T) { 528 adjArray := get(test.givenRuleToAdjustments, string(test.givenBidType), string(test.givenBidderName), test.givenDealId) 529 assert.Equal(t, test.expected, adjArray) 530 }) 531 } 532 }