Skip to content

Commit

Permalink
Release: OWS_Q2_5_July_2022 (prebid#324)
Browse files Browse the repository at this point in the history
* OTT-356: Setting WB=1 for adpod bids for new generate bid id feature (prebid#304)
* OTT-478: Added updatedrequest in debug log to know about floor rule selection (prebid#306)
* OTT-478: Fixed UT for floors enforcement (prebid#308)
* OTT-583 :: Refactored floor code and used RequestWrapper for retrieving and setting extension object (prebid#310)
* OTT-589: Eids is getting passed randomly to user.eids for appnexus adapter (prebid#311)
* OTT-583: Added formating (prebid#318)
* OTT-479: Updated for currency conversion related valiation and error in rejected bids (prebid#320)
* OTT-598:: Added check if floor data is nil
* OTT-596: Updated error message for currency conversion error (prebid#322)
* OTT-596: Fixed UT's for  error message for currency conversion error (prebid#323)

Co-authored-by: Jaydeep Mohite <30924180+pm-jaydeep-mohite@users.noreply.github.com>
Co-authored-by: Jaydeep Mohite <jaydeep.mohite@pubmatic.com>
Co-authored-by: Viral Vala <63396712+pm-viral-vala@users.noreply.github.com>
Co-authored-by: Pubmatic-Dhruv-Sonone <83747371+Pubmatic-Dhruv-Sonone@users.noreply.github.com>
Co-authored-by: PubMatic-OpenWrap <UOEDev@pubmatic.com>
  • Loading branch information
6 people authored Jun 29, 2022
1 parent 31d0dd2 commit 6ea3250
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 44 deletions.
4 changes: 1 addition & 3 deletions exchange/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,6 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *

// If floors feature is enabled at server and request level, Update floors values in impression object
floorErrs := SignalFloors(&r, e.floor, conversions, responseDebugAllow)
errs = append(errs, floorErrs...)

recordImpMetrics(r.BidRequestWrapper.BidRequest, e.me)

Expand All @@ -260,7 +259,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
tcf2Cfg := r.TCF2ConfigBuilder(e.privacyConfig.GDPR.TCF2, r.Account.GDPR)
gdprPerms := r.GDPRPermissionsBuilder(e.privacyConfig.GDPR, tcf2Cfg, e.gvlVendorIDs, e.vendorListFetcher)
bidderRequests, privacyLabels, errs := cleanOpenRTBRequests(ctx, r, requestExt, e.bidderToSyncerKey, e.me, gdprDefaultValue, gdprPerms, e.privacyConfig, tcf2Cfg)

errs = append(errs, floorErrs...)
e.me.RecordRequestPrivacy(privacyLabels)

// If we need to cache bids, then it will take some time to call prebid cache.
Expand Down Expand Up @@ -723,7 +722,6 @@ func (e *exchange) buildBidResponse(ctx context.Context, liveAdapters []openrtb_
}

bidResponse.SeatBid = seatBids

bidResponse.Ext, err = encodeBidResponseExt(bidResponseExt)

return bidResponse, err
Expand Down
22 changes: 13 additions & 9 deletions exchange/floors.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@ func EnforceFloorToBids(bidRequest *openrtb2.BidRequest, seatBids map[openrtb_ex
if seatBid.currency != bidFloor.bidFloorCur {
rate, err := conversions.GetRate(seatBid.currency, bidFloor.bidFloorCur)
if err != nil {
glog.Warningf("error in rate conversion with bidder %s for impression id %s and bid id %s", bidderName, bid.bid.ImpID, bidID)
errMsg := fmt.Sprintf("Error in rate conversion from = %s to %s with bidder %s for impression id %s and bid id %s", seatBid.currency, bidFloor.bidFloorCur, bidderName, bid.bid.ImpID, bidID)
glog.Errorf(errMsg)
rejections = append(rejections, errMsg)
continue
}
bidPrice = rate * bid.bid.Price
}
if bidFloor.bidFloor > bidPrice {
rejections = updateRejections(rejections, bidID, fmt.Sprintf("bid price value %f is less than bidFloor value %f for impression id %s bidder %s", bidPrice, bidFloor.bidFloor, bid.bid.ImpID, bidderName))
rejections = updateRejections(rejections, bidID, fmt.Sprintf("bid price value %.4f %s is less than bidFloor value %.4f %s for impression id %s bidder %s", bidPrice, bidFloor.bidFloorCur, bidFloor.bidFloor, bidFloor.bidFloorCur, bid.bid.ImpID, bidderName))
continue
}
eligibleBids = append(eligibleBids, bid)
Expand All @@ -77,7 +79,7 @@ func SignalFloors(r *AuctionRequest, floor floors.Floor, conversions currency.Co
return errs
}
prebidExt := requestExt.GetPrebid()
if floor != nil && floor.Enabled() && floors.IsRequestEnabledWithFloor(prebidExt.Floors) {
if floor != nil && floor.Enabled() && floors.IsRequestEnabledWithFloor(prebidExt.Floors) && prebidExt.Floors != nil {
errs = floors.UpdateImpsWithFloors(prebidExt.Floors, r.BidRequestWrapper.BidRequest, conversions)
requestExt.SetPrebid(prebidExt)
err := r.BidRequestWrapper.RebuildRequest()
Expand All @@ -104,14 +106,16 @@ func EnforceFloors(r *AuctionRequest, seatBids map[openrtb_ext.BidderName]*pbsOr
return seatBids, rejections
}
prebidExt := requestExt.GetPrebid()
if floor != nil && floor.Enabled() && floors.IsRequestEnabledWithFloor(prebidExt.Floors) && floors.ShouldEnforceFloors(r.BidRequestWrapper.BidRequest, prebidExt.Floors, floor.GetEnforceRate(), rand.Intn) {
var enforceDealFloors bool
if prebidExt.Floors.Enforcement != nil {
enforceDealFloors = prebidExt.Floors.Enforcement.FloorDeals && floor.EnforceDealFloor()
if floor != nil && floor.Enabled() && floors.IsRequestEnabledWithFloor(prebidExt.Floors) {
if floors.ShouldEnforceFloors(r.BidRequestWrapper.BidRequest, prebidExt.Floors, floor.GetEnforceRate(), rand.Intn) {
var enforceDealFloors bool
if prebidExt != nil && prebidExt.Floors != nil && prebidExt.Floors.Enforcement != nil && prebidExt.Floors.Enforcement.FloorDeals != nil {
enforceDealFloors = *prebidExt.Floors.Enforcement.FloorDeals && floor.EnforceDealFloor()
}
seatBids, rejections = EnforceFloorToBids(r.BidRequestWrapper.BidRequest, seatBids, conversions, enforceDealFloors)
}
seatBids, rejections = EnforceFloorToBids(r.BidRequestWrapper.BidRequest, seatBids, conversions, enforceDealFloors)
requestExt.SetPrebid(prebidExt)
err := r.BidRequestWrapper.RebuildRequest()
err = r.BidRequestWrapper.RebuildRequest()
if err != nil {
rejections = append(rejections, err.Error())
return seatBids, rejections
Expand Down
16 changes: 8 additions & 8 deletions exchange/floors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func TestEnforceFloorToBids(t *testing.T) {
currency: "USD",
},
},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 0.500000 is less than bidFloor value 1.010000 for impression id some-impression-id-1 bidder appnexus", "bid rejected [bid ID: some-bid-2] reason: bid price value 1.500000 is less than bidFloor value 2.010000 for impression id some-impression-id-2 bidder pubmatic"},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 0.5000 USD is less than bidFloor value 1.0100 USD for impression id some-impression-id-1 bidder appnexus", "bid rejected [bid ID: some-bid-2] reason: bid price value 1.5000 USD is less than bidFloor value 2.0100 USD for impression id some-impression-id-2 bidder pubmatic"},
},
{
name: "Bids with different currency",
Expand Down Expand Up @@ -248,7 +248,7 @@ func TestEnforceFloorToBids(t *testing.T) {
currency: "USD",
},
},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 38.795000 is less than bidFloor value 60.000000 for impression id some-impression-id-1 bidder appnexus"},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 38.7950 INR is less than bidFloor value 60.0000 INR for impression id some-impression-id-1 bidder appnexus"},
},
{
name: "Bids with different currency with enforceDealFloor false",
Expand Down Expand Up @@ -351,7 +351,7 @@ func TestEnforceFloorToBids(t *testing.T) {
currency: "USD",
},
},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 38.795000 is less than bidFloor value 60.000000 for impression id some-impression-id-1 bidder appnexus"},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 38.7950 INR is less than bidFloor value 60.0000 INR for impression id some-impression-id-1 bidder appnexus"},
},
{
name: "Dealid not empty, enforceDealFloors is true",
Expand Down Expand Up @@ -461,7 +461,7 @@ func TestEnforceFloorToBids(t *testing.T) {
currency: "USD",
},
},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 38.795000 is less than bidFloor value 60.000000 for impression id some-impression-id-1 bidder appnexus"},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 38.7950 INR is less than bidFloor value 60.0000 INR for impression id some-impression-id-1 bidder appnexus"},
},
{
name: "Dealid not empty, enforceDealFloors is false",
Expand Down Expand Up @@ -673,7 +673,7 @@ func TestEnforceFloorToBids(t *testing.T) {
currency: "USD",
},
},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 0.500000 is less than bidFloor value 1.010000 for impression id some-impression-id-1 bidder appnexus", "bid rejected [bid ID: some-bid-2] reason: bid price value 1.500000 is less than bidFloor value 2.010000 for impression id some-impression-id-2 bidder pubmatic"},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 0.5000 USD is less than bidFloor value 1.0100 USD for impression id some-impression-id-1 bidder appnexus", "bid rejected [bid ID: some-bid-2] reason: bid price value 1.5000 USD is less than bidFloor value 2.0100 USD for impression id some-impression-id-2 bidder pubmatic"},
},
{
name: "Impression map does not have imp id",
Expand Down Expand Up @@ -774,7 +774,7 @@ func TestEnforceFloorToBids(t *testing.T) {
currency: "USD",
},
},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 0.500000 is less than bidFloor value 1.010000 for impression id some-impression-id-1 bidder appnexus", "bid rejected [bid ID: some-bid-2] reason: bid price value 1.500000 is less than bidFloor value 2.010000 for impression id some-impression-id-2 bidder pubmatic"},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 0.5000 USD is less than bidFloor value 1.0100 USD for impression id some-impression-id-1 bidder appnexus", "bid rejected [bid ID: some-bid-2] reason: bid price value 1.5000 USD is less than bidFloor value 2.0100 USD for impression id some-impression-id-2 bidder pubmatic"},
},
}
for _, tt := range tests {
Expand Down Expand Up @@ -857,7 +857,7 @@ func TestEnforceFloorToBidsConversion(t *testing.T) {
currency: "EUR",
},
},
want1: nil,
want1: []string{"Error in rate conversion from = EUR to USD with bidder pubmatic for impression id some-impression-id-1 and bid id some-bid-1", "Error in rate conversion from = EUR to USD with bidder pubmatic for impression id some-impression-id-2 and bid id some-bid-2"},
},
}

Expand Down Expand Up @@ -988,7 +988,7 @@ func TestEnforceFloors(t *testing.T) {
currency: "USD",
},
},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 0.500000 is less than bidFloor value 20.010000 for impression id some-impression-id-1 bidder appnexus", "bid rejected [bid ID: some-bid-1] reason: bid price value 1.200000 is less than bidFloor value 20.010000 for impression id some-impression-id-1 bidder pubmatic"},
want1: []string{"bid rejected [bid ID: some-bid-11] reason: bid price value 0.5000 USD is less than bidFloor value 20.0100 USD for impression id some-impression-id-1 bidder appnexus", "bid rejected [bid ID: some-bid-1] reason: bid price value 1.2000 USD is less than bidFloor value 20.0100 USD for impression id some-impression-id-1 bidder pubmatic"},
},
}
for _, tt := range tests {
Expand Down
14 changes: 11 additions & 3 deletions floors/enforce.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@ func ShouldEnforceFloors(bidRequest *openrtb2.BidRequest, floorExt *openrtb_ext.
}
}

