Skip to content
This repository has been archived by the owner on Dec 22, 2022. It is now read-only.

Commit

Permalink
Video endpoint bid selection enhancements (prebid#1419)
Browse files Browse the repository at this point in the history
Co-authored-by: Veronika Solovei <veronika.solovei@xandr.com>
  • Loading branch information
VeronikaSolovei9 and Veronika Solovei authored Aug 12, 2020
1 parent 5c8dcc4 commit f56f419
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 17 deletions.
18 changes: 13 additions & 5 deletions endpoints/openrtb2/video_auction.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ func buildVideoResponse(bidresponse *openrtb.BidResponse, podErrors []PodError)
if err := json.Unmarshal(bid.Ext, &tempRespBidExt); err != nil {
return nil, err
}
if tempRespBidExt.Prebid.Targeting[string(openrtb_ext.HbVastCacheKey)] == "" {
if tempRespBidExt.Prebid.Targeting[formatTargetingKey(openrtb_ext.HbVastCacheKey, seatBid.Seat)] == "" {
continue
}

Expand All @@ -479,9 +479,9 @@ func buildVideoResponse(bidresponse *openrtb.BidResponse, podErrors []PodError)
podId, _ := strconv.ParseInt(podNum, 0, 64)

videoTargeting := openrtb_ext.VideoTargeting{
HbPb: tempRespBidExt.Prebid.Targeting[string(openrtb_ext.HbpbConstantKey)],
HbPbCatDur: tempRespBidExt.Prebid.Targeting[string(openrtb_ext.HbCategoryDurationKey)],
HbCacheID: tempRespBidExt.Prebid.Targeting[string(openrtb_ext.HbVastCacheKey)],
HbPb: tempRespBidExt.Prebid.Targeting[formatTargetingKey(openrtb_ext.HbpbConstantKey, seatBid.Seat)],
HbPbCatDur: tempRespBidExt.Prebid.Targeting[formatTargetingKey(openrtb_ext.HbCategoryDurationKey, seatBid.Seat)],
HbCacheID: tempRespBidExt.Prebid.Targeting[formatTargetingKey(openrtb_ext.HbVastCacheKey, seatBid.Seat)],
}

adPod := findAdPod(podId, adPods)
Expand Down Expand Up @@ -519,6 +519,14 @@ func buildVideoResponse(bidresponse *openrtb.BidResponse, podErrors []PodError)
return &openrtb_ext.BidResponseVideo{AdPods: adPods}, nil
}

func formatTargetingKey(key openrtb_ext.TargetingKey, bidderName string) string {
fullKey := fmt.Sprintf("%s_%s", string(key), bidderName)
if len(fullKey) > exchange.MaxKeyLength {
return string(fullKey[0:exchange.MaxKeyLength])
}
return fullKey
}

func findAdPod(podInd int64, pods []*openrtb_ext.AdPod) *openrtb_ext.AdPod {
for _, pod := range pods {
if pod.PodId == podInd {
Expand Down Expand Up @@ -623,9 +631,9 @@ func createBidExtension(videoRequest *openrtb_ext.BidRequestVideo) ([]byte, erro

targeting := openrtb_ext.ExtRequestTargeting{
PriceGranularity: priceGranularity,
IncludeWinners: true,
IncludeBrandCategory: inclBrandCat,
DurationRangeSec: durationRangeSec,
IncludeBidderKeys: true,
}

vastXml := openrtb_ext.ExtRequestPrebidCacheVAST{}
Expand Down
29 changes: 23 additions & 6 deletions endpoints/openrtb2/video_auction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ func TestVideoEndpointImpressionsDuration(t *testing.T) {
t.Fatalf("The request never made it into the Exchange.")
}

var extData openrtb_ext.ExtRequest
json.Unmarshal(ex.lastRequest.Ext, &extData)
assert.True(t, extData.Prebid.Targeting.IncludeBidderKeys, "Request ext incorrect: IncludeBidderKeys should be true ")

assert.Len(t, ex.lastRequest.Imp, 22, "Incorrect number of impressions in request")
assert.Equal(t, ex.lastRequest.Imp[0].ID, "1_0", "Incorrect impression id in request")
assert.Equal(t, ex.lastRequest.Imp[0].Video.MaxDuration, int64(15), "Incorrect impression max duration in request")
Expand Down Expand Up @@ -643,9 +647,9 @@ func TestVideoBuildVideoResponseMissedCacheForOneBid(t *testing.T) {
bid2 := openrtb.Bid{}
bid3 := openrtb.Bid{}

extBid1 := []byte(`{"prebid":{"targeting":{"hb_bidder":"appnexus","hb_pb":"17.00","hb_pb_cat_dur":"17.00_123_30s","hb_size":"1x1","hb_uuid":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"}}}`)
extBid2 := []byte(`{"prebid":{"targeting":{"hb_bidder":"appnexus","hb_pb":"17.00","hb_pb_cat_dur":"17.00_456_30s","hb_size":"1x1","hb_uuid":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"}}}`)
extBid3 := []byte(`{"prebid":{"targeting":{"hb_bidder":"appnexus","hb_pb":"17.00","hb_pb_cat_dur":"17.00_406_30s","hb_size":"1x1"}}}`)
extBid1 := []byte(`{"prebid":{"targeting":{"hb_bidder_appnexus":"appnexus","hb_pb_appnexus":"17.00","hb_pb_cat_dur_appnex":"17.00_123_30s","hb_size":"1x1","hb_uuid_appnexus":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"}}}`)
extBid2 := []byte(`{"prebid":{"targeting":{"hb_bidder_appnexus":"appnexus","hb_pb_appnexus":"17.00","hb_pb_cat_dur_appnex":"17.00_456_30s","hb_size":"1x1","hb_uuid_appnexus":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"}}}`)
extBid3 := []byte(`{"prebid":{"targeting":{"hb_bidder_appnexus":"appnexus","hb_pb_appnexus":"17.00","hb_pb_cat_dur_appnex":"17.00_406_30s","hb_size":"1x1"}}}`)

bid1.Ext = extBid1
bids = append(bids, bid1)
Expand All @@ -657,6 +661,7 @@ func TestVideoBuildVideoResponseMissedCacheForOneBid(t *testing.T) {
bids = append(bids, bid3)

seatBid.Bid = bids
seatBid.Seat = "appnexus"
seatBids = append(seatBids, seatBid)
openRtbBidResp.SeatBid = seatBids

Expand Down Expand Up @@ -713,8 +718,8 @@ func TestVideoBuildVideoResponsePodErrors(t *testing.T) {
bid1 := openrtb.Bid{}
bid2 := openrtb.Bid{}

extBid1 := []byte(`{"prebid":{"targeting":{"hb_bidder":"appnexus","hb_pb":"17.00","hb_pb_cat_dur":"17.00_123_30s","hb_size":"1x1","hb_uuid":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"}}}`)
extBid2 := []byte(`{"prebid":{"targeting":{"hb_bidder":"appnexus","hb_pb":"17.00","hb_pb_cat_dur":"17.00_456_30s","hb_size":"1x1","hb_uuid":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"}}}`)
extBid1 := []byte(`{"prebid":{"targeting":{"hb_bidder_appnexus":"appnexus","hb_pb_appnexus":"17.00","hb_pb_cat_dur_appnex":"17.00_123_30s","hb_size":"1x1","hb_uuid_appnexus":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"}}}`)
extBid2 := []byte(`{"prebid":{"targeting":{"hb_bidder_appnexus":"appnexus","hb_pb_appnexus":"17.00","hb_pb_cat_dur_appnex":"17.00_456_30s","hb_size":"1x1","hb_uuid_appnexus":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"}}}`)

bid1.Ext = extBid1
bids = append(bids, bid1)
Expand All @@ -723,6 +728,7 @@ func TestVideoBuildVideoResponsePodErrors(t *testing.T) {
bids = append(bids, bid2)

seatBid.Bid = bids
seatBid.Seat = "appnexus"
seatBids = append(seatBids, seatBid)
openRtbBidResp.SeatBid = seatBids

Expand Down Expand Up @@ -1107,6 +1113,16 @@ func TestCCPA(t *testing.T) {
}
}

func TestFormatTargetingKey(t *testing.T) {
res := formatTargetingKey(openrtb_ext.HbCategoryDurationKey, "appnexus")
assert.Equal(t, "hb_pb_cat_dur_appnex", res, "Tergeting key constructed incorrectly")
}

func TestFormatTargetingKeyLongKey(t *testing.T) {
res := formatTargetingKey(openrtb_ext.HbpbConstantKey, "20.00")
assert.Equal(t, "hb_pb_20.00", res, "Tergeting key constructed incorrectly")
}

func mockDepsWithMetrics(t *testing.T, ex *mockExchangeVideo) (*endpointDeps, *pbsmetrics.Metrics, *mockAnalyticsModule) {
theMetrics := pbsmetrics.NewMetrics(metrics.NewRegistry(), openrtb_ext.BidderList(), config.DisabledMetrics{})
mockModule := &mockAnalyticsModule{}
Expand Down Expand Up @@ -1205,9 +1221,10 @@ func (m *mockExchangeVideo) HoldAuction(ctx context.Context, bidRequest *openrtb
if debugLog != nil && debugLog.Enabled {
m.cache.called = true
}
ext := []byte(`{"prebid":{"targeting":{"hb_bidder":"appnexus","hb_pb":"20.00","hb_pb_cat_dur":"20.00_395_30s","hb_size":"1x1", "hb_uuid":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"},"type":"video"},"bidder":{"appnexus":{"brand_id":1,"auction_id":7840037870526938650,"bidder_id":2,"bid_ad_type":1,"creative_info":{"video":{"duration":30,"mimes":["video\/mp4"]}}}}}`)
ext := []byte(`{"prebid":{"targeting":{"hb_bidder_appnexus":"appnexus","hb_pb_appnexus":"20.00","hb_pb_cat_dur_appnex":"20.00_395_30s","hb_size":"1x1", "hb_uuid_appnexus":"837ea3b7-5598-4958-8c45-8e9ef2bf7cc1"},"type":"video"},"bidder":{"appnexus":{"brand_id":1,"auction_id":7840037870526938650,"bidder_id":2,"bid_ad_type":1,"creative_info":{"video":{"duration":30,"mimes":["video\/mp4"]}}}}}`)
return &openrtb.BidResponse{
SeatBid: []openrtb.SeatBid{{
Seat: "appnexus",
Bid: []openrtb.Bid{
{ID: "01", ImpID: "1_0", Ext: ext},
{ID: "02", ImpID: "1_1", Ext: ext},
Expand Down
2 changes: 1 addition & 1 deletion exchange/auction.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func (a *auction) doCache(ctx context.Context, cache prebid_cache_client.Client,
var customCacheKey string
var catDur string
useCustomCacheKey := false
if competitiveExclusion && isOverallWinner {
if competitiveExclusion && isOverallWinner || includeBidderKeys {
// set custom cache key for winning bid when competitive exclusion applies
catDur = bidCategory[topBidPerBidder.bid.ID]
if len(catDur) > 0 {
Expand Down
101 changes: 101 additions & 0 deletions exchange/impcustomcachekeytest/multiImpVideo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
{
"bidRequest": {
"imp": [{
"id": "1_0"
},
{
"id": "1_1"
}
]
},
"pbsBids": [{
"bid": {
"id": "apn_1_0",
"impid": "1_0",
"price": 12.00,
"nurl": "http://apn_1_0.com",
"cat": ["12.00_sports_30s"]
},
"bidType": "video",
"bidder": "appnexus"
}, {
"bid": {
"id": "spotx_1_0",
"impid": "1_0",
"price": 20.00,
"nurl": "http://spotx_1_0.com",
"cat": ["20_news_30s"]
},
"bidType": "video",
"bidder": "spotx"
}, {
"bid": {
"id": "apn_1_1",
"impid": "1_1",
"price": 18.00,
"nurl": "http://apn_1_1.com",
"cat": ["18_furniture_30s"]
},
"bidType": "video",
"bidder": "appnexus"
}, {
"bid": {
"id": "spotx_1_1",
"impid": "1_1",
"price": 17.00,
"nurl": "http://spotx_1_1.com",
"cat": ["17_auto_30s"]
},
"bidType": "video",
"bidder": "spotx"
}, {
"bid": {
"id": "rubicon_1_1",
"impid": "1_1",
"price": 17.50,
"nurl": "http://rubicon_1_1.com",
"cat": ["17_music_30s"]
},
"bidType": "video",
"bidder": "rubicon"
}],
"expectedCacheables": [{
"Type": "xml",
"TTLSeconds": 3660,
"Data": "\u003cVAST version=\"3.0\"\u003e\u003cAd\u003e\u003cWrapper\u003e\u003cAdSystem\u003eprebid.org wrapper\u003c/AdSystem\u003e\u003cVASTAdTagURI\u003e\u003c![CDATA[http://apn_1_0.com]]\u003e\u003c/VASTAdTagURI\u003e\u003cImpression\u003e\u003c/Impression\u003e\u003cCreatives\u003e\u003c/Creatives\u003e\u003c/Wrapper\u003e\u003c/Ad\u003e\u003c/VAST\u003e",
"Key": "12.00_sports_30s"
}, {
"Type": "xml",
"TTLSeconds": 3660,
"Data": "\u003cVAST version=\"3.0\"\u003e\u003cAd\u003e\u003cWrapper\u003e\u003cAdSystem\u003eprebid.org wrapper\u003c/AdSystem\u003e\u003cVASTAdTagURI\u003e\u003c![CDATA[http://spotx_1_0.com]]\u003e\u003c/VASTAdTagURI\u003e\u003cImpression\u003e\u003c/Impression\u003e\u003cCreatives\u003e\u003c/Creatives\u003e\u003c/Wrapper\u003e\u003c/Ad\u003e\u003c/VAST\u003e",
"Key": "20_news_30s"
}, {
"Type": "xml",
"TTLSeconds": 3660,
"Data": "\u003cVAST version=\"3.0\"\u003e\u003cAd\u003e\u003cWrapper\u003e\u003cAdSystem\u003eprebid.org wrapper\u003c/AdSystem\u003e\u003cVASTAdTagURI\u003e\u003c![CDATA[http://apn_1_1.com]]\u003e\u003c/VASTAdTagURI\u003e\u003cImpression\u003e\u003c/Impression\u003e\u003cCreatives\u003e\u003c/Creatives\u003e\u003c/Wrapper\u003e\u003c/Ad\u003e\u003c/VAST\u003e",
"Key": "18_furniture_30s"
},
{
"Type": "xml",
"TTLSeconds": 3660,
"Data": "\u003cVAST version=\"3.0\"\u003e\u003cAd\u003e\u003cWrapper\u003e\u003cAdSystem\u003eprebid.org wrapper\u003c/AdSystem\u003e\u003cVASTAdTagURI\u003e\u003c![CDATA[http://spotx_1_1.com]]\u003e\u003c/VASTAdTagURI\u003e\u003cImpression\u003e\u003c/Impression\u003e\u003cCreatives\u003e\u003c/Creatives\u003e\u003c/Wrapper\u003e\u003c/Ad\u003e\u003c/VAST\u003e",
"Key": "17_auto_30s"
},
{
"Type": "xml",
"TTLSeconds": 3660,
"Data": "\u003cVAST version=\"3.0\"\u003e\u003cAd\u003e\u003cWrapper\u003e\u003cAdSystem\u003eprebid.org wrapper\u003c/AdSystem\u003e\u003cVASTAdTagURI\u003e\u003c![CDATA[http://rubicon_1_1.com]]\u003e\u003c/VASTAdTagURI\u003e\u003cImpression\u003e\u003c/Impression\u003e\u003cCreatives\u003e\u003c/Creatives\u003e\u003c/Wrapper\u003e\u003c/Ad\u003e\u003c/VAST\u003e",
"Key": "17_music_30s"
}
],
"defaultTTLs": {
"banner": 300,
"video": 3600,
"audio": 1800,
"native": 300
},
"targetDataIncludeWinners": false,
"targetDataIncludeBidderKeys": true,
"targetDataIncludeCacheBids": false,
"targetDataIncludeCacheVast": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"bidRequest": {
"imp": [{
"id": "1_0"
},
{
"id": "1_1"
}
]
},
"pbsBids": [{
"bid": {
"id": "apn_1_0",
"impid": "1_0",
"price": 12.00,
"nurl": "http://apn_1_0.com",
"cat": ["12.00_sports_30s"]
},
"bidType": "video",
"bidder": "appnexus"
}, {
"bid": {
"id": "spotx_1_0",
"impid": "1_0",
"price": 20.00,
"nurl": "http://spotx_1_0.com",
"cat": ["20_news_30s"]
},
"bidType": "video",
"bidder": "spotx"
}, {
"bid": {
"id": "apn_1_1",
"impid": "1_1",
"price": 18.00,
"nurl": "http://apn_1_1.com",
"cat": ["18_furniture_30s"]
},
"bidType": "video",
"bidder": "appnexus"
}, {
"bid": {
"id": "spotx_1_1",
"impid": "1_1",
"price": 17.00,
"nurl": "http://spotx_1_1.com",
"cat": ["17_auto_30s"]
},
"bidType": "video",
"bidder": "spotx"
}, {
"bid": {
"id": "rubicon_1_1",
"impid": "1_1",
"price": 17.50,
"nurl": "http://rubicon_1_1.com",
"cat": ["17_music_30s"]
},
"bidType": "video",
"bidder": "rubicon"
}],
"expectedCacheables": [
{
"Type": "xml",
"TTLSeconds": 3660,
"Data": "\u003cVAST version=\"3.0\"\u003e\u003cAd\u003e\u003cWrapper\u003e\u003cAdSystem\u003eprebid.org wrapper\u003c/AdSystem\u003e\u003cVASTAdTagURI\u003e\u003c![CDATA[http://spotx_1_0.com]]\u003e\u003c/VASTAdTagURI\u003e\u003cImpression\u003e\u003c/Impression\u003e\u003cCreatives\u003e\u003c/Creatives\u003e\u003c/Wrapper\u003e\u003c/Ad\u003e\u003c/VAST\u003e",
"Key": "20_news_30s"
},
{
"Type": "xml",
"TTLSeconds": 3660,
"Data": "\u003cVAST version=\"3.0\"\u003e\u003cAd\u003e\u003cWrapper\u003e\u003cAdSystem\u003eprebid.org wrapper\u003c/AdSystem\u003e\u003cVASTAdTagURI\u003e\u003c![CDATA[http://apn_1_1.com]]\u003e\u003c/VASTAdTagURI\u003e\u003cImpression\u003e\u003c/Impression\u003e\u003cCreatives\u003e\u003c/Creatives\u003e\u003c/Wrapper\u003e\u003c/Ad\u003e\u003c/VAST\u003e",
"Key": "18_furniture_30s"
}
],
"defaultTTLs": {
"banner": 300,
"video": 3600,
"audio": 1800,
"native": 300
},
"targetDataIncludeWinners": true,
"targetDataIncludeBidderKeys": false,
"targetDataIncludeCacheBids": false,
"targetDataIncludeCacheVast": true
}
4 changes: 2 additions & 2 deletions exchange/targeting.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/prebid/prebid-server/openrtb_ext"
)

const maxKeyLength = 20
const MaxKeyLength = 20

// targetData tracks information about the winning Bid in each Imp.
//
Expand Down Expand Up @@ -83,7 +83,7 @@ func (targData *targetData) setTargeting(auc *auction, isApp bool, categoryMappi

func (targData *targetData) addKeys(keys map[string]string, key openrtb_ext.TargetingKey, value string, bidderName openrtb_ext.BidderName, overallWinner bool) {
if targData.includeBidderKeys {
keys[key.BidderKey(bidderName, maxKeyLength)] = value
keys[key.BidderKey(bidderName, MaxKeyLength)] = value
}
if targData.includeWinners && overallWinner {
keys[string(key)] = value
Expand Down
6 changes: 3 additions & 3 deletions exchange/targeting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ func TestTargetingCache(t *testing.T) {

// Make sure that the cache keys exist on the bids where they're expected to
assertKeyExists(t, bids["winning-bid"], string(openrtb_ext.HbCacheKey), true)
assertKeyExists(t, bids["winning-bid"], openrtb_ext.HbCacheKey.BidderKey(openrtb_ext.BidderAppnexus, maxKeyLength), true)
assertKeyExists(t, bids["winning-bid"], openrtb_ext.HbCacheKey.BidderKey(openrtb_ext.BidderAppnexus, MaxKeyLength), true)

assertKeyExists(t, bids["contending-bid"], string(openrtb_ext.HbCacheKey), false)
assertKeyExists(t, bids["contending-bid"], openrtb_ext.HbCacheKey.BidderKey(openrtb_ext.BidderRubicon, maxKeyLength), true)
assertKeyExists(t, bids["contending-bid"], openrtb_ext.HbCacheKey.BidderKey(openrtb_ext.BidderRubicon, MaxKeyLength), true)

assertKeyExists(t, bids["losing-bid"], string(openrtb_ext.HbCacheKey), false)
assertKeyExists(t, bids["losing-bid"], openrtb_ext.HbCacheKey.BidderKey(openrtb_ext.BidderAppnexus, maxKeyLength), false)
assertKeyExists(t, bids["losing-bid"], openrtb_ext.HbCacheKey.BidderKey(openrtb_ext.BidderAppnexus, MaxKeyLength), false)

//assert hb_cache_host was included
assert.Contains(t, string(bids["winning-bid"].Ext), string(openrtb_ext.HbConstantCacheHostKey))
Expand Down

0 comments on commit f56f419

Please sign in to comment.