github.com/prebid/prebid-server/v2@v2.18.0/floors/floors_test.go (about) 1 package floors 2 3 import ( 4 "encoding/json" 5 "errors" 6 "reflect" 7 "testing" 8 9 "github.com/prebid/openrtb/v20/openrtb2" 10 "github.com/prebid/prebid-server/v2/config" 11 "github.com/prebid/prebid-server/v2/currency" 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 "github.com/stretchr/testify/assert" 16 ) 17 18 func TestIsRequestEnabledWithFloor(t *testing.T) { 19 FalseFlag := false 20 TrueFlag := true 21 22 testCases := []struct { 23 name string 24 in *openrtb_ext.ExtRequest 25 out bool 26 }{ 27 { 28 name: "Request With Nil Floors", 29 in: &openrtb_ext.ExtRequest{}, 30 out: true, 31 }, 32 { 33 name: "Request With Floors Disabled", 34 in: &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Floors: &openrtb_ext.PriceFloorRules{Enabled: &FalseFlag}}}, 35 out: false, 36 }, 37 { 38 name: "Request With Floors Enabled", 39 in: &openrtb_ext.ExtRequest{Prebid: openrtb_ext.ExtRequestPrebid{Floors: &openrtb_ext.PriceFloorRules{Enabled: &TrueFlag}}}, 40 out: true, 41 }, 42 } 43 for _, tc := range testCases { 44 t.Run(tc.name, func(t *testing.T) { 45 out := tc.in.Prebid.Floors.GetEnabled() 46 assert.Equal(t, out, tc.out, tc.name) 47 }) 48 } 49 } 50 51 func getCurrencyRates(rates map[string]map[string]float64) currency.Conversions { 52 return currency.NewRates(rates) 53 } 54 55 type mockPriceFloorFetcher struct{} 56 57 func (mpf *mockPriceFloorFetcher) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) { 58 return nil, openrtb_ext.FetchNone 59 } 60 61 func (mpf *mockPriceFloorFetcher) Stop() {} 62 63 func TestEnrichWithPriceFloors(t *testing.T) { 64 rates := map[string]map[string]float64{ 65 "USD": { 66 "INR": 70, 67 "EUR": 0.9, 68 "JPY": 5.09, 69 }, 70 } 71 72 testAccountConfig := config.Account{ 73 PriceFloors: config.AccountPriceFloors{ 74 Enabled: true, 75 UseDynamicData: false, 76 MaxRule: 100, 77 MaxSchemaDims: 5, 78 }, 79 } 80 81 width := int64(300) 82 height := int64(600) 83 84 testCases := []struct { 85 name string 86 bidRequestWrapper *openrtb_ext.RequestWrapper 87 account config.Account 88 conversions currency.Conversions 89 Skipped bool 90 err string 91 expFloorVal float64 92 expFloorCur string 93 expPriceFlrLoc string 94 expSchemaVersion int 95 }{ 96 { 97 name: "Floors disabled in account config", 98 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 99 BidRequest: &openrtb2.BidRequest{ 100 Site: &openrtb2.Site{ 101 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 102 }, 103 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 104 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 105 }, 106 }, 107 account: config.Account{ 108 PriceFloors: config.AccountPriceFloors{ 109 Enabled: false, 110 }, 111 }, 112 err: "Floors feature is disabled at account or in the request", 113 }, 114 { 115 name: "Floors disabled in req.ext.prebid.floors.Enabled=false config", 116 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 117 BidRequest: &openrtb2.BidRequest{ 118 Site: &openrtb2.Site{ 119 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 120 }, 121 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 122 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":false,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 123 }, 124 }, 125 account: testAccountConfig, 126 err: "Floors feature is disabled at account or in the request", 127 }, 128 { 129 name: "Floors enabled in req.ext.prebid.floors.Enabled and enabled account config", 130 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 131 BidRequest: &openrtb2.BidRequest{ 132 Site: &openrtb2.Site{ 133 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 134 }, 135 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 136 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 2 from req","currency":"USD","values":{"banner|300x250|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}},{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 137 }, 138 }, 139 account: testAccountConfig, 140 expFloorVal: 5, 141 expFloorCur: "USD", 142 expPriceFlrLoc: openrtb_ext.RequestLocation, 143 }, 144 { 145 name: "Skiprate = 100, Floors enabled in req.ext.prebid.floors.Enabled and account config: Floors singalling skipped ", 146 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 147 BidRequest: &openrtb2.BidRequest{ 148 Site: &openrtb2.Site{ 149 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 150 }, 151 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 152 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"skiprate": 100,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 153 }, 154 }, 155 account: testAccountConfig, 156 Skipped: true, 157 }, 158 { 159 name: "Single ModelGroup, Invalid Skiprate = 110: Floors singalling skipped", 160 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 161 BidRequest: &openrtb2.BidRequest{ 162 Site: &openrtb2.Site{ 163 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 164 }, 165 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 166 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"skiprate": 110,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 167 }, 168 }, 169 account: testAccountConfig, 170 err: "Invalid SkipRate = '110' at ext.prebid.floors.skiprate", 171 expPriceFlrLoc: openrtb_ext.RequestLocation, 172 }, 173 { 174 name: "Multiple ModelGroups, Invalid Skiprate = 110: in one group, Floors singalling done using second ModelGroup", 175 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 176 BidRequest: &openrtb2.BidRequest{ 177 Site: &openrtb2.Site{ 178 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 179 }, 180 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 181 Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":11,"floormincur":"USD","data":{"currency":"USD","floorsschemaversion":2,"modelgroups":[{"modelweight":50,"modelversion":"version2","schema":{"fields":["mediaType","size","domain"],"delimiter":"|"},"values":{"*|*|*":11.01,"*|*|www.website1.com":17.01},"default":21},{"modelweight":50,"modelversion":"version11","skiprate":110,"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"},"values":{"*|300x250|*":11.01,"*|300x250|www.website1.com":100.01},"default":21}]},"enforcement":{"enforcepbs":true,"floordeals":true},"enabled":true}}}`), 182 }, 183 }, 184 account: testAccountConfig, 185 err: "Invalid Floor Model = 'version11' due to SkipRate = '110' is out of range (1-100)", 186 expFloorVal: 11.01, 187 expFloorCur: "USD", 188 expPriceFlrLoc: openrtb_ext.RequestLocation, 189 expSchemaVersion: 2, 190 }, 191 { 192 name: "Rule selection with Site object, banner|300x600|www.website.com", 193 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 194 BidRequest: &openrtb2.BidRequest{ 195 Site: &openrtb2.Site{ 196 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 197 }, 198 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{W: &width, H: &height}}}, 199 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"BANNER|300x600|WWW.WEBSITE.COM":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 200 }, 201 }, 202 account: testAccountConfig, 203 expFloorVal: 5, 204 expFloorCur: "USD", 205 expPriceFlrLoc: openrtb_ext.RequestLocation, 206 }, 207 { 208 name: "Rule selection with App object, *|*|www.test.com", 209 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 210 BidRequest: &openrtb2.BidRequest{ 211 App: &openrtb2.App{ 212 Domain: "www.test.com", 213 }, 214 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{W: &width, H: &height}}}, 215 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website.com":5,"*|*|www.test.com":15,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 216 }, 217 }, 218 account: testAccountConfig, 219 expFloorVal: 15, 220 expFloorCur: "USD", 221 expPriceFlrLoc: openrtb_ext.RequestLocation, 222 }, 223 { 224 name: "Floors Signalling not done as req.ext.prebid.floors not provided", 225 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 226 BidRequest: &openrtb2.BidRequest{ 227 App: &openrtb2.App{ 228 Domain: "www.test.com", 229 }, 230 Imp: []openrtb2.Imp{{ID: "1234", BidFloor: 10, BidFloorCur: "EUR", Banner: &openrtb2.Banner{W: &width, H: &height}}}, 231 Ext: json.RawMessage(`{"prebid":{}}`), 232 }, 233 }, 234 account: testAccountConfig, 235 expFloorVal: 10, 236 expFloorCur: "EUR", 237 expPriceFlrLoc: openrtb_ext.NoDataLocation, 238 err: "Empty Floors data", 239 }, 240 { 241 name: "BidFloor(USD) Less than MinBidFloor(INR) with different currency", 242 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 243 BidRequest: &openrtb2.BidRequest{ 244 Site: &openrtb2.Site{ 245 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 246 }, 247 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 248 Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":80,"floormincur":"INR","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":1,"*|*|www.test.com":15,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 249 }, 250 }, 251 account: testAccountConfig, 252 expFloorVal: 1.1429, 253 expFloorCur: "USD", 254 expPriceFlrLoc: openrtb_ext.RequestLocation, 255 }, 256 { 257 name: "BidFloor(INR) Less than MinBidFloor(USD) with different currency", 258 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 259 BidRequest: &openrtb2.BidRequest{ 260 Site: &openrtb2.Site{ 261 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 262 }, 263 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 264 Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":1,"floormincur":"USD","data":{"currency":"INR","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com":60,"*|*|www.test.com":65,"*|*|*":67},"Default":50,"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 265 }, 266 }, 267 account: testAccountConfig, 268 expFloorVal: 70, 269 expFloorCur: "INR", 270 expPriceFlrLoc: openrtb_ext.RequestLocation, 271 }, 272 { 273 name: "BidFloor is greater than MinBidFloor with same currency", 274 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 275 BidRequest: &openrtb2.BidRequest{ 276 Site: &openrtb2.Site{ 277 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 278 }, 279 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 280 Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":1,"floormincur":"USD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com":2,"*|*|www.test.com":1.5,"*|*|*":1.7},"Default":5,"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 281 }, 282 }, 283 account: testAccountConfig, 284 expFloorVal: 2, 285 expFloorCur: "USD", 286 expPriceFlrLoc: openrtb_ext.RequestLocation, 287 }, 288 { 289 name: "BidFloor Less than MinBidFloor with same currency", 290 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 291 BidRequest: &openrtb2.BidRequest{ 292 Site: &openrtb2.Site{ 293 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 294 }, 295 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 296 Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":3,"floormincur":"USD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com":2,"*|*|www.test.com":1.5,"*|*|*":1.7},"Default":5,"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 297 }, 298 }, 299 account: testAccountConfig, 300 expFloorVal: 3, 301 expFloorCur: "USD", 302 expPriceFlrLoc: openrtb_ext.RequestLocation, 303 }, 304 { 305 name: "No Rule matching, default value provided", 306 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 307 BidRequest: &openrtb2.BidRequest{ 308 Site: &openrtb2.Site{ 309 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 310 }, 311 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 312 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com1":2,"*|*|www.test2.com":1.5},"schema":{"fields":["mediaType","size","domain"]}, "default": 20}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 313 }, 314 }, 315 account: testAccountConfig, 316 expFloorVal: 20, 317 expFloorCur: "USD", 318 expPriceFlrLoc: openrtb_ext.RequestLocation, 319 }, 320 { 321 name: "No Rule matching, default value less than floorMin", 322 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 323 BidRequest: &openrtb2.BidRequest{ 324 Site: &openrtb2.Site{ 325 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 326 }, 327 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 328 Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":15,"floormincur":"USD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com1":2,"*|*|www.test2.com":1.5},"schema":{"fields":["mediaType","size","domain"]}, "default": 5}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 329 }, 330 }, 331 account: testAccountConfig, 332 expFloorVal: 15, 333 expFloorCur: "USD", 334 expPriceFlrLoc: openrtb_ext.RequestLocation, 335 }, 336 { 337 name: "imp.bidfloor provided, No Rule matching, MinBidFloor provided", 338 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 339 BidRequest: &openrtb2.BidRequest{ 340 Site: &openrtb2.Site{ 341 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 342 }, 343 Imp: []openrtb2.Imp{{ID: "1234", BidFloor: 100, BidFloorCur: "INR", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 344 Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":2,"floormincur":"USD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","values":{"banner|300x250|www.website.com1":2,"*|*|www.test2.com":1.5},"schema":{"fields":["mediaType","size","domain"]}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 345 }, 346 }, 347 account: testAccountConfig, 348 expFloorVal: 100, 349 expFloorCur: "INR", 350 expPriceFlrLoc: openrtb_ext.RequestLocation, 351 }, 352 { 353 name: "Empty RequestWrapper ", 354 bidRequestWrapper: nil, 355 account: testAccountConfig, 356 err: "Empty bidrequest", 357 }, 358 { 359 name: "Invalid Floor Min Currency", 360 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 361 BidRequest: &openrtb2.BidRequest{ 362 Site: &openrtb2.Site{ 363 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 364 }, 365 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 366 Ext: json.RawMessage(`{"prebid":{"floors":{"floormin":80,"floormincur":"ABCD","data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x250|www.website.com":1,"*|*|www.test.com":15,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 367 }, 368 }, 369 account: testAccountConfig, 370 err: "Error in getting FloorMin value : 'currency: tag is not well-formed'", 371 expPriceFlrLoc: openrtb_ext.RequestLocation, 372 }, 373 } 374 375 for _, tc := range testCases { 376 t.Run(tc.name, func(t *testing.T) { 377 378 ErrList := EnrichWithPriceFloors(tc.bidRequestWrapper, tc.account, getCurrencyRates(rates), &mockPriceFloorFetcher{}) 379 if tc.bidRequestWrapper != nil { 380 assert.Equal(t, tc.bidRequestWrapper.Imp[0].BidFloor, tc.expFloorVal, tc.name) 381 assert.Equal(t, tc.bidRequestWrapper.Imp[0].BidFloorCur, tc.expFloorCur, tc.name) 382 requestExt, err := tc.bidRequestWrapper.GetRequestExt() 383 if err == nil { 384 if tc.Skipped { 385 assert.Equal(t, *requestExt.GetPrebid().Floors.Skipped, tc.Skipped, tc.name) 386 } else { 387 assert.Equal(t, requestExt.GetPrebid().Floors.PriceFloorLocation, tc.expPriceFlrLoc, tc.name) 388 if tc.expSchemaVersion != 0 { 389 assert.Equal(t, requestExt.GetPrebid().Floors.Data.FloorsSchemaVersion, tc.expSchemaVersion, tc.name) 390 } 391 } 392 } 393 } 394 if len(ErrList) > 0 { 395 assert.Equal(t, ErrList[0].Error(), tc.err, tc.name) 396 } 397 }) 398 } 399 } 400 401 func getTrue() *bool { 402 trueFlag := true 403 return &trueFlag 404 } 405 406 func getFalse() *bool { 407 falseFlag := false 408 return &falseFlag 409 } 410 411 type MockFetch struct { 412 FakeFetch func(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) 413 } 414 415 func (m *MockFetch) Stop() {} 416 417 func (m *MockFetch) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) { 418 419 if !configs.UseDynamicData { 420 return nil, openrtb_ext.FetchNone 421 } 422 priceFloors := openrtb_ext.PriceFloorRules{ 423 Enabled: getTrue(), 424 PriceFloorLocation: openrtb_ext.RequestLocation, 425 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 426 EnforcePBS: getTrue(), 427 EnforceRate: 100, 428 FloorDeals: getTrue(), 429 }, 430 Data: &openrtb_ext.PriceFloorData{ 431 Currency: "USD", 432 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 433 { 434 ModelVersion: "Version 101", 435 Currency: "USD", 436 Values: map[string]float64{ 437 "banner|300x600|www.website5.com": 15, 438 "*|*|*": 25, 439 }, 440 Schema: openrtb_ext.PriceFloorSchema{ 441 Fields: []string{"mediaType", "size", "domain"}, 442 Delimiter: "|", 443 }, 444 }, 445 }, 446 }, 447 } 448 return &priceFloors, openrtb_ext.FetchSuccess 449 } 450 451 func TestResolveFloors(t *testing.T) { 452 rates := map[string]map[string]float64{ 453 "USD": { 454 "INR": 70, 455 "EUR": 0.9, 456 "JPY": 5.09, 457 }, 458 } 459 460 testCases := []struct { 461 name string 462 bidRequestWrapper *openrtb_ext.RequestWrapper 463 account config.Account 464 conversions currency.Conversions 465 fetcher FloorFetcher 466 expErr []error 467 expFloors *openrtb_ext.PriceFloorRules 468 }{ 469 { 470 name: "Dynamic fetch disabled, floors from request selected", 471 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 472 BidRequest: &openrtb2.BidRequest{ 473 Site: &openrtb2.Site{ 474 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 475 }, 476 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 477 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 478 }, 479 }, 480 account: config.Account{ 481 PriceFloors: config.AccountPriceFloors{ 482 Enabled: true, 483 UseDynamicData: false, 484 }, 485 }, 486 fetcher: &MockFetch{}, 487 expFloors: &openrtb_ext.PriceFloorRules{ 488 Enabled: getTrue(), 489 FetchStatus: openrtb_ext.FetchNone, 490 PriceFloorLocation: openrtb_ext.RequestLocation, 491 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 492 EnforcePBS: getTrue(), 493 EnforceRate: 100, 494 FloorDeals: getTrue(), 495 }, 496 Data: &openrtb_ext.PriceFloorData{ 497 Currency: "USD", 498 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 499 { 500 ModelVersion: "model 1 from req", 501 Currency: "USD", 502 Values: map[string]float64{ 503 "banner|300x600|www.website5.com": 5, 504 "*|*|*": 7, 505 }, 506 Schema: openrtb_ext.PriceFloorSchema{ 507 Fields: []string{"mediaType", "size", "domain"}, 508 Delimiter: "|", 509 }, 510 }, 511 }, 512 }, 513 }, 514 }, 515 { 516 name: "Dynamic fetch enabled, floors from fetched selected", 517 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 518 BidRequest: &openrtb2.BidRequest{ 519 Site: &openrtb2.Site{ 520 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 521 }, 522 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 523 }, 524 }, 525 account: config.Account{ 526 PriceFloors: config.AccountPriceFloors{ 527 Enabled: true, 528 UseDynamicData: true, 529 }, 530 }, 531 fetcher: &MockFetch{}, 532 expFloors: &openrtb_ext.PriceFloorRules{ 533 Enabled: getTrue(), 534 FetchStatus: openrtb_ext.FetchSuccess, 535 PriceFloorLocation: openrtb_ext.FetchLocation, 536 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 537 EnforcePBS: getTrue(), 538 FloorDeals: getTrue(), 539 EnforceRate: 100, 540 }, 541 Data: &openrtb_ext.PriceFloorData{ 542 Currency: "USD", 543 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 544 { 545 ModelVersion: "Version 101", 546 Currency: "USD", 547 Values: map[string]float64{ 548 "banner|300x600|www.website5.com": 15, 549 "*|*|*": 25, 550 }, 551 Schema: openrtb_ext.PriceFloorSchema{ 552 Fields: []string{"mediaType", "size", "domain"}, 553 Delimiter: "|", 554 }, 555 }, 556 }, 557 }, 558 }, 559 }, 560 { 561 name: "Dynamic fetch enabled, floors formed after merging", 562 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 563 BidRequest: &openrtb2.BidRequest{ 564 Site: &openrtb2.Site{ 565 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 566 }, 567 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 568 Ext: json.RawMessage(`{"prebid":{"floors":{"floormincur":"EUR","enabled":true,"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"floormin":10.11,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 569 }, 570 }, 571 account: config.Account{ 572 PriceFloors: config.AccountPriceFloors{ 573 Enabled: true, 574 UseDynamicData: true, 575 }, 576 }, 577 fetcher: &MockFetch{}, 578 expFloors: &openrtb_ext.PriceFloorRules{ 579 Enabled: getTrue(), 580 FloorMin: 10.11, 581 FloorMinCur: "EUR", 582 FetchStatus: openrtb_ext.FetchSuccess, 583 PriceFloorLocation: openrtb_ext.FetchLocation, 584 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 585 EnforcePBS: getTrue(), 586 EnforceRate: 100, 587 FloorDeals: getTrue(), 588 }, 589 Data: &openrtb_ext.PriceFloorData{ 590 Currency: "USD", 591 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 592 { 593 ModelVersion: "Version 101", 594 Currency: "USD", 595 Values: map[string]float64{ 596 "banner|300x600|www.website5.com": 15, 597 "*|*|*": 25, 598 }, 599 Schema: openrtb_ext.PriceFloorSchema{ 600 Fields: []string{"mediaType", "size", "domain"}, 601 Delimiter: "|", 602 }, 603 }, 604 }, 605 }, 606 }, 607 }, 608 { 609 name: "Dynamic fetch disabled, only enforcement object present in req.ext", 610 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 611 BidRequest: &openrtb2.BidRequest{ 612 Site: &openrtb2.Site{ 613 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 614 }, 615 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 616 Ext: json.RawMessage(`{"prebid":{"floors":{"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 617 }, 618 }, 619 account: config.Account{ 620 PriceFloors: config.AccountPriceFloors{ 621 Enabled: true, 622 UseDynamicData: false, 623 }, 624 }, 625 fetcher: &MockFetch{}, 626 expFloors: &openrtb_ext.PriceFloorRules{ 627 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 628 EnforcePBS: getTrue(), 629 EnforceRate: 100, 630 FloorDeals: getTrue(), 631 }, 632 FetchStatus: openrtb_ext.FetchNone, 633 PriceFloorLocation: openrtb_ext.RequestLocation, 634 }, 635 }, 636 { 637 name: "Dynamic fetch enabled, floors from fetched selected and new URL is updated", 638 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 639 BidRequest: &openrtb2.BidRequest{ 640 Site: &openrtb2.Site{ 641 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 642 }, 643 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 644 Ext: json.RawMessage(`{"prebid":{"floors":{"floorendpoint":{"url":"http://test.com/floor"},"enabled":true}}}`), 645 }, 646 }, 647 account: config.Account{ 648 PriceFloors: config.AccountPriceFloors{ 649 Enabled: true, 650 UseDynamicData: true, 651 }, 652 }, 653 fetcher: &MockFetch{}, 654 expFloors: &openrtb_ext.PriceFloorRules{ 655 Enabled: getTrue(), 656 FetchStatus: openrtb_ext.FetchSuccess, 657 PriceFloorLocation: openrtb_ext.FetchLocation, 658 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 659 EnforcePBS: getTrue(), 660 FloorDeals: getTrue(), 661 EnforceRate: 100, 662 }, 663 Location: &openrtb_ext.PriceFloorEndpoint{ 664 URL: "http://test.com/floor", 665 }, 666 Data: &openrtb_ext.PriceFloorData{ 667 Currency: "USD", 668 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 669 { 670 ModelVersion: "Version 101", 671 Currency: "USD", 672 Values: map[string]float64{ 673 "banner|300x600|www.website5.com": 15, 674 "*|*|*": 25, 675 }, 676 Schema: openrtb_ext.PriceFloorSchema{ 677 Fields: []string{"mediaType", "size", "domain"}, 678 Delimiter: "|", 679 }, 680 }, 681 }, 682 }, 683 }, 684 }, 685 { 686 name: "Dynamic Fetch Enabled but price floor fetcher is nil, floors from request is selected", 687 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 688 BidRequest: &openrtb2.BidRequest{ 689 Site: &openrtb2.Site{ 690 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 691 }, 692 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 693 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 694 }, 695 }, 696 account: config.Account{ 697 PriceFloors: config.AccountPriceFloors{ 698 Enabled: true, 699 UseDynamicData: true, 700 }, 701 }, 702 fetcher: nil, 703 expFloors: &openrtb_ext.PriceFloorRules{ 704 Enabled: getTrue(), 705 FetchStatus: openrtb_ext.FetchNone, 706 PriceFloorLocation: openrtb_ext.RequestLocation, 707 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 708 EnforcePBS: getTrue(), 709 EnforceRate: 100, 710 FloorDeals: getTrue(), 711 }, 712 Data: &openrtb_ext.PriceFloorData{ 713 Currency: "USD", 714 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 715 { 716 ModelVersion: "model 1 from req", 717 Currency: "USD", 718 Values: map[string]float64{ 719 "banner|300x600|www.website5.com": 5, 720 "*|*|*": 7, 721 }, 722 Schema: openrtb_ext.PriceFloorSchema{ 723 Fields: []string{"mediaType", "size", "domain"}, 724 Delimiter: "|", 725 }, 726 }, 727 }, 728 }, 729 }, 730 }, 731 { 732 name: "Dynamic Fetch Enabled but price floor fetcher is nil and request has no floors", 733 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 734 BidRequest: &openrtb2.BidRequest{ 735 Site: &openrtb2.Site{ 736 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 737 }, 738 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 739 Ext: json.RawMessage(`{"prebid":{}}`), 740 }, 741 }, 742 account: config.Account{ 743 PriceFloors: config.AccountPriceFloors{ 744 Enabled: true, 745 UseDynamicData: true, 746 }, 747 }, 748 fetcher: nil, 749 expFloors: &openrtb_ext.PriceFloorRules{ 750 FetchStatus: openrtb_ext.FetchNone, 751 PriceFloorLocation: openrtb_ext.NoDataLocation, 752 }, 753 }, 754 } 755 756 for _, tc := range testCases { 757 t.Run(tc.name, func(t *testing.T) { 758 resolvedFloors, _ := resolveFloors(tc.account, tc.bidRequestWrapper, getCurrencyRates(rates), tc.fetcher) 759 assert.Equal(t, resolvedFloors, tc.expFloors, tc.name) 760 }) 761 } 762 } 763 764 type MockFetchDataRate0 struct{} 765 766 func (m *MockFetchDataRate0) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) { 767 768 if !configs.UseDynamicData { 769 return nil, openrtb_ext.FetchNone 770 } 771 priceFloors := openrtb_ext.PriceFloorRules{ 772 Enabled: getTrue(), 773 PriceFloorLocation: openrtb_ext.RequestLocation, 774 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 775 EnforcePBS: getTrue(), 776 EnforceRate: 100, 777 FloorDeals: getTrue(), 778 }, 779 Data: &openrtb_ext.PriceFloorData{ 780 Currency: "USD", 781 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 782 { 783 ModelVersion: "model from fetched", 784 Currency: "USD", 785 Values: map[string]float64{ 786 "banner|300x600|www.website5.com": 15, 787 "*|*|*": 25, 788 }, 789 Schema: openrtb_ext.PriceFloorSchema{ 790 Fields: []string{"mediaType", "size", "domain"}, 791 }, 792 }, 793 }, 794 FetchRate: ptrutil.ToPtr(0), 795 }, 796 } 797 return &priceFloors, openrtb_ext.FetchSuccess 798 } 799 800 func (m *MockFetchDataRate0) Stop() { 801 802 } 803 804 type MockFetchDataRate100 struct{} 805 806 func (m *MockFetchDataRate100) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) { 807 808 if !configs.UseDynamicData { 809 return nil, openrtb_ext.FetchNone 810 } 811 priceFloors := openrtb_ext.PriceFloorRules{ 812 Enabled: getTrue(), 813 PriceFloorLocation: openrtb_ext.RequestLocation, 814 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 815 EnforcePBS: getTrue(), 816 EnforceRate: 100, 817 FloorDeals: getTrue(), 818 }, 819 Data: &openrtb_ext.PriceFloorData{ 820 Currency: "USD", 821 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 822 { 823 ModelVersion: "model from fetched", 824 Currency: "USD", 825 Values: map[string]float64{ 826 "banner|300x600|www.website5.com": 15, 827 "*|*|*": 25, 828 }, 829 Schema: openrtb_ext.PriceFloorSchema{ 830 Fields: []string{"mediaType", "size", "domain"}, 831 }, 832 }, 833 }, 834 FetchRate: ptrutil.ToPtr(100), 835 }, 836 } 837 return &priceFloors, openrtb_ext.FetchSuccess 838 } 839 840 func (m *MockFetchDataRate100) Stop() { 841 842 } 843 844 type MockFetchDataRateNotProvided struct{} 845 846 func (m *MockFetchDataRateNotProvided) Fetch(configs config.AccountPriceFloors) (*openrtb_ext.PriceFloorRules, string) { 847 848 if !configs.UseDynamicData { 849 return nil, openrtb_ext.FetchNone 850 } 851 priceFloors := openrtb_ext.PriceFloorRules{ 852 Enabled: getTrue(), 853 PriceFloorLocation: openrtb_ext.RequestLocation, 854 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 855 EnforcePBS: getTrue(), 856 EnforceRate: 100, 857 FloorDeals: getTrue(), 858 }, 859 Data: &openrtb_ext.PriceFloorData{ 860 Currency: "USD", 861 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 862 { 863 ModelVersion: "model from fetched", 864 Currency: "USD", 865 Values: map[string]float64{ 866 "banner|300x600|www.website5.com": 5, 867 "*|*|*": 15, 868 }, 869 Schema: openrtb_ext.PriceFloorSchema{ 870 Fields: []string{"mediaType", "size", "domain"}, 871 }, 872 }, 873 }, 874 }, 875 } 876 return &priceFloors, openrtb_ext.FetchSuccess 877 } 878 879 func (m *MockFetchDataRateNotProvided) Stop() { 880 881 } 882 883 func TestResolveFloorsWithUseDataRate(t *testing.T) { 884 rates := map[string]map[string]float64{} 885 886 testCases := []struct { 887 name string 888 bidRequestWrapper *openrtb_ext.RequestWrapper 889 account config.Account 890 conversions currency.Conversions 891 expErr []error 892 expFloors *openrtb_ext.PriceFloorRules 893 fetcher FloorFetcher 894 }{ 895 { 896 name: "Dynamic fetch enabled, floors from request selected as data rate 0", 897 fetcher: &MockFetchDataRate0{}, 898 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 899 BidRequest: &openrtb2.BidRequest{ 900 Site: &openrtb2.Site{ 901 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 902 }, 903 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 904 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 905 }, 906 }, 907 account: config.Account{ 908 PriceFloors: config.AccountPriceFloors{ 909 Enabled: true, 910 UseDynamicData: true, 911 }, 912 }, 913 expFloors: &openrtb_ext.PriceFloorRules{ 914 Enabled: getTrue(), 915 FetchStatus: openrtb_ext.FetchNone, 916 PriceFloorLocation: openrtb_ext.RequestLocation, 917 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 918 EnforcePBS: getTrue(), 919 FloorDeals: getTrue(), 920 EnforceRate: 100, 921 }, 922 Data: &openrtb_ext.PriceFloorData{ 923 Currency: "USD", 924 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 925 { 926 ModelVersion: "model 1 from req", 927 Currency: "USD", 928 Values: map[string]float64{ 929 "banner|300x600|www.website5.com": 5, 930 "*|*|*": 7, 931 }, 932 Schema: openrtb_ext.PriceFloorSchema{ 933 Fields: []string{"mediaType", "size", "domain"}, 934 Delimiter: "|", 935 }, 936 }, 937 }, 938 }, 939 }, 940 }, 941 { 942 name: "Dynamic fetch enabled, floors from fetched selected as data rate is 100", 943 fetcher: &MockFetchDataRate100{}, 944 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 945 BidRequest: &openrtb2.BidRequest{ 946 Site: &openrtb2.Site{ 947 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 948 }, 949 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 950 }, 951 }, 952 account: config.Account{ 953 PriceFloors: config.AccountPriceFloors{ 954 Enabled: true, 955 UseDynamicData: true, 956 }, 957 }, 958 expFloors: &openrtb_ext.PriceFloorRules{ 959 Enabled: getTrue(), 960 FetchStatus: openrtb_ext.FetchSuccess, 961 PriceFloorLocation: openrtb_ext.FetchLocation, 962 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 963 EnforcePBS: getTrue(), 964 FloorDeals: getTrue(), 965 EnforceRate: 100, 966 }, 967 Data: &openrtb_ext.PriceFloorData{ 968 Currency: "USD", 969 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 970 { 971 ModelVersion: "model from fetched", 972 Currency: "USD", 973 Values: map[string]float64{ 974 "banner|300x600|www.website5.com": 15, 975 "*|*|*": 25, 976 }, 977 Schema: openrtb_ext.PriceFloorSchema{ 978 Fields: []string{"mediaType", "size", "domain"}, 979 }, 980 }, 981 }, 982 FetchRate: ptrutil.ToPtr(100), 983 }, 984 }, 985 }, 986 { 987 name: "Dynamic fetch enabled, floors from fetched selected as data rate not provided as default value = 100", 988 fetcher: &MockFetchDataRateNotProvided{}, 989 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 990 BidRequest: &openrtb2.BidRequest{ 991 Site: &openrtb2.Site{ 992 Publisher: &openrtb2.Publisher{Domain: "www.website.com"}, 993 }, 994 Imp: []openrtb2.Imp{{ID: "1234", Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}}}}}, 995 Ext: json.RawMessage(`{"prebid":{"floors":{"data":{"currency":"USD","modelgroups":[{"modelversion":"model 1 from req","currency":"USD","values":{"banner|300x600|www.website5.com":5,"*|*|*":7},"schema":{"fields":["mediaType","size","domain"],"delimiter":"|"}}]},"enabled":true,"enforcement":{"enforcepbs":true,"floordeals":true,"enforcerate":100}}}}`), 996 }, 997 }, 998 account: config.Account{ 999 PriceFloors: config.AccountPriceFloors{ 1000 Enabled: true, 1001 UseDynamicData: true, 1002 }, 1003 }, 1004 expFloors: &openrtb_ext.PriceFloorRules{ 1005 Enabled: getTrue(), 1006 FetchStatus: openrtb_ext.FetchSuccess, 1007 PriceFloorLocation: openrtb_ext.FetchLocation, 1008 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1009 EnforcePBS: getTrue(), 1010 FloorDeals: getTrue(), 1011 EnforceRate: 100, 1012 }, 1013 Data: &openrtb_ext.PriceFloorData{ 1014 Currency: "USD", 1015 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1016 { 1017 ModelVersion: "model from fetched", 1018 Currency: "USD", 1019 Values: map[string]float64{ 1020 "banner|300x600|www.website5.com": 5, 1021 "*|*|*": 15, 1022 }, 1023 Schema: openrtb_ext.PriceFloorSchema{ 1024 Fields: []string{"mediaType", "size", "domain"}, 1025 }, 1026 }, 1027 }, 1028 }, 1029 }, 1030 }, 1031 } 1032 1033 for _, tc := range testCases { 1034 t.Run(tc.name, func(t *testing.T) { 1035 resolvedFloors, _ := resolveFloors(tc.account, tc.bidRequestWrapper, getCurrencyRates(rates), tc.fetcher) 1036 assert.Equal(t, resolvedFloors, tc.expFloors, tc.name) 1037 }) 1038 } 1039 } 1040 1041 func printFloors(floors *openrtb_ext.PriceFloorRules) string { 1042 fbytes, _ := jsonutil.Marshal(floors) 1043 return string(fbytes) 1044 } 1045 1046 func TestCreateFloorsFrom(t *testing.T) { 1047 1048 testAccountConfig := config.Account{ 1049 PriceFloors: config.AccountPriceFloors{ 1050 Enabled: true, 1051 UseDynamicData: false, 1052 MaxRule: 100, 1053 MaxSchemaDims: 5, 1054 }, 1055 } 1056 1057 type args struct { 1058 floors *openrtb_ext.PriceFloorRules 1059 account config.Account 1060 fetchStatus string 1061 floorLocation string 1062 } 1063 testCases := []struct { 1064 name string 1065 args args 1066 want *openrtb_ext.PriceFloorRules 1067 want1 []error 1068 }{ 1069 { 1070 name: "floor provider should be selected from floor json", 1071 args: args{ 1072 account: testAccountConfig, 1073 floors: &openrtb_ext.PriceFloorRules{ 1074 Enabled: getTrue(), 1075 FloorMin: 10.11, 1076 FloorMinCur: "EUR", 1077 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1078 EnforcePBS: getTrue(), 1079 EnforceRate: 100, 1080 FloorDeals: getTrue(), 1081 }, 1082 Data: &openrtb_ext.PriceFloorData{ 1083 Currency: "USD", 1084 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1085 { 1086 ModelVersion: "model from fetched", 1087 Currency: "USD", 1088 Values: map[string]float64{ 1089 "banner|300x600|www.website5.com": 15, 1090 "*|*|*": 25, 1091 }, 1092 Schema: openrtb_ext.PriceFloorSchema{ 1093 Fields: []string{"mediaType", "size", "domain"}, 1094 }, 1095 }, 1096 }, 1097 FloorProvider: "PM", 1098 }, 1099 }, 1100 fetchStatus: openrtb_ext.FetchSuccess, 1101 floorLocation: openrtb_ext.FetchLocation, 1102 }, 1103 want: &openrtb_ext.PriceFloorRules{ 1104 Enabled: getTrue(), 1105 FloorMin: 10.11, 1106 FloorMinCur: "EUR", 1107 FetchStatus: openrtb_ext.FetchSuccess, 1108 PriceFloorLocation: openrtb_ext.FetchLocation, 1109 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1110 EnforcePBS: getTrue(), 1111 EnforceRate: 100, 1112 FloorDeals: getTrue(), 1113 }, 1114 Data: &openrtb_ext.PriceFloorData{ 1115 Currency: "USD", 1116 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1117 { 1118 ModelVersion: "model from fetched", 1119 Currency: "USD", 1120 Values: map[string]float64{ 1121 "banner|300x600|www.website5.com": 15, 1122 "*|*|*": 25, 1123 }, 1124 Schema: openrtb_ext.PriceFloorSchema{ 1125 Fields: []string{"mediaType", "size", "domain"}, 1126 }, 1127 }, 1128 }, 1129 FloorProvider: "PM", 1130 }, 1131 }, 1132 }, 1133 { 1134 name: "floor provider will be empty if no value provided in floor json", 1135 args: args{ 1136 account: testAccountConfig, 1137 floors: &openrtb_ext.PriceFloorRules{ 1138 Enabled: getTrue(), 1139 FloorMin: 10.11, 1140 FloorMinCur: "EUR", 1141 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1142 EnforcePBS: getTrue(), 1143 EnforceRate: 100, 1144 FloorDeals: getTrue(), 1145 }, 1146 Data: &openrtb_ext.PriceFloorData{ 1147 Currency: "USD", 1148 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1149 { 1150 ModelVersion: "model from request", 1151 Currency: "USD", 1152 Values: map[string]float64{ 1153 "banner|300x600|www.website5.com": 15, 1154 "*|*|*": 25, 1155 }, 1156 Schema: openrtb_ext.PriceFloorSchema{ 1157 Fields: []string{"mediaType", "size", "domain"}, 1158 }, 1159 }, 1160 }, 1161 FloorProvider: "", 1162 }, 1163 }, 1164 fetchStatus: openrtb_ext.FetchSuccess, 1165 floorLocation: openrtb_ext.FetchLocation, 1166 }, 1167 want: &openrtb_ext.PriceFloorRules{ 1168 Enabled: getTrue(), 1169 FloorMin: 10.11, 1170 FloorMinCur: "EUR", 1171 FetchStatus: openrtb_ext.FetchSuccess, 1172 PriceFloorLocation: openrtb_ext.FetchLocation, 1173 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1174 EnforcePBS: getTrue(), 1175 EnforceRate: 100, 1176 FloorDeals: getTrue(), 1177 }, 1178 Data: &openrtb_ext.PriceFloorData{ 1179 Currency: "USD", 1180 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1181 { 1182 ModelVersion: "model from request", 1183 Currency: "USD", 1184 Values: map[string]float64{ 1185 "banner|300x600|www.website5.com": 15, 1186 "*|*|*": 25, 1187 }, 1188 Schema: openrtb_ext.PriceFloorSchema{ 1189 Fields: []string{"mediaType", "size", "domain"}, 1190 }, 1191 }, 1192 }, 1193 FloorProvider: "", 1194 }, 1195 }, 1196 }, 1197 { 1198 name: "only floor enforcement object present", 1199 args: args{ 1200 account: testAccountConfig, 1201 floors: &openrtb_ext.PriceFloorRules{ 1202 Enabled: getTrue(), 1203 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1204 EnforcePBS: getTrue(), 1205 EnforceRate: 100, 1206 FloorDeals: getTrue(), 1207 }, 1208 }, 1209 fetchStatus: openrtb_ext.FetchNone, 1210 floorLocation: openrtb_ext.RequestLocation, 1211 }, 1212 want: &openrtb_ext.PriceFloorRules{ 1213 FetchStatus: openrtb_ext.FetchNone, 1214 PriceFloorLocation: openrtb_ext.RequestLocation, 1215 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1216 EnforcePBS: getTrue(), 1217 EnforceRate: 100, 1218 FloorDeals: getTrue(), 1219 }, 1220 }, 1221 }, 1222 { 1223 name: "Invalid modelGroup with skipRate = 110", 1224 args: args{ 1225 account: testAccountConfig, 1226 floors: &openrtb_ext.PriceFloorRules{ 1227 Enabled: getTrue(), 1228 Data: &openrtb_ext.PriceFloorData{ 1229 Currency: "USD", 1230 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1231 { 1232 ModelVersion: "model from fetched", 1233 Currency: "USD", 1234 SkipRate: 110, 1235 Values: map[string]float64{ 1236 "banner|300x600|www.website5.com": 15, 1237 "*|*|*": 25, 1238 }, 1239 Schema: openrtb_ext.PriceFloorSchema{ 1240 Fields: []string{"mediaType", "size", "domain"}, 1241 }, 1242 }, 1243 }, 1244 }, 1245 }, 1246 fetchStatus: openrtb_ext.FetchNone, 1247 floorLocation: openrtb_ext.RequestLocation, 1248 }, 1249 want: &openrtb_ext.PriceFloorRules{ 1250 FetchStatus: openrtb_ext.FetchNone, 1251 PriceFloorLocation: openrtb_ext.RequestLocation, 1252 }, 1253 want1: []error{ 1254 errors.New("Invalid Floor Model = 'model from fetched' due to SkipRate = '110' is out of range (1-100)"), 1255 }, 1256 }, 1257 } 1258 for _, tc := range testCases { 1259 t.Run(tc.name, func(t *testing.T) { 1260 got, got1 := createFloorsFrom(tc.args.floors, tc.args.account, tc.args.fetchStatus, tc.args.floorLocation) 1261 assert.Equal(t, got1, tc.want1, tc.name) 1262 assert.Equal(t, got, tc.want, tc.name) 1263 }) 1264 } 1265 } 1266 1267 func TestIsPriceFloorsEnabled(t *testing.T) { 1268 type args struct { 1269 account config.Account 1270 bidRequestWrapper *openrtb_ext.RequestWrapper 1271 } 1272 tests := []struct { 1273 name string 1274 args args 1275 want bool 1276 }{ 1277 { 1278 name: "Disabled in account and req", 1279 args: args{ 1280 account: config.Account{PriceFloors: config.AccountPriceFloors{Enabled: false}}, 1281 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 1282 BidRequest: &openrtb2.BidRequest{ 1283 Ext: json.RawMessage(`{"prebid":{"floors":{"enabled": false} }}`), 1284 }, 1285 }, 1286 }, 1287 want: false, 1288 }, 1289 { 1290 name: "Enabled in account and req", 1291 args: args{ 1292 account: config.Account{PriceFloors: config.AccountPriceFloors{Enabled: true}}, 1293 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 1294 BidRequest: &openrtb2.BidRequest{ 1295 Ext: json.RawMessage(`{"prebid":{"floors":{"enabled": true} }}`), 1296 }, 1297 }, 1298 }, 1299 want: true, 1300 }, 1301 { 1302 name: "disabled in account and enabled req", 1303 args: args{ 1304 account: config.Account{PriceFloors: config.AccountPriceFloors{Enabled: false}}, 1305 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 1306 BidRequest: &openrtb2.BidRequest{ 1307 Ext: json.RawMessage(`{"prebid":{"floors":{"enabled": true} }}`), 1308 }, 1309 }, 1310 }, 1311 want: false, 1312 }, 1313 { 1314 name: "Enabled in account and disabled in req", 1315 args: args{ 1316 account: config.Account{PriceFloors: config.AccountPriceFloors{Enabled: true}}, 1317 bidRequestWrapper: &openrtb_ext.RequestWrapper{ 1318 BidRequest: &openrtb2.BidRequest{ 1319 Ext: json.RawMessage(`{"prebid":{"floors":{"enabled": false} }}`)}, 1320 }, 1321 }, 1322 want: false, 1323 }, 1324 } 1325 for _, tt := range tests { 1326 t.Run(tt.name, func(t *testing.T) { 1327 got := isPriceFloorsEnabled(tt.args.account, tt.args.bidRequestWrapper) 1328 assert.Equal(t, got, tt.want, tt.name) 1329 }) 1330 } 1331 } 1332 1333 func TestResolveFloorMin(t *testing.T) { 1334 rates := map[string]map[string]float64{ 1335 "USD": { 1336 "INR": 70, 1337 "EUR": 0.9, 1338 "JPY": 5.09, 1339 }, 1340 } 1341 1342 tt := []struct { 1343 name string 1344 reqFloors openrtb_ext.PriceFloorRules 1345 fetchFloors openrtb_ext.PriceFloorRules 1346 conversions currency.Conversions 1347 expPrice Price 1348 }{ 1349 { 1350 name: "FloorsMin present in request Floors only", 1351 reqFloors: openrtb_ext.PriceFloorRules{ 1352 FloorMin: 10, 1353 FloorMinCur: "JPY", 1354 }, 1355 fetchFloors: openrtb_ext.PriceFloorRules{}, 1356 expPrice: Price{FloorMin: 10, FloorMinCur: "JPY"}, 1357 }, 1358 { 1359 name: "FloorsMin, FloorMinCur and data currency present in request Floors", 1360 reqFloors: openrtb_ext.PriceFloorRules{ 1361 FloorMin: 10, 1362 FloorMinCur: "JPY", 1363 Data: &openrtb_ext.PriceFloorData{ 1364 Currency: "USD", 1365 }, 1366 }, 1367 fetchFloors: openrtb_ext.PriceFloorRules{}, 1368 expPrice: Price{FloorMin: 10, FloorMinCur: "JPY"}, 1369 }, 1370 { 1371 name: "FloorsMin and data currency present in request Floors", 1372 reqFloors: openrtb_ext.PriceFloorRules{ 1373 FloorMin: 10, 1374 Data: &openrtb_ext.PriceFloorData{ 1375 Currency: "USD", 1376 }, 1377 }, 1378 fetchFloors: openrtb_ext.PriceFloorRules{}, 1379 expPrice: Price{FloorMin: 10, FloorMinCur: "USD"}, 1380 }, 1381 { 1382 name: "FloorsMin and FloorMinCur present in request Floors and fetched floors", 1383 reqFloors: openrtb_ext.PriceFloorRules{ 1384 FloorMin: 10, 1385 FloorMinCur: "USD", 1386 }, 1387 fetchFloors: openrtb_ext.PriceFloorRules{ 1388 FloorMin: 15, 1389 FloorMinCur: "INR", 1390 }, 1391 expPrice: Price{FloorMin: 10, FloorMinCur: "USD"}, 1392 }, 1393 { 1394 name: "FloorsMin present fetched floors only", 1395 reqFloors: openrtb_ext.PriceFloorRules{}, 1396 fetchFloors: openrtb_ext.PriceFloorRules{ 1397 FloorMin: 15, 1398 FloorMinCur: "EUR", 1399 }, 1400 expPrice: Price{FloorMin: 15, FloorMinCur: "EUR"}, 1401 }, 1402 { 1403 name: "FloorMinCur present in reqFloors And FloorsMin, FloorMinCur present in fetched floors (Same Currency)", 1404 reqFloors: openrtb_ext.PriceFloorRules{ 1405 FloorMinCur: "EUR", 1406 }, 1407 fetchFloors: openrtb_ext.PriceFloorRules{ 1408 FloorMin: 15, 1409 FloorMinCur: "EUR", 1410 }, 1411 expPrice: Price{FloorMin: 15, FloorMinCur: "EUR"}, 1412 }, 1413 { 1414 name: "FloorMinCur present in reqFloors And FloorsMin, FloorMinCur present in fetched floors (Different Currency)", 1415 reqFloors: openrtb_ext.PriceFloorRules{ 1416 FloorMinCur: "USD", 1417 }, 1418 fetchFloors: openrtb_ext.PriceFloorRules{ 1419 FloorMin: 15, 1420 FloorMinCur: "EUR", 1421 }, 1422 expPrice: Price{FloorMin: 16.6667, FloorMinCur: "USD"}, 1423 }, 1424 { 1425 name: "FloorMin present in reqFloors And FloorMinCur present in fetched floors", 1426 reqFloors: openrtb_ext.PriceFloorRules{ 1427 FloorMin: 11, 1428 }, 1429 fetchFloors: openrtb_ext.PriceFloorRules{ 1430 FloorMinCur: "EUR", 1431 }, 1432 expPrice: Price{FloorMin: 11, FloorMinCur: "EUR"}, 1433 }, 1434 { 1435 name: "FloorMinCur present in reqFloors And FloorMin present in fetched floors", 1436 reqFloors: openrtb_ext.PriceFloorRules{ 1437 FloorMinCur: "INR", 1438 }, 1439 fetchFloors: openrtb_ext.PriceFloorRules{ 1440 FloorMin: 12, 1441 }, 1442 expPrice: Price{FloorMin: 12, FloorMinCur: "INR"}, 1443 }, 1444 { 1445 name: "FloorMinCur present in reqFloors And FloorMin, data currency present in fetched floors", 1446 reqFloors: openrtb_ext.PriceFloorRules{ 1447 FloorMinCur: "INR", 1448 }, 1449 fetchFloors: openrtb_ext.PriceFloorRules{ 1450 FloorMin: 1, 1451 Data: &openrtb_ext.PriceFloorData{Currency: "USD"}, 1452 }, 1453 expPrice: Price{FloorMin: 70, FloorMinCur: "INR"}, 1454 }, 1455 { 1456 name: "FloorMinCur present in fetched Floors And data currency present in reqFloors", 1457 reqFloors: openrtb_ext.PriceFloorRules{ 1458 FloorMin: 2, 1459 }, 1460 fetchFloors: openrtb_ext.PriceFloorRules{ 1461 Data: &openrtb_ext.PriceFloorData{Currency: "USD"}, 1462 }, 1463 expPrice: Price{FloorMin: 2, FloorMinCur: "USD"}, 1464 }, 1465 { 1466 name: "Data currency and FloorMin present in fetched floors", 1467 reqFloors: openrtb_ext.PriceFloorRules{}, 1468 fetchFloors: openrtb_ext.PriceFloorRules{ 1469 FloorMin: 12, 1470 Data: &openrtb_ext.PriceFloorData{Currency: "USD"}, 1471 }, 1472 expPrice: Price{FloorMin: 12, FloorMinCur: "USD"}, 1473 }, 1474 { 1475 name: "Empty reqFloors And Empty fetched floors", 1476 reqFloors: openrtb_ext.PriceFloorRules{}, 1477 fetchFloors: openrtb_ext.PriceFloorRules{}, 1478 expPrice: Price{FloorMin: 0.0, FloorMinCur: ""}, 1479 }, 1480 } 1481 for _, tc := range tt { 1482 t.Run(tc.name, func(t *testing.T) { 1483 price := resolveFloorMin(&tc.reqFloors, &tc.fetchFloors, getCurrencyRates(rates)) 1484 if !reflect.DeepEqual(price.FloorMin, tc.expPrice.FloorMin) { 1485 t.Errorf("Floor Value error: \nreturn:\t%v\nwant:\t%v", price.FloorMin, tc.expPrice.FloorMin) 1486 } 1487 if !reflect.DeepEqual(price.FloorMinCur, tc.expPrice.FloorMinCur) { 1488 t.Errorf("Floor Currency error: \nreturn:\t%v\nwant:\t%v", price.FloorMinCur, tc.expPrice.FloorMinCur) 1489 } 1490 1491 }) 1492 } 1493 } 1494 1495 func TestMergeFloors(t *testing.T) { 1496 1497 rates := map[string]map[string]float64{ 1498 "USD": { 1499 "INR": 70, 1500 "EUR": 0.9, 1501 "JPY": 5.09, 1502 }, 1503 } 1504 1505 type args struct { 1506 reqFloors *openrtb_ext.PriceFloorRules 1507 fetchFloors *openrtb_ext.PriceFloorRules 1508 } 1509 tests := []struct { 1510 name string 1511 args args 1512 want *openrtb_ext.PriceFloorRules 1513 }{ 1514 { 1515 name: "Fetched Floors are present and request Floors are empty", 1516 args: args{ 1517 reqFloors: nil, 1518 fetchFloors: &openrtb_ext.PriceFloorRules{ 1519 Enabled: getTrue(), 1520 Data: &openrtb_ext.PriceFloorData{ 1521 Currency: "INR", 1522 SkipRate: 0, 1523 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1524 { 1525 ModelVersion: "Version 1", 1526 Currency: "INR", 1527 Values: map[string]float64{ 1528 "banner|300x600|www.website5.com": 20, 1529 "*|*|*": 50, 1530 }, 1531 Schema: openrtb_ext.PriceFloorSchema{ 1532 Fields: []string{"mediaType", "size", "domain"}, 1533 Delimiter: "|", 1534 }, 1535 }, 1536 }, 1537 }, 1538 }, 1539 }, 1540 want: &openrtb_ext.PriceFloorRules{ 1541 Enabled: getTrue(), 1542 Data: &openrtb_ext.PriceFloorData{ 1543 Currency: "INR", 1544 SkipRate: 0, 1545 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1546 { 1547 ModelVersion: "Version 1", 1548 Currency: "INR", 1549 Values: map[string]float64{ 1550 "banner|300x600|www.website5.com": 20, 1551 "*|*|*": 50, 1552 }, 1553 Schema: openrtb_ext.PriceFloorSchema{ 1554 Fields: []string{"mediaType", "size", "domain"}, 1555 Delimiter: "|", 1556 }, 1557 }, 1558 }, 1559 }, 1560 }, 1561 }, 1562 { 1563 name: "Fetched Floors are present and request Floors has floors disabled", 1564 args: args{ 1565 reqFloors: &openrtb_ext.PriceFloorRules{ 1566 Enabled: getFalse(), 1567 }, 1568 fetchFloors: &openrtb_ext.PriceFloorRules{ 1569 Enabled: getTrue(), 1570 Data: &openrtb_ext.PriceFloorData{ 1571 Currency: "INR", 1572 SkipRate: 0, 1573 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1574 { 1575 ModelVersion: "Version 1", 1576 Currency: "INR", 1577 Values: map[string]float64{ 1578 "banner|300x600|www.website5.com": 20, 1579 "*|*|*": 50, 1580 }, 1581 Schema: openrtb_ext.PriceFloorSchema{ 1582 Fields: []string{"mediaType", "size", "domain"}, 1583 Delimiter: "|", 1584 }, 1585 }, 1586 }, 1587 }, 1588 }, 1589 }, 1590 want: &openrtb_ext.PriceFloorRules{ 1591 Enabled: getFalse(), 1592 Data: &openrtb_ext.PriceFloorData{ 1593 Currency: "INR", 1594 SkipRate: 0, 1595 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1596 { 1597 ModelVersion: "Version 1", 1598 Currency: "INR", 1599 Values: map[string]float64{ 1600 "banner|300x600|www.website5.com": 20, 1601 "*|*|*": 50, 1602 }, 1603 Schema: openrtb_ext.PriceFloorSchema{ 1604 Fields: []string{"mediaType", "size", "domain"}, 1605 Delimiter: "|", 1606 }, 1607 }, 1608 }, 1609 }, 1610 }, 1611 }, 1612 { 1613 name: "Fetched Floors are present and request Floors has enforcement (enforcepbs = true)", 1614 args: args{ 1615 reqFloors: &openrtb_ext.PriceFloorRules{ 1616 Enabled: getTrue(), 1617 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1618 EnforceRate: 50, 1619 EnforcePBS: getTrue(), 1620 }, 1621 }, 1622 fetchFloors: &openrtb_ext.PriceFloorRules{ 1623 Enabled: getTrue(), 1624 Data: &openrtb_ext.PriceFloorData{ 1625 Currency: "INR", 1626 SkipRate: 0, 1627 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1628 { 1629 ModelVersion: "Version 1", 1630 Currency: "INR", 1631 Values: map[string]float64{ 1632 "banner|300x600|www.website5.com": 20, 1633 "*|*|*": 50, 1634 }, 1635 Schema: openrtb_ext.PriceFloorSchema{ 1636 Fields: []string{"mediaType", "size", "domain"}, 1637 Delimiter: "|", 1638 }, 1639 }, 1640 }, 1641 }, 1642 }, 1643 }, 1644 want: &openrtb_ext.PriceFloorRules{ 1645 Enabled: getTrue(), 1646 Data: &openrtb_ext.PriceFloorData{ 1647 Currency: "INR", 1648 SkipRate: 0, 1649 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1650 { 1651 ModelVersion: "Version 1", 1652 Currency: "INR", 1653 Values: map[string]float64{ 1654 "banner|300x600|www.website5.com": 20, 1655 "*|*|*": 50, 1656 }, 1657 Schema: openrtb_ext.PriceFloorSchema{ 1658 Fields: []string{"mediaType", "size", "domain"}, 1659 Delimiter: "|", 1660 }, 1661 }, 1662 }, 1663 }, 1664 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1665 EnforceRate: 50, 1666 EnforcePBS: getTrue(), 1667 }, 1668 }, 1669 }, 1670 { 1671 name: "Fetched Floors are present and request Floors has enforcement (enforcepbs = false)", 1672 args: args{ 1673 reqFloors: &openrtb_ext.PriceFloorRules{ 1674 Enabled: getTrue(), 1675 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1676 EnforceRate: 50, 1677 EnforcePBS: getFalse(), 1678 }, 1679 }, 1680 fetchFloors: &openrtb_ext.PriceFloorRules{ 1681 Enabled: getTrue(), 1682 Data: &openrtb_ext.PriceFloorData{ 1683 Currency: "INR", 1684 SkipRate: 0, 1685 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1686 { 1687 ModelVersion: "Version 1", 1688 Currency: "INR", 1689 Values: map[string]float64{ 1690 "banner|300x600|www.website5.com": 20, 1691 "*|*|*": 50, 1692 }, 1693 Schema: openrtb_ext.PriceFloorSchema{ 1694 Fields: []string{"mediaType", "size", "domain"}, 1695 Delimiter: "|", 1696 }, 1697 }, 1698 }, 1699 }, 1700 }, 1701 }, 1702 want: &openrtb_ext.PriceFloorRules{ 1703 Enabled: getTrue(), 1704 Data: &openrtb_ext.PriceFloorData{ 1705 Currency: "INR", 1706 SkipRate: 0, 1707 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1708 { 1709 ModelVersion: "Version 1", 1710 Currency: "INR", 1711 Values: map[string]float64{ 1712 "banner|300x600|www.website5.com": 20, 1713 "*|*|*": 50, 1714 }, 1715 Schema: openrtb_ext.PriceFloorSchema{ 1716 Fields: []string{"mediaType", "size", "domain"}, 1717 Delimiter: "|", 1718 }, 1719 }, 1720 }, 1721 }, 1722 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1723 EnforceRate: 50, 1724 EnforcePBS: getFalse(), 1725 }, 1726 }, 1727 }, 1728 { 1729 name: "Fetched Floors are present and request Floors has Floormin", 1730 args: args{ 1731 reqFloors: &openrtb_ext.PriceFloorRules{ 1732 Enabled: getTrue(), 1733 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1734 EnforceRate: 50, 1735 EnforcePBS: getFalse(), 1736 }, 1737 FloorMin: 5, 1738 FloorMinCur: "INR", 1739 }, 1740 fetchFloors: &openrtb_ext.PriceFloorRules{ 1741 Enabled: getTrue(), 1742 Data: &openrtb_ext.PriceFloorData{ 1743 Currency: "INR", 1744 SkipRate: 0, 1745 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1746 { 1747 ModelVersion: "Version 1", 1748 Currency: "INR", 1749 Values: map[string]float64{ 1750 "banner|300x600|www.website5.com": 20, 1751 "*|*|*": 50, 1752 }, 1753 Schema: openrtb_ext.PriceFloorSchema{ 1754 Fields: []string{"mediaType", "size", "domain"}, 1755 Delimiter: "|", 1756 }, 1757 }, 1758 }, 1759 }, 1760 }, 1761 }, 1762 want: &openrtb_ext.PriceFloorRules{ 1763 Enabled: getTrue(), 1764 Data: &openrtb_ext.PriceFloorData{ 1765 Currency: "INR", 1766 SkipRate: 0, 1767 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1768 { 1769 ModelVersion: "Version 1", 1770 Currency: "INR", 1771 Values: map[string]float64{ 1772 "banner|300x600|www.website5.com": 20, 1773 "*|*|*": 50, 1774 }, 1775 Schema: openrtb_ext.PriceFloorSchema{ 1776 Fields: []string{"mediaType", "size", "domain"}, 1777 Delimiter: "|", 1778 }, 1779 }, 1780 }, 1781 }, 1782 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1783 EnforceRate: 50, 1784 EnforcePBS: getFalse(), 1785 }, 1786 FloorMin: 5, 1787 FloorMinCur: "INR", 1788 }, 1789 }, 1790 { 1791 name: "Fetched Floors are present and request Floors has URL", 1792 args: args{ 1793 reqFloors: &openrtb_ext.PriceFloorRules{ 1794 Enabled: getTrue(), 1795 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1796 EnforceRate: 50, 1797 EnforcePBS: getFalse(), 1798 }, 1799 FloorMin: 5, 1800 FloorMinCur: "INR", 1801 Location: &openrtb_ext.PriceFloorEndpoint{ 1802 URL: "https://test.com/floors", 1803 }, 1804 }, 1805 fetchFloors: &openrtb_ext.PriceFloorRules{ 1806 Enabled: getTrue(), 1807 Data: &openrtb_ext.PriceFloorData{ 1808 Currency: "INR", 1809 SkipRate: 0, 1810 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1811 { 1812 ModelVersion: "Version 1", 1813 Currency: "INR", 1814 Values: map[string]float64{ 1815 "banner|300x600|www.website5.com": 20, 1816 "*|*|*": 50, 1817 }, 1818 Schema: openrtb_ext.PriceFloorSchema{ 1819 Fields: []string{"mediaType", "size", "domain"}, 1820 Delimiter: "|", 1821 }, 1822 }, 1823 }, 1824 }, 1825 }, 1826 }, 1827 want: &openrtb_ext.PriceFloorRules{ 1828 Enabled: getTrue(), 1829 Data: &openrtb_ext.PriceFloorData{ 1830 Currency: "INR", 1831 SkipRate: 0, 1832 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1833 { 1834 ModelVersion: "Version 1", 1835 Currency: "INR", 1836 Values: map[string]float64{ 1837 "banner|300x600|www.website5.com": 20, 1838 "*|*|*": 50, 1839 }, 1840 Schema: openrtb_ext.PriceFloorSchema{ 1841 Fields: []string{"mediaType", "size", "domain"}, 1842 Delimiter: "|", 1843 }, 1844 }, 1845 }, 1846 }, 1847 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1848 EnforceRate: 50, 1849 EnforcePBS: getFalse(), 1850 }, 1851 FloorMin: 5, 1852 FloorMinCur: "INR", 1853 Location: &openrtb_ext.PriceFloorEndpoint{ 1854 URL: "https://test.com/floors", 1855 }, 1856 }, 1857 }, 1858 { 1859 name: "Fetched Floors has no enable atrribute are present and request Floors has URL", 1860 args: args{ 1861 reqFloors: &openrtb_ext.PriceFloorRules{ 1862 Enabled: getTrue(), 1863 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1864 EnforceRate: 50, 1865 EnforcePBS: getFalse(), 1866 }, 1867 FloorMin: 5, 1868 FloorMinCur: "INR", 1869 Location: &openrtb_ext.PriceFloorEndpoint{ 1870 URL: "https://test.com/floors", 1871 }, 1872 }, 1873 fetchFloors: &openrtb_ext.PriceFloorRules{ 1874 Data: &openrtb_ext.PriceFloorData{ 1875 Currency: "INR", 1876 SkipRate: 0, 1877 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1878 { 1879 ModelVersion: "Version 1", 1880 Currency: "INR", 1881 Values: map[string]float64{ 1882 "banner|300x600|www.website5.com": 20, 1883 "*|*|*": 50, 1884 }, 1885 Schema: openrtb_ext.PriceFloorSchema{ 1886 Fields: []string{"mediaType", "size", "domain"}, 1887 Delimiter: "|", 1888 }, 1889 }, 1890 }, 1891 }, 1892 }, 1893 }, 1894 want: &openrtb_ext.PriceFloorRules{ 1895 Enabled: getTrue(), 1896 Data: &openrtb_ext.PriceFloorData{ 1897 Currency: "INR", 1898 SkipRate: 0, 1899 ModelGroups: []openrtb_ext.PriceFloorModelGroup{ 1900 { 1901 ModelVersion: "Version 1", 1902 Currency: "INR", 1903 Values: map[string]float64{ 1904 "banner|300x600|www.website5.com": 20, 1905 "*|*|*": 50, 1906 }, 1907 Schema: openrtb_ext.PriceFloorSchema{ 1908 Fields: []string{"mediaType", "size", "domain"}, 1909 Delimiter: "|", 1910 }, 1911 }, 1912 }, 1913 }, 1914 Enforcement: &openrtb_ext.PriceFloorEnforcement{ 1915 EnforceRate: 50, 1916 EnforcePBS: getFalse(), 1917 }, 1918 FloorMin: 5, 1919 FloorMinCur: "INR", 1920 Location: &openrtb_ext.PriceFloorEndpoint{ 1921 URL: "https://test.com/floors", 1922 }, 1923 }, 1924 }, 1925 } 1926 for _, tt := range tests { 1927 t.Run(tt.name, func(t *testing.T) { 1928 if got := mergeFloors(tt.args.reqFloors, tt.args.fetchFloors, getCurrencyRates(rates)); !reflect.DeepEqual(got, tt.want) { 1929 t.Errorf("mergeFloors() = %v, want %v", got, tt.want) 1930 } 1931 }) 1932 } 1933 }