if floorExt.Enforcement != nil && floorExt.Enforcement.EnforcePBS != nil && !*floorExt.Enforcement.EnforcePBS {
if floorExt != nil && floorExt.Enforcement != nil && floorExt.Enforcement.EnforcePBS != nil && !*floorExt.Enforcement.EnforcePBS {
return *floorExt.Enforcement.EnforcePBS
}

if floorExt.Enforcement != nil && floorExt.Enforcement.EnforceRate > 0 {
if floorExt != nil && floorExt.Enforcement != nil && floorExt.Enforcement.EnforceRate > 0 {
configEnforceRate = floorExt.Enforcement.EnforceRate
}

shouldEnforce := configEnforceRate > f(ENFORCE_RATE_MAX+1)
if floorExt == nil {
floorExt = new(openrtb_ext.PriceFloorRules)
}

if floorExt.Enforcement == nil {
floorExt.Enforcement = new(openrtb_ext.PriceFloorEnforcement)
}
floorExt.Enforcement.EnforcePBS = &shouldEnforce

if floorExt.Enforcement.EnforcePBS == nil {
floorExt.Enforcement.EnforcePBS = new(bool)
}
*floorExt.Enforcement.EnforcePBS = shouldEnforce
return shouldEnforce
}
33 changes: 19 additions & 14 deletions floors/floors.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,8 @@ type Floor interface {

// IsRequestEnabledWithFloor will check if floors is enabled in request
func IsRequestEnabledWithFloor(Floors *openrtb_ext.PriceFloorRules) bool {
if Floors == nil {
return false
}

if Floors.Enabled != nil && !*Floors.Enabled {
if Floors != nil && Floors.Enabled != nil && !*Floors.Enabled {
return *Floors.Enabled
}

Expand All @@ -79,6 +76,14 @@ func UpdateImpsWithFloors(floorExt *openrtb_ext.PriceFloorRules, request *openrt
floorVal float64
)
floorData := floorExt.Data
if floorData == nil {
return floorModelErrList
}

floorModelErrList = validateFloorSkipRates(floorExt)
if len(floorModelErrList) > 0 {
return floorModelErrList
}

floorData.ModelGroups, floorModelErrList = validateFloorModelGroups(floorData.ModelGroups)
if len(floorData.ModelGroups) == 0 {
Expand Down Expand Up @@ -109,19 +114,19 @@ func UpdateImpsWithFloors(floorExt *openrtb_ext.PriceFloorRules, request *openrt
floorVal = floorData.ModelGroups[0].Values[matchedRule]
}

if floorVal > 0.0 {
request.Imp[i].BidFloor = math.Round(floorVal*10000) / 10000
floorMinVal, floorCur, err := getMinFloorValue(floorExt, conversions)
if err == nil {
if floorMinVal > 0.0 && floorVal < floorMinVal {
request.Imp[i].BidFloor = math.Round(floorMinVal*10000) / 10000
}
request.Imp[i].BidFloorCur = floorCur
updateImpExtWithFloorDetails(matchedRule, &request.Imp[i], floorVal)
floorMinVal, floorCur, err := getMinFloorValue(floorExt, conversions)
if err == nil {
if floorMinVal > 0.0 && floorVal < floorMinVal {
request.Imp[i].BidFloor = math.Round(floorMinVal*10000) / 10000
} else {
floorModelErrList = append(floorModelErrList, fmt.Errorf("error in Currency Conversion = '%v'", err.Error()))
request.Imp[i].BidFloor = math.Round(floorVal*10000) / 10000
}
request.Imp[i].BidFloorCur = floorCur
updateImpExtWithFloorDetails(matchedRule, &request.Imp[i], floorVal)
} else {
floorModelErrList = append(floorModelErrList, fmt.Errorf("Error in getting FloorMin value : '%v'", err.Error()))
}

}
}
floorModelErrList = append(floorModelErrList, floorErrList...)
Expand Down
4 changes: 2 additions & 2 deletions floors/floors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestIsRequestEnabledWithFloor(t *testing.T) {
{
name: "Request With Nil Floors",
in: &openrtb_ext.ExtRequest{},
out: false,
out: true,
},
{
name: "Request With Floors Disabled",
Expand Down Expand Up @@ -563,7 +563,7 @@ func TestUpdateImpsWithInvalidModelGroups(t *testing.T) {
floorExt: floorExt,
floorVal: 0.0,
floorCur: "",
Err: "invalid Floor Model = 'Version 1' due to SkipRate = '110'",
Err: "Invalid Floor Model = 'Version 1' due to SkipRate = '110'",
},
}
for _, tc := range tt {
Expand Down
19 changes: 17 additions & 2 deletions floors/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,32 @@ func validateFloorRules(Schema openrtb_ext.PriceFloorSchema, delimiter string, R
return errs
}

func validateFloorSkipRates(floorExt *openrtb_ext.PriceFloorRules) []error {
var errs []error

if floorExt.Data != nil && (floorExt.Data.SkipRate < SKIP_RATE_MIN || floorExt.Data.SkipRate > SKIP_RATE_MAX) {
errs = append(errs, fmt.Errorf("Invalid SkipRate at data level = '%v'", floorExt.Data.SkipRate))
return errs
}

if floorExt.SkipRate < SKIP_RATE_MIN || floorExt.SkipRate > SKIP_RATE_MAX {
errs = append(errs, fmt.Errorf("Invalid SkipRate at root level = '%v'", floorExt.SkipRate))
}

return errs
}

func validateFloorModelGroups(modelGroups []openrtb_ext.PriceFloorModelGroup) ([]openrtb_ext.PriceFloorModelGroup, []error) {
var errs []error
var validModelGroups []openrtb_ext.PriceFloorModelGroup
for _, modelGroup := range modelGroups {
if modelGroup.SkipRate < SKIP_RATE_MIN || modelGroup.SkipRate > SKIP_RATE_MAX {
errs = append(errs, fmt.Errorf("invalid Floor Model = '%v' due to SkipRate = '%v'", modelGroup.ModelVersion, modelGroup.SkipRate))
errs = append(errs, fmt.Errorf("Invalid Floor Model = '%v' due to SkipRate = '%v'", modelGroup.ModelVersion, modelGroup.SkipRate))
continue
}

if modelGroup.ModelWeight < MODEL_WEIGHT_MIN_VALUE || modelGroup.ModelWeight > MODEL_WEIGHT_MAX_VALUE {
errs = append(errs, fmt.Errorf("invalid Floor Model = '%v' due to ModelWeight = '%v'", modelGroup.ModelVersion, modelGroup.ModelWeight))
errs = append(errs, fmt.Errorf("Invalid Floor Model = '%v' due to ModelWeight = '%v'", modelGroup.ModelVersion, modelGroup.ModelWeight))
continue
}

Expand Down
62 changes: 60 additions & 2 deletions floors/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,64 @@ import (
"github.com/prebid/prebid-server/openrtb_ext"
)

func TestValidateFloorSkipRates(t *testing.T) {
floorExt1 := &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
ModelVersion: "Version 1",
Schema: openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}, Delimiter: "|"},
Values: map[string]float64{
"banner|300x250|www.website.com": 1.01,
"banner|300x250|*": 2.01,
"banner|300x600|www.website.com|www.test.com": 3.01,
"banner|300x600|*": 4.01,
}, Default: 0.01},
}}}
floorExt2 := &openrtb_ext.PriceFloorRules{SkipRate: -10}

floorExt3 := &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
SkipRate: -10,
ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
ModelVersion: "Version 1",
Schema: openrtb_ext.PriceFloorSchema{Fields: []string{"mediaType", "size", "domain"}},
Values: map[string]float64{
"*|*|www.website.com": 15.01,
"*|*|*": 16.01,
}, Default: 0.01},
}}}

