Skip to content

Commit

Permalink
Merge pull request #309 from PubMatic-OpenWrap/feature-2174-add-extra…
Browse files Browse the repository at this point in the history
…-bid-1-validation-1

Validate extra-bidder prebid#2257 prebid#2174
  • Loading branch information
pm-nilesh-chate authored Jun 2, 2022
2 parents e2425bc + 8489145 commit 597792d
Show file tree
Hide file tree
Showing 8 changed files with 376 additions and 44 deletions.
62 changes: 51 additions & 11 deletions config/accounts.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package config

import (
"fmt"

"github.com/prebid/go-gdpr/consentconstants"
"github.com/prebid/prebid-server/openrtb_ext"
)
Expand All @@ -18,17 +20,18 @@ const (

// Account represents a publisher account configuration
type Account struct {
ID string `mapstructure:"id" json:"id"`
Disabled bool `mapstructure:"disabled" json:"disabled"`
CacheTTL DefaultTTLs `mapstructure:"cache_ttl" json:"cache_ttl"`
EventsEnabled bool `mapstructure:"events_enabled" json:"events_enabled"`
CCPA AccountCCPA `mapstructure:"ccpa" json:"ccpa"`
GDPR AccountGDPR `mapstructure:"gdpr" json:"gdpr"`
DebugAllow bool `mapstructure:"debug_allow" json:"debug_allow"`
DefaultIntegration string `mapstructure:"default_integration" json:"default_integration"`
CookieSync CookieSync `mapstructure:"cookie_sync" json:"cookie_sync"`
Events Events `mapstructure:"events" json:"events"` // Don't enable this feature. It is still under developmment - https://github.com/prebid/prebid-server/issues/1725
TruncateTargetAttribute *int `mapstructure:"truncate_target_attr" json:"truncate_target_attr"`
ID string `mapstructure:"id" json:"id"`
Disabled bool `mapstructure:"disabled" json:"disabled"`
CacheTTL DefaultTTLs `mapstructure:"cache_ttl" json:"cache_ttl"`
EventsEnabled bool `mapstructure:"events_enabled" json:"events_enabled"`
CCPA AccountCCPA `mapstructure:"ccpa" json:"ccpa"`
GDPR AccountGDPR `mapstructure:"gdpr" json:"gdpr"`
DebugAllow bool `mapstructure:"debug_allow" json:"debug_allow"`
DefaultIntegration string `mapstructure:"default_integration" json:"default_integration"`
CookieSync CookieSync `mapstructure:"cookie_sync" json:"cookie_sync"`
Events Events `mapstructure:"events" json:"events"` // Don't enable this feature. It is still under developmment - https://github.com/prebid/prebid-server/issues/1725
TruncateTargetAttribute *int `mapstructure:"truncate_target_attr" json:"truncate_target_attr"`
AlternateBidderCodes AlternateBidderCodes `mapstructure:"alternatebiddercodes" json:"alternatebiddercodes"`
}

// CookieSync represents the account-level defaults for the cookie sync endpoint.
Expand Down Expand Up @@ -222,3 +225,40 @@ func (a *AccountIntegration) GetByIntegrationType(integrationType IntegrationTyp

return integrationEnabled
}

type AlternateBidderCodes struct {
Enabled bool `mapstructure:"enabled" json:"enabled"`
Adapters map[openrtb_ext.BidderName]AdapterAlternateBidderCodes `mapstructure:"adapters" json:"adapters"`
}

type AdapterAlternateBidderCodes struct {
Enabled bool `mapstructure:"enabled" json:"enabled"`
AllowedBidderCodes []openrtb_ext.BidderName `mapstructure:"allowedbiddercodes" json:"allowedbiddercodes"`
}

func (account *AlternateBidderCodes) IsValidBidderCode(bidder, alternateBidder openrtb_ext.BidderName) (bool, error) {
if alternateBidder == "" || bidder == alternateBidder {
return true, nil
}

if account.Adapters == nil {
return account.Enabled, nil
}

adapterCfg, ok := account.Adapters[bidder]
if !((ok && adapterCfg.Enabled) || (!ok && account.Enabled)) {
return false, nil
}

if len(adapterCfg.AllowedBidderCodes) == 0 || adapterCfg.AllowedBidderCodes[0] == "*" {
return true, nil
}

for _, code := range adapterCfg.AllowedBidderCodes {
if alternateBidder == code {
return true, nil
}
}

return false, fmt.Errorf("invalid biddercode %s sent by adapter %s", alternateBidder, bidder)
}
178 changes: 178 additions & 0 deletions config/accounts_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"errors"
"testing"

"github.com/prebid/go-gdpr/consentconstants"
Expand Down Expand Up @@ -707,3 +708,180 @@ func TestBasicEnforcementVendor(t *testing.T) {
assert.Equal(t, tt.wantBasicVendorSet, present, tt.description)
}
}

