Skip to content

Commit

Permalink
Add bidder name key support (#1496)
Browse files Browse the repository at this point in the history
  • Loading branch information
camrice authored Oct 15, 2020
1 parent c7ddfa6 commit 0a34a01
Show file tree
Hide file tree
Showing 8 changed files with 532 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"description": "Video endpoint valid request with AppendBidderNames.",
"requestPayload": {
"appendbiddernames": true,
"storedrequestid": "80ce30c53c16e6ede735f123ef6e32361bfc7b22",
"podconfig": {
"durationrangesec": [
30
],
"requireexactduration": true,
"pods": [{
"podid": 1,
"adpoddurationsec": 180,
"configid": "fba10607-0c12-43d1-ad07-b8a513bc75d6"
},
{
"podid": 2,
"adpoddurationsec": 150,
"configid": "8b452b41-2681-4a20-9086-6f16ffad7773"
}
]
},
"site": {
"page": "prebid.com"
},
"regs": {
"ext": {
"gdpr": 0
}
},
"user": {
"yob": 1991,
"gender": "F",
"keywords": "Hotels, Travelling",
"ext": {
"prebid": {
"buyeruids": {
"appnexus": "unique_id_an",
"rubicon": "unique_id_rubi"
}
}
}
},
"device": {
"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2",
"ip": "123.145.167.10",
"devicetype": 1,
"ifa": "AA000DFE74168477C70D291f574D344790E0BB11",
"lmt": 44,
"os": "mac os",
"w": 640,
"h": 480,
"didsha1": "didsha1",
"didmd5": "didmd5",
"dpidsha1": "dpidsha1",
"dpidmd5": "dpidmd5",
"macsha1": "macsha1",
"macmd5": "macmd5"
},
"includebrandcategory": {
"primaryadserver": 1,
"publisher": ""
},
"video": {
"w": 640,
"h": 480,
"mimes": [
"video/mp4"
],
"protocols": [
2, 3, 5, 6
]
},
"content": {
"episode": 6,
"title": "episodeName",
"series": "TvName",
"season": "season3",
"len": 900,
"livestream": 0
},
"cacheconfig": {
"ttl": 42
}
}
}
1 change: 1 addition & 0 deletions endpoints/openrtb2/video_auction.go
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ func createBidExtension(videoRequest *openrtb_ext.BidRequestVideo) ([]byte, erro
IncludeBrandCategory: inclBrandCat,
DurationRangeSec: durationRangeSec,
IncludeBidderKeys: true,
AppendBidderNames: videoRequest.AppendBidderNames,
}

vastXml := openrtb_ext.ExtRequestPrebidCacheVAST{}
Expand Down
102 changes: 102 additions & 0 deletions endpoints/openrtb2/video_auction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,48 @@ func TestCCPA(t *testing.T) {
}
}

func TestVideoEndpointAppendBidderNames(t *testing.T) {
ex := &mockExchangeAppendBidderNames{}
reqData, err := ioutil.ReadFile("sample-requests/video/video_valid_sample_appendbiddernames.json")
if err != nil {
t.Fatalf("Failed to fetch a valid request: %v", err)
}
reqBody := string(getRequestPayload(t, reqData))
req := httptest.NewRequest("POST", "/openrtb2/video", strings.NewReader(reqBody))
recorder := httptest.NewRecorder()

deps := mockDepsAppendBidderNames(t, ex)
deps.VideoAuctionEndpoint(recorder, req, nil)

if ex.lastRequest == nil {
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.AppendBidderNames, "Request ext incorrect: AppendBidderNames should be true ")

respBytes := recorder.Body.Bytes()
resp := &openrtb_ext.BidResponseVideo{}
if err := json.Unmarshal(respBytes, resp); err != nil {
t.Fatalf("Unable to unmarshal response.")
}

assert.Len(t, ex.lastRequest.Imp, 11, "Incorrect number of impressions in request")
assert.Equal(t, string(ex.lastRequest.Site.Page), "prebid.com", "Incorrect site page in request")
assert.Equal(t, ex.lastRequest.Site.Content.Series, "TvName", "Incorrect site content series in request")

assert.Len(t, resp.AdPods, 5, "Incorrect number of Ad Pods in response")
assert.Len(t, resp.AdPods[0].Targeting, 4, "Incorrect Targeting data in response")
assert.Len(t, resp.AdPods[1].Targeting, 3, "Incorrect Targeting data in response")
assert.Len(t, resp.AdPods[2].Targeting, 5, "Incorrect Targeting data in response")
assert.Len(t, resp.AdPods[3].Targeting, 1, "Incorrect Targeting data in response")
assert.Len(t, resp.AdPods[4].Targeting, 3, "Incorrect Targeting data in response")

assert.Equal(t, resp.AdPods[4].Targeting[0].HbPbCatDur, "20.00_395_30s_appnexus", "Incorrect number of Ad Pods in response")

}