tt := []struct {
name string
floorExt *openrtb_ext.PriceFloorRules
Err string
}{
{
name: "Valid Skip Rate",
floorExt: floorExt1,
Err: "",
},
{
name: "Invalid Skip Rate at Root level",
floorExt: floorExt2,
Err: "Invalid SkipRate at root level = '-10'",
},
{
name: "Invalid Skip Rate at Date level",
floorExt: floorExt3,
Err: "Invalid SkipRate at data level = '-10'",
},
}
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
ErrList := validateFloorSkipRates(tc.floorExt)

if len(ErrList) > 0 && !reflect.DeepEqual(ErrList[0].Error(), tc.Err) {
t.Errorf("Incorrect Error: \nreturn:\t%v\nwant:\t%v", ErrList[0].Error(), tc.Err)
}

})
}
}

func TestValidateFloorModelGroups(t *testing.T) {
floorExt := &openrtb_ext.PriceFloorRules{Data: &openrtb_ext.PriceFloorData{
ModelGroups: []openrtb_ext.PriceFloorModelGroup{{
Expand Down Expand Up @@ -116,13 +174,13 @@ func TestValidateFloorModelGroups(t *testing.T) {
name: "Invalid Skip Rate in model Group 1, with banner|300x250|www.website.com",
floorExt: floorExt,
ModelVersion: "Version 1",
Err: "invalid Floor Model = 'Version 1' due to SkipRate = '110'",
Err: "Invalid Floor Model = 'Version 1' due to SkipRate = '110'",
},
{
name: "Invalid model weight Model Group 1, with banner|300x250|www.website.com",
floorExt: floorExt2,
ModelVersion: "Version 1",
Err: "invalid Floor Model = 'Version 1' due to ModelWeight = '-1'",
Err: "Invalid Floor Model = 'Version 1' due to ModelWeight = '-1'",
},
}
for _, tc := range tt {
Expand Down
2 changes: 1 addition & 1 deletion openrtb_ext/floors.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type PriceFloorData struct {

type PriceFloorEnforcement struct {
EnforcePBS *bool `json:"enforcepbs,omitempty"`
FloorDeals bool `json:"floordeals,omitempty"`
FloorDeals *bool `json:"floordeals,omitempty"`
BidAdjustment bool `json:"bidadjustment,omitempty"`
EnforceRate int `json:"enforcerate,omitempty"`
}
Expand Down

0 comments on commit 6ea3250

Please sign in to comment.