func TestAlternateBidderCodes_IsValidBidderCode(t *testing.T) {
type fields struct {
Enabled bool
Adapters map[openrtb_ext.BidderName]AdapterAlternateBidderCodes
}
type args struct {
bidder openrtb_ext.BidderName
alternateBidder openrtb_ext.BidderName
}
tests := []struct {
name string
fields fields
args args
wantIsValid bool
wantErr error
}{
{
name: "Default alternateBidder is not set/blank",
wantIsValid: true,
},
{
name: "alternateBidder, bidder are same",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: openrtb_ext.BidderPubmatic,
},
wantIsValid: true,
},
{
name: "adapter config is not nil",
wantIsValid: true,
},
{
name: "alternateBidder disabled at account level",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
wantIsValid: false,
},
{
name: "alternateBidder disabled at account level, adapter config is not available",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
wantIsValid: false,
},
{
name: "alternateBidder disabled at account level, adapter config present, has alternateBidder disabled",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
fields: fields{
Enabled: false,
Adapters: map[openrtb_ext.BidderName]AdapterAlternateBidderCodes{
openrtb_ext.BidderPubmatic: {Enabled: false},
},
},
wantIsValid: false,
},
{
name: "alternateBidder disabled at account level, adapter config present, has alternateBidder enabled",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
fields: fields{
Enabled: true,
Adapters: map[openrtb_ext.BidderName]AdapterAlternateBidderCodes{
openrtb_ext.BidderPubmatic: {Enabled: true},
},
},
wantIsValid: true,
},
{
// This case also asserts len(allowedBidderCodes)=0
name: "alternateBidder enabled at account level, adapter config is not available",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
fields: fields{Enabled: true},
wantIsValid: true,
},
{
name: "alternateBidder enabled at account level, adapter config present, has alternateBidder disabled",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
fields: fields{
Enabled: false,
Adapters: map[openrtb_ext.BidderName]AdapterAlternateBidderCodes{
openrtb_ext.BidderPubmatic: {Enabled: false},
},
},
wantIsValid: false,
},
{
name: "alternateBidder enabled at account level, adapter config present, has alternateBidder enabled",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
fields: fields{
Enabled: true,
Adapters: map[openrtb_ext.BidderName]AdapterAlternateBidderCodes{
openrtb_ext.BidderPubmatic: {Enabled: true},
},
},
wantIsValid: true,
},
{
name: "allowedBidderCodes is *",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
fields: fields{
Adapters: map[openrtb_ext.BidderName]AdapterAlternateBidderCodes{
openrtb_ext.BidderPubmatic: {
Enabled: true,
AllowedBidderCodes: []openrtb_ext.BidderName{"*"},
},
},
},
wantIsValid: true,
},
{
name: "allowedBidderCodes is in the list",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
fields: fields{
Adapters: map[openrtb_ext.BidderName]AdapterAlternateBidderCodes{
openrtb_ext.BidderPubmatic: {
Enabled: true,
AllowedBidderCodes: []openrtb_ext.BidderName{"groupm"},
},
},
},
wantIsValid: true,
},
{
name: "allowedBidderCodes is not in the list",
args: args{
bidder: openrtb_ext.BidderPubmatic,
alternateBidder: "groupm",
},
fields: fields{
Adapters: map[openrtb_ext.BidderName]AdapterAlternateBidderCodes{
openrtb_ext.BidderPubmatic: {
Enabled: true,
AllowedBidderCodes: []openrtb_ext.BidderName{"xyz"},
},
},
},
wantIsValid: false,
wantErr: errors.New("invalid biddercode groupm sent by adapter pubmatic"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &AlternateBidderCodes{
Enabled: tt.fields.Enabled,
Adapters: tt.fields.Adapters,
}
gotIsValid, gotErr := a.IsValidBidderCode(tt.args.bidder, tt.args.alternateBidder)
assert.Equal(t, tt.wantIsValid, gotIsValid)
assert.Equal(t, tt.wantErr, gotErr)
})
}
}
32 changes: 20 additions & 12 deletions exchange/bidder.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type AdaptedBidder interface {
//
// Any errors will be user-facing in the API.
// Error messages should help publishers understand what might account for "bad" bids.
requestBid(ctx context.Context, bidderRequest BidderRequest, bidAdjustment float64, conversions currency.Conversions, reqInfo *adapters.ExtraRequestInfo, accountDebugAllowed, headerDebugAllowed bool) ([]*pbsOrtbSeatBid, []error)
requestBid(ctx context.Context, bidderRequest BidderRequest, bidAdjustment float64, conversions currency.Conversions, reqInfo *adapters.ExtraRequestInfo, accountDebugAllowed, headerDebugAllowed bool, alternateBidderCodes config.AlternateBidderCodes) ([]*pbsOrtbSeatBid, []error)
}

const ImpIdReqBody = "Stored bid response for impression id: "
Expand Down Expand Up @@ -136,7 +136,7 @@ type bidderAdapterConfig struct {
DebugInfo config.DebugInfo
}

func (bidder *bidderAdapter) requestBid(ctx context.Context, bidderRequest BidderRequest, bidAdjustment float64, conversions currency.Conversions, reqInfo *adapters.ExtraRequestInfo, accountDebugAllowed, headerDebugAllowed bool) ([]*pbsOrtbSeatBid, []error) {
func (bidder *bidderAdapter) requestBid(ctx context.Context, bidderRequest BidderRequest, bidAdjustment float64, conversions currency.Conversions, reqInfo *adapters.ExtraRequestInfo, accountDebugAllowed, headerDebugAllowed bool, alternateBidderCodes config.AlternateBidderCodes) ([]*pbsOrtbSeatBid, []error) {

var reqData []*adapters.RequestData
var errs []error
Expand Down Expand Up @@ -302,19 +302,27 @@ func (bidder *bidderAdapter) requestBid(ctx context.Context, bidderRequest Bidde
bidderName := bidderRequest.BidderName
if bidResponse.Bids[i].Seat != "" {
bidderName = bidResponse.Bids[i].Seat
}

if _, ok := seatBidMap[bidderName]; !ok {
// Initalize seatBidMap entry as this is first extra bid with seat bidderName
// seatBidMap[bidderName] =
seatBidMap[bidderName] = &pbsOrtbSeatBid{
bids: make([]*pbsOrtbBid, 0, dataLen),
currency: defaultCurrency,
// Do we need to fill httpCalls for this?. Can we refer one from adaptercode for debugging?
httpCalls: seatBidMap[bidderRequest.BidderName].httpCalls,
seat: bidderName.String(),
}
if valid, err := alternateBidderCodes.IsValidBidderCode(bidderRequest.BidderName, bidderName); !valid {
if err != nil {
errs = append(errs, err)
}
continue
}

if _, ok := seatBidMap[bidderName]; !ok {
// Initalize seatBidMap entry as this is first extra bid with seat bidderName
// seatBidMap[bidderName] =
seatBidMap[bidderName] = &pbsOrtbSeatBid{
bids: make([]*pbsOrtbBid, 0, dataLen),
currency: defaultCurrency,
// Do we need to fill httpCalls for this?. Can we refer one from adaptercode for debugging?
httpCalls: seatBidMap[bidderRequest.BidderName].httpCalls,
seat: bidderName.String(),
}
}

seatBidMap[bidderName].bids = append(seatBidMap[bidderName].bids, &pbsOrtbBid{
bid: bidResponse.Bids[i].Bid,
bidMeta: bidResponse.Bids[i].BidMeta,
Expand Down
Loading

0 comments on commit 597792d

Please sign in to comment.