Skip to content

Commit

Permalink
Adds keyvalue hb_format support (#1414)
Browse files Browse the repository at this point in the history
  • Loading branch information
hhhjort authored Jul 30, 2020
1 parent 551faad commit 126455c
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/endpoints/openrtb2/auction.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ to set these params on the response at `response.seatbid[i].bid[j].ext.prebid.ta
},
"includewinners": false, // Optional param defaulting to true
"includebidderkeys": false // Optional param defaulting to true
"includeformat": false // Optional param defaulting to false
}
}
}
Expand All @@ -184,6 +185,8 @@ For backwards compatibility the following strings will also be allowed as price

One of "includewinners" or "includebidderkeys" must be true (both default to true if unset). If both were false, then no targeting keys would be set, which is better configured by omitting targeting altogether.

The parameter "includeformat" indicates the type of the bid (banner, video, etc) for multiformat requests. It will add the key `hb_format` and/or `hb_format_{bidderName}` as per "includewinners" and "includebidderkeys" above.

MediaType PriceGranularity (PBS-Java only) - when a single OpenRTB request contains multiple impressions with different mediatypes, or a single impression supports multiple formats, the different mediatypes may need different price granularities. If `mediatypepricegranularity` is present, `pricegranularity` would only be used for any mediatypes not specified.

```
Expand Down
1 change: 1 addition & 0 deletions exchange/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ func (e *exchange) HoldAuction(ctx context.Context, bidRequest *openrtb.BidReque
includeBidderKeys: requestExt.Prebid.Targeting.IncludeBidderKeys,
includeCacheBids: shouldCacheBids,
includeCacheVast: shouldCacheVAST,
includeFormat: requestExt.Prebid.Targeting.IncludeFormat,
}
targData.cacheHost, targData.cachePath = e.cache.GetExtCacheData()
}
Expand Down
4 changes: 4 additions & 0 deletions exchange/targeting.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type targetData struct {
includeBidderKeys bool
includeCacheBids bool
includeCacheVast bool
includeFormat bool
// cacheHost and cachePath exist to supply cache host and path as targeting parameters
cacheHost string
cachePath string
Expand Down Expand Up @@ -53,6 +54,9 @@ func (targData *targetData) setTargeting(auc *auction, isApp bool, categoryMappi
if vastID, ok := auc.vastCacheIds[topBidPerBidder.bid]; ok {
targData.addKeys(targets, openrtb_ext.HbVastCacheKey, vastID, bidderName, isOverallWinner)
}
if targData.includeFormat {
targData.addKeys(targets, openrtb_ext.HbFormatKey, string(topBidPerBidder.bidType), bidderName, isOverallWinner)
}

if targData.cacheHost != "" {
targData.addKeys(targets, openrtb_ext.HbConstantCacheHostKey, targData.cacheHost, bidderName, isOverallWinner)
Expand Down
209 changes: 209 additions & 0 deletions exchange/targeting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,212 @@ func (f *mockFetcher) GetId(bidder openrtb_ext.BidderName) (string, bool) {
func mockServer(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("{}"))
}

type TargetingTestData struct {
Description string
TargetData targetData
Auction auction
IsApp bool
CategoryMapping map[string]string
ExpectedBidTargetsByBidder map[string]map[openrtb_ext.BidderName]map[string]string
}

var bid123 *openrtb.Bid = &openrtb.Bid{
Price: 1.23,
}

var bid111 *openrtb.Bid = &openrtb.Bid{
Price: 1.11,
DealID: "mydeal",
}
var bid084 *openrtb.Bid = &openrtb.Bid{
Price: 0.84,
}

var TargetingTests []TargetingTestData = []TargetingTestData{
{
Description: "Targeting winners only (most basic targeting example)",
TargetData: targetData{
priceGranularity: openrtb_ext.PriceGranularityFromString("med"),
includeWinners: true,
},
Auction: auction{
winningBidsByBidder: map[string]map[openrtb_ext.BidderName]*pbsOrtbBid{
"ImpId-1": {
openrtb_ext.BidderAppnexus: {
bid: bid123,
bidType: openrtb_ext.BidTypeBanner,
},
openrtb_ext.BidderRubicon: {
bid: bid084,
bidType: openrtb_ext.BidTypeBanner,
},
},
},
},
ExpectedBidTargetsByBidder: map[string]map[openrtb_ext.BidderName]map[string]string{
"ImpId-1": {
openrtb_ext.BidderAppnexus: {
"hb_bidder": "appnexus",
"hb_pb": "1.20",
},
openrtb_ext.BidderRubicon: {},
},
},
},
{
Description: "Targeting on bidders only",
TargetData: targetData{
priceGranularity: openrtb_ext.PriceGranularityFromString("med"),
includeBidderKeys: true,
},
Auction: auction{
winningBidsByBidder: map[string]map[openrtb_ext.BidderName]*pbsOrtbBid{
"ImpId-1": {
openrtb_ext.BidderAppnexus: {
bid: bid123,
bidType: openrtb_ext.BidTypeBanner,
},
openrtb_ext.BidderRubicon: {
bid: bid084,
bidType: openrtb_ext.BidTypeBanner,
},
},
},
},
ExpectedBidTargetsByBidder: map[string]map[openrtb_ext.BidderName]map[string]string{
"ImpId-1": {
openrtb_ext.BidderAppnexus: {
"hb_bidder_appnexus": "appnexus",
"hb_pb_appnexus": "1.20",
},
openrtb_ext.BidderRubicon: {
"hb_bidder_rubicon": "rubicon",
"hb_pb_rubicon": "0.80",
},
},
},
},
{
Description: "Full basic targeting with hd_format",
TargetData: targetData{
priceGranularity: openrtb_ext.PriceGranularityFromString("med"),
includeWinners: true,
includeBidderKeys: true,
includeFormat: true,
},
Auction: auction{
winningBidsByBidder: map[string]map[openrtb_ext.BidderName]*pbsOrtbBid{
"ImpId-1": {
openrtb_ext.BidderAppnexus: {
bid: bid123,
bidType: openrtb_ext.BidTypeBanner,
},
openrtb_ext.BidderRubicon: {
bid: bid084,
bidType: openrtb_ext.BidTypeBanner,
},
},
},
},
ExpectedBidTargetsByBidder: map[string]map[openrtb_ext.BidderName]map[string]string{
"ImpId-1": {
openrtb_ext.BidderAppnexus: {
"hb_bidder": "appnexus",
"hb_bidder_appnexus": "appnexus",
"hb_pb": "1.20",
"hb_pb_appnexus": "1.20",
"hb_format": "banner",
"hb_format_appnexus": "banner",
},
openrtb_ext.BidderRubicon: {
"hb_bidder_rubicon": "rubicon",
"hb_pb_rubicon": "0.80",
"hb_format_rubicon": "banner",
},
},
},
},
{
Description: "Cache and deal targeting test",
TargetData: targetData{
priceGranularity: openrtb_ext.PriceGranularityFromString("med"),
includeBidderKeys: true,
cacheHost: "cache.prebid.com",
cachePath: "cache",
},
Auction: auction{
winningBidsByBidder: map[string]map[openrtb_ext.BidderName]*pbsOrtbBid{
"ImpId-1": {
openrtb_ext.BidderAppnexus: {
bid: bid123,
bidType: openrtb_ext.BidTypeBanner,
},
openrtb_ext.BidderRubicon: {
bid: bid111,
bidType: openrtb_ext.BidTypeBanner,
},
},
},
cacheIds: map[*openrtb.Bid]string{
bid123: "55555",
bid111: "cacheme",
},
},
ExpectedBidTargetsByBidder: map[string]map[openrtb_ext.BidderName]map[string]string{
"ImpId-1": {
openrtb_ext.BidderAppnexus: {
"hb_bidder_appnexus": "appnexus",
"hb_pb_appnexus": "1.20",
"hb_cache_id_appnexus": "55555",
"hb_cache_host_appnex": "cache.prebid.com",
"hb_cache_path_appnex": "cache",
},
openrtb_ext.BidderRubicon: {
"hb_bidder_rubicon": "rubicon",
"hb_pb_rubicon": "1.10",
"hb_cache_id_rubicon": "cacheme",
"hb_deal_rubicon": "mydeal",
"hb_cache_host_rubico": "cache.prebid.com",
"hb_cache_path_rubico": "cache",
},
},
},
},
}

func TestSetTargeting(t *testing.T) {
for _, test := range TargetingTests {
auc := &test.Auction
// Set rounded prices from the auction data
auc.setRoundedPrices(test.TargetData.priceGranularity)
winningBids := make(map[string]*pbsOrtbBid)
// Set winning bids from the auction data
for imp, bidsByBidder := range auc.winningBidsByBidder {
for _, bid := range bidsByBidder {
if winningBid, ok := winningBids[imp]; ok {
if winningBid.bid.Price < bid.bid.Price {
winningBids[imp] = bid
}
} else {
winningBids[imp] = bid
}
}
}
auc.winningBids = winningBids
targData := test.TargetData
targData.setTargeting(auc, test.IsApp, test.CategoryMapping)
for imp, targetsByBidder := range test.ExpectedBidTargetsByBidder {
for bidder, expected := range targetsByBidder {
assert.Equal(t,
expected,
auc.winningBidsByBidder[imp][bidder].bidTargets,
"Test: %s\nTargeting failed for bidder %s on imp %s.",
test.Description,
string(bidder),
imp)
}
}
}

}
3 changes: 3 additions & 0 deletions openrtb_ext/bid.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ const (
HbSizeConstantKey TargetingKey = "hb_size"
HbDealIDConstantKey TargetingKey = "hb_deal"

// HbFormatKey is the format of the bid. For example, "video", "banner"
HbFormatKey TargetingKey = "hb_format"

// HbCacheKey and HbVastCacheKey store UUIDs which can be used to fetch things from prebid cache.
// Callers should *never* assume that either of these exist, since the call to the cache may always fail.
//
Expand Down
1 change: 1 addition & 0 deletions openrtb_ext/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type ExtRequestTargeting struct {
IncludeWinners bool `json:"includewinners"`
IncludeBidderKeys bool `json:"includebidderkeys"`
IncludeBrandCategory *ExtIncludeBrandCategory `json:"includebrandcategory"`
IncludeFormat bool `json:"includeformat"`
DurationRangeSec []int `json:"durationrangesec"`
}

Expand Down

0 comments on commit 126455c

Please sign in to comment.