func TestFormatTargetingKey(t *testing.T) {
res := formatTargetingKey(openrtb_ext.HbCategoryDurationKey, "appnexus")
assert.Equal(t, "hb_pb_cat_dur_appnex", res, "Tergeting key constructed incorrectly")
Expand Down Expand Up @@ -1229,6 +1271,30 @@ func mockDeps(t *testing.T, ex *mockExchangeVideo) *endpointDeps {
return deps
}

func mockDepsAppendBidderNames(t *testing.T, ex *mockExchangeAppendBidderNames) *endpointDeps {
theMetrics := pbsmetrics.NewMetrics(metrics.NewRegistry(), openrtb_ext.BidderList(), config.DisabledMetrics{})
deps := &endpointDeps{
ex,
newParamsValidator(t),
&mockVideoStoredReqFetcher{},
&mockVideoStoredReqFetcher{},
empty_fetcher.EmptyFetcher{},
empty_fetcher.EmptyFetcher{},
&config.Configuration{MaxRequestSize: maxSize},
theMetrics,
analyticsConf.NewPBSAnalytics(&config.Analytics{}),
map[string]string{},
false,
[]byte{},
openrtb_ext.BidderMap,
ex.cache,
regexp.MustCompile(`[<>]`),
hardcodedResponseIPValidator{response: true},
}

return deps
}

func mockDepsNoBids(t *testing.T, ex *mockExchangeVideoNoBids) *endpointDeps {
theMetrics := pbsmetrics.NewMetrics(metrics.NewRegistry(), openrtb_ext.BidderList(), config.DisabledMetrics{})
edep := &endpointDeps{
Expand Down Expand Up @@ -1311,6 +1377,42 @@ func (m *mockExchangeVideo) HoldAuction(ctx context.Context, bidRequest *openrtb
}, nil
}

type mockExchangeAppendBidderNames struct {
lastRequest *openrtb.BidRequest
cache *mockCacheClient
}

func (m *mockExchangeAppendBidderNames) HoldAuction(ctx context.Context, bidRequest *openrtb.BidRequest, ids exchange.IdFetcher, labels pbsmetrics.Labels, account *config.Account, categoriesFetcher *stored_requests.CategoryFetcher, debugLog *exchange.DebugLog) (*openrtb.BidResponse, error) {
m.lastRequest = bidRequest
if debugLog != nil && debugLog.Enabled {
m.cache.called = true
}
ext := []byte(`{"prebid":{"targeting":{"hb_bidder_appnexus":"appnexus","hb_pb_appnexus":"20.00","hb_pb_cat_dur_appnex":"20.00_395_30s_appnexus","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},
{ID: "03", ImpID: "1_2", Ext: ext},
{ID: "04", ImpID: "1_3", Ext: ext},
{ID: "05", ImpID: "2_0", Ext: ext},
{ID: "06", ImpID: "2_1", Ext: ext},
{ID: "07", ImpID: "2_2", Ext: ext},
{ID: "08", ImpID: "3_0", Ext: ext},
{ID: "09", ImpID: "3_1", Ext: ext},
{ID: "10", ImpID: "3_2", Ext: ext},
{ID: "11", ImpID: "3_3", Ext: ext},
{ID: "12", ImpID: "3_5", Ext: ext},
{ID: "13", ImpID: "4_0", Ext: ext},
{ID: "14", ImpID: "5_0", Ext: ext},
{ID: "15", ImpID: "5_1", Ext: ext},
{ID: "16", ImpID: "5_2", Ext: ext},
},
}},
}, nil
}

type mockExchangeVideoNoBids struct {
lastRequest *openrtb.BidRequest
cache *mockCacheClient
Expand Down
5 changes: 5 additions & 0 deletions exchange/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ func applyCategoryMapping(ctx context.Context, requestExt *openrtb_ext.ExtReques

//If ext.prebid.targeting.includebrandcategory is present in ext then competitive exclusion feature is on.
var includeBrandCategory = brandCatExt != nil //if not present - category will no be appended
appendBidderNames := requestExt.Prebid.Targeting.AppendBidderNames

var primaryAdServer string
var publisher string
Expand Down Expand Up @@ -630,6 +631,10 @@ func applyCategoryMapping(ctx context.Context, requestExt *openrtb_ext.ExtReques
dupeKey = categoryDuration
}

if appendBidderNames {
categoryDuration = fmt.Sprintf("%s_%s", categoryDuration, bidderName.String())
}

if dupe, ok := dedupe[dupeKey]; ok {

dupeBidPrice, err := strconv.ParseFloat(dupe.bidPrice, 64)
Expand Down
108 changes: 108 additions & 0 deletions exchange/exchange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1888,6 +1888,114 @@ func TestNoCategoryDedupe(t *testing.T) {

}

func TestCategoryMappingBidderName(t *testing.T) {

categoriesFetcher, error := newCategoryFetcher("./test/category-mapping")
if error != nil {
t.Errorf("Failed to create a category Fetcher: %v", error)
}

requestExt := newExtRequest()
requestExt.Prebid.Targeting.AppendBidderNames = true

targData := &targetData{
priceGranularity: requestExt.Prebid.Targeting.PriceGranularity,
includeWinners: true,
}

requestExt.Prebid.Targeting.DurationRangeSec = []int{15, 30}

adapterBids := make(map[openrtb_ext.BidderName]*pbsOrtbSeatBid)

cats1 := []string{"IAB1-1"}
cats2 := []string{"IAB1-2"}
bid1 := openrtb.Bid{ID: "bid_id1", ImpID: "imp_id1", Price: 10.0000, Cat: cats1, W: 1, H: 1}
bid2 := openrtb.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 10.0000, Cat: cats2, W: 1, H: 1}

bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0}
bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0}

innerBids1 := []*pbsOrtbBid{
&bid1_1,
}
innerBids2 := []*pbsOrtbBid{
&bid1_2,
}

seatBid1 := pbsOrtbSeatBid{innerBids1, "USD", nil, nil}
bidderName1 := openrtb_ext.BidderName("bidder1")

seatBid2 := pbsOrtbSeatBid{innerBids2, "USD", nil, nil}
bidderName2 := openrtb_ext.BidderName("bidder2")

adapterBids[bidderName1] = &seatBid1
adapterBids[bidderName2] = &seatBid2

bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, &requestExt, adapterBids, categoriesFetcher, targData)

assert.NoError(t, err, "Category mapping error should be empty")
assert.Empty(t, rejections, "There should be 0 bid rejection messages")
assert.Equal(t, "10.00_VideoGames_30s_bidder1", bidCategory["bid_id1"], "Category mapping doesn't match")
assert.Equal(t, "10.00_HomeDecor_30s_bidder2", bidCategory["bid_id2"], "Category mapping doesn't match")
assert.Len(t, adapterBids[bidderName1].bids, 1, "Bidders number doesn't match")
assert.Len(t, adapterBids[bidderName2].bids, 1, "Bidders number doesn't match")
assert.Len(t, bidCategory, 2, "Bidders category mapping doesn't match")
}

func TestCategoryMappingBidderNameNoCategories(t *testing.T) {

categoriesFetcher, error := newCategoryFetcher("./test/category-mapping")
if error != nil {
t.Errorf("Failed to create a category Fetcher: %v", error)
}

requestExt := newExtRequestNoBrandCat()
requestExt.Prebid.Targeting.AppendBidderNames = true

targData := &targetData{
priceGranularity: requestExt.Prebid.Targeting.PriceGranularity,
includeWinners: true,
}

requestExt.Prebid.Targeting.DurationRangeSec = []int{15, 30}

adapterBids := make(map[openrtb_ext.BidderName]*pbsOrtbSeatBid)

cats1 := []string{"IAB1-1"}
cats2 := []string{"IAB1-2"}
bid1 := openrtb.Bid{ID: "bid_id1", ImpID: "imp_id1", Price: 10.0000, Cat: cats1, W: 1, H: 1}
bid2 := openrtb.Bid{ID: "bid_id2", ImpID: "imp_id2", Price: 12.0000, Cat: cats2, W: 1, H: 1}

bid1_1 := pbsOrtbBid{&bid1, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0}
bid1_2 := pbsOrtbBid{&bid2, "video", nil, &openrtb_ext.ExtBidPrebidVideo{Duration: 30}, 0}

innerBids1 := []*pbsOrtbBid{
&bid1_1,
}
innerBids2 := []*pbsOrtbBid{
&bid1_2,
}

seatBid1 := pbsOrtbSeatBid{innerBids1, "USD", nil, nil}
bidderName1 := openrtb_ext.BidderName("bidder1")

seatBid2 := pbsOrtbSeatBid{innerBids2, "USD", nil, nil}
bidderName2 := openrtb_ext.BidderName("bidder2")

adapterBids[bidderName1] = &seatBid1
adapterBids[bidderName2] = &seatBid2

bidCategory, adapterBids, rejections, err := applyCategoryMapping(nil, &requestExt, adapterBids, categoriesFetcher, targData)

assert.NoError(t, err, "Category mapping error should be empty")
assert.Empty(t, rejections, "There should be 0 bid rejection messages")
assert.Equal(t, "10.00_30s_bidder1", bidCategory["bid_id1"], "Category mapping doesn't match")
assert.Equal(t, "12.00_30s_bidder2", bidCategory["bid_id2"], "Category mapping doesn't match")
assert.Len(t, adapterBids[bidderName1].bids, 1, "Bidders number doesn't match")
assert.Len(t, adapterBids[bidderName2].bids, 1, "Bidders number doesn't match")
assert.Len(t, bidCategory, 2, "Bidders category mapping doesn't match")
}

func TestBidRejectionErrors(t *testing.T) {
categoriesFetcher, error := newCategoryFetcher("./test/category-mapping")
if error != nil {
Expand Down
Loading

0 comments on commit 0a34a01

Please sign in to comment.