Skip to content

Commit

Permalink
Fix for storedauctionresponse bid type (#2615)
Browse files Browse the repository at this point in the history
  • Loading branch information
VeronikaSolovei9 authored Mar 20, 2023
1 parent 60d4a81 commit 2fb3b7e
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"description": "Amp request where impression makes reference to a valid stored response with a $5.00 bid",
"query": "tag_id=101",
"mockAmpStoredResponse": {
"6d718149": "[{\"bid\": [{\"id\": \"bid_id\", \"price\": 5.00, \"ext\": {\"prebid\": {\"targeting\": { \"hb_pb\": \"1.20\", \"hb_cat\": \"IAB-20\", \"hb_cache_id\": \"some_id\"}}}}],\"seat\": \"appnexus\"}]"
"6d718149": "[{\"bid\": [{\"id\": \"bid_id\", \"price\": 5.00, \"ext\": {\"prebid\": {\"type\":\"video\", \"targeting\": { \"hb_pb\": \"1.20\", \"hb_cat\": \"IAB-20\", \"hb_cache_id\": \"some_id\"}}}}],\"seat\": \"appnexus\"}]"
},
"mockBidRequest": {
"id": "request-with-stored-resp",
Expand Down
40 changes: 39 additions & 1 deletion exchange/exchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -1300,6 +1300,20 @@ func listBiddersWithRequests(bidderRequests []BidderRequest) []openrtb_ext.Bidde
return liveAdapters
}

func getPrebidMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
if bid.Ext != nil {
var bidExt openrtb_ext.ExtBid
err := json.Unmarshal(bid.Ext, &bidExt)
if err == nil && bidExt.Prebid != nil {
return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type))
}
}

return "", &errortypes.BadServerResponse{
Message: fmt.Sprintf("Failed to parse bid mediatype for impression \"%s\"", bid.ImpID),
}
}

func buildStoredAuctionResponse(storedAuctionResponses map[string]json.RawMessage) (
map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid,
*openrtb_ext.Fledge,
Expand All @@ -1320,7 +1334,31 @@ func buildStoredAuctionResponse(storedAuctionResponses map[string]json.RawMessag
//set imp id from request
for i := range seat.Bid {
seat.Bid[i].ImpID = impId
bidsToAdd = append(bidsToAdd, &entities.PbsOrtbBid{Bid: &seat.Bid[i]})
mType := seat.Bid[i].MType
var bidType openrtb_ext.BidType
if mType > 0 {
switch mType {
case openrtb2.MarkupBanner:
bidType = openrtb_ext.BidTypeBanner
case openrtb2.MarkupVideo:
bidType = openrtb_ext.BidTypeVideo
case openrtb2.MarkupAudio:
bidType = openrtb_ext.BidTypeAudio
case openrtb2.MarkupNative:
bidType = openrtb_ext.BidTypeNative
default:
return nil, nil, nil, &errortypes.BadServerResponse{
Message: fmt.Sprintf("Failed to parse bid mType for impression \"%s\"", seat.Bid[i].ImpID),
}
}
} else {
var err error
bidType, err = getPrebidMediaTypeForBid(seat.Bid[i])
if err != nil {
return nil, nil, nil, err
}
}
bidsToAdd = append(bidsToAdd, &entities.PbsOrtbBid{Bid: &seat.Bid[i], BidType: bidType})
}

bidderName := openrtb_ext.BidderName(seat.Seat)
Expand Down
184 changes: 145 additions & 39 deletions exchange/exchange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4117,7 +4117,7 @@ func TestStoredAuctionResponses(t *testing.T) {
SeatBid: []openrtb2.SeatBid{
{
Bid: []openrtb2.Bid{
{ID: "bid_id", ImpID: "impression-id", Ext: json.RawMessage(`{"origbidcpm":0,"prebid":{"type":""}}`)},
{ID: "bid_id", ImpID: "impression-id", Ext: json.RawMessage(`{"origbidcpm":0,"prebid":{"type":"video"}}`)},
},
Seat: "appnexus",
},
Expand All @@ -4132,7 +4132,7 @@ func TestStoredAuctionResponses(t *testing.T) {
{
desc: "Single imp with valid stored response",
storedAuctionResp: map[string]json.RawMessage{
"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id"}],"seat": "appnexus"}]`),
"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "ext": {"prebid": {"type": "video"}}}],"seat": "appnexus"}]`),
},
errorExpected: false,
},
Expand Down Expand Up @@ -4179,43 +4179,67 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
}

testCases := []struct {
desc string
in testIn
expected testResults
desc string
in testIn
expected testResults
errorMessage string
}{
{
desc: "Single imp with single stored response bid",
in: testIn{
StoredAuctionResponses: map[string]json.RawMessage{
"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id"}],"seat": "appnexus"}]`),
"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
},
},
expected: testResults{
adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
openrtb_ext.BidderName("appnexus"): {
Bids: []*entities.PbsOrtbBid{
{
Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id"},
Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)},
BidType: openrtb_ext.BidTypeNative,
},
},
},
},
liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
},
},
{
desc: "Single imp with single stored response bid with incorrect bid type",
in: testIn{
StoredAuctionResponses: map[string]json.RawMessage{
"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "ext": {"prebid": {"type": "incorrect"}}}],"seat": "appnexus"}]`),
},
},
expected: testResults{
adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
openrtb_ext.BidderName("appnexus"): {
Bids: []*entities.PbsOrtbBid{
{
Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)},
BidType: openrtb_ext.BidTypeNative,
},
},
},
},
liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
},
errorMessage: "invalid BidType: incorrect",
},
{
desc: "Single imp with multiple bids in stored response one bidder",
in: testIn{
StoredAuctionResponses: map[string]json.RawMessage{
"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id1"}, {"id": "bid_id2"}],"seat": "appnexus"}]`),
"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "bid_id2", "ext": {"prebid": {"type": "video"}}}],"seat": "appnexus"}]`),
},
},
expected: testResults{
adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
openrtb_ext.BidderName("appnexus"): {
Bids: []*entities.PbsOrtbBid{
{Bid: &openrtb2.Bid{ID: "bid_id1", ImpID: "impression-id"}},
{Bid: &openrtb2.Bid{ID: "bid_id2", ImpID: "impression-id"}},
{Bid: &openrtb2.Bid{ID: "bid_id1", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "bid_id2", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "video"}}`)}, BidType: openrtb_ext.BidTypeVideo},
},
},
},
Expand All @@ -4226,21 +4250,21 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
desc: "Single imp with multiple bids in stored response two bidders",
in: testIn{
StoredAuctionResponses: map[string]json.RawMessage{
"impression-id": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1"}, {"id": "rubicon_id2"}],"seat": "rubicon"}]`),
"impression-id": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1", "ext": {"prebid": {"type": "banner"}}}, {"id": "rubicon_id2", "ext": {"prebid": {"type": "banner"}}}],"seat": "rubicon"}]`),
},
},
expected: testResults{
adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
openrtb_ext.BidderName("appnexus"): {
Bids: []*entities.PbsOrtbBid{
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id"}},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id"}},
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
},
},
openrtb_ext.BidderName("rubicon"): {
Bids: []*entities.PbsOrtbBid{
{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id"}},
{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id"}},
{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "banner"}}`)}, BidType: openrtb_ext.BidTypeBanner},
{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id", Ext: []byte(`{"prebid": {"type": "banner"}}`)}, BidType: openrtb_ext.BidTypeBanner},
},
},
},
Expand All @@ -4251,24 +4275,24 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
desc: "Two imps with two bids in stored response two bidders, different bids number",
in: testIn{
StoredAuctionResponses: map[string]json.RawMessage{
"impression-id1": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}]`),
"impression-id2": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1"}, {"id": "rubicon_id2"}],"seat": "rubicon"}]`),
"impression-id1": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
"impression-id2": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "rubicon_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "rubicon"}]`),
},
},
expected: testResults{
adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
openrtb_ext.BidderName("appnexus"): {
Bids: []*entities.PbsOrtbBid{
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id1"}},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id1"}},
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id2"}},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id2"}},
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
},
},
openrtb_ext.BidderName("rubicon"): {
Bids: []*entities.PbsOrtbBid{
{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id2"}},
{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id2"}},
{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
},
},
},
Expand All @@ -4279,26 +4303,26 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
desc: "Two imps with two bids in stored response two bidders",
in: testIn{
StoredAuctionResponses: map[string]json.RawMessage{
"impression-id1": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1"}, {"id": "rubicon_id2"}],"seat": "rubicon"}]`),
"impression-id2": json.RawMessage(`[{"bid": [{"id": "apn_id1"}, {"id": "apn_id2"}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1"}, {"id": "rubicon_id2"}],"seat": "rubicon"}]`),
"impression-id1": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "rubicon_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "rubicon"}]`),
"impression-id2": json.RawMessage(`[{"bid": [{"id": "apn_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "apn_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}, {"bid": [{"id": "rubicon_id1", "ext": {"prebid": {"type": "native"}}}, {"id": "rubicon_id2", "ext": {"prebid": {"type": "native"}}}],"seat": "rubicon"}]`),
},
},
expected: testResults{
adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
openrtb_ext.BidderName("appnexus"): {
Bids: []*entities.PbsOrtbBid{
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id1"}},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id1"}},
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id2"}},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id2"}},
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "apn_id1", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "apn_id2", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
},
},
openrtb_ext.BidderName("rubicon"): {
Bids: []*entities.PbsOrtbBid{
{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id1"}},
{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id1"}},
{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id2"}},
{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id2"}},
{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id1", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "rubicon_id1", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
{Bid: &openrtb2.Bid{ID: "rubicon_id2", ImpID: "impression-id2", Ext: []byte(`{"prebid": {"type": "native"}}`)}, BidType: openrtb_ext.BidTypeNative},
},
},
},
Expand Down Expand Up @@ -4331,19 +4355,101 @@ func TestBuildStoredAuctionResponses(t *testing.T) {
},
},
},
{
desc: "Single imp with single stored response bid with bid.mtype",
in: testIn{
StoredAuctionResponses: map[string]json.RawMessage{
"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 2, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
},
},
expected: testResults{
adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
openrtb_ext.BidderName("appnexus"): {
Bids: []*entities.PbsOrtbBid{
{
Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id", MType: 2, Ext: []byte(`{"prebid": {"type": "native"}}`)},
BidType: openrtb_ext.BidTypeVideo,
},
},
},
},
liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
},
},
{
desc: "Multiple imps with multiple stored response bid with bid.mtype and different types",
in: testIn{
StoredAuctionResponses: map[string]json.RawMessage{
"impression-id1": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 1, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
"impression-id2": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 2, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
"impression-id3": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 3, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
"impression-id4": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 4, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
},
},
expected: testResults{
adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
openrtb_ext.BidderName("appnexus"): {
Bids: []*entities.PbsOrtbBid{
{
Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id1", MType: 1, Ext: []byte(`{"prebid": {"type": "native"}}`)},
BidType: openrtb_ext.BidTypeBanner,
},
{
Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id2", MType: 2, Ext: []byte(`{"prebid": {"type": "native"}}`)},
BidType: openrtb_ext.BidTypeVideo,
},
{
Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id3", MType: 3, Ext: []byte(`{"prebid": {"type": "native"}}`)},
BidType: openrtb_ext.BidTypeAudio,
},
{
Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id4", MType: 4, Ext: []byte(`{"prebid": {"type": "native"}}`)},
BidType: openrtb_ext.BidTypeNative,
},
},
},
},
liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
},
},
{
desc: "Single imp with single stored response bid with incorrect bid.mtype",
in: testIn{
StoredAuctionResponses: map[string]json.RawMessage{
"impression-id": json.RawMessage(`[{"bid": [{"id": "bid_id", "mtype": 10, "ext": {"prebid": {"type": "native"}}}],"seat": "appnexus"}]`),
},
},
expected: testResults{
adapterBids: map[openrtb_ext.BidderName]*entities.PbsOrtbSeatBid{
openrtb_ext.BidderName("appnexus"): {
Bids: []*entities.PbsOrtbBid{
{
Bid: &openrtb2.Bid{ID: "bid_id", ImpID: "impression-id", MType: 2, Ext: []byte(`{"prebid": {"type": "native"}}`)},
BidType: openrtb_ext.BidTypeVideo,
},
},
},
},
liveAdapters: []openrtb_ext.BidderName{openrtb_ext.BidderName("appnexus")},
},
errorMessage: "Failed to parse bid mType for impression \"impression-id\"",
},
}
for _, test := range testCases {

bids, fledge, adapters, err := buildStoredAuctionResponse(test.in.StoredAuctionResponses)
assert.NoErrorf(t, err, "%s. HoldAuction error: %v \n", test.desc, err)
if len(test.errorMessage) > 0 {
assert.Equal(t, test.errorMessage, err.Error(), " incorrect expected error")
} else {
assert.NoErrorf(t, err, "%s. HoldAuction error: %v \n", test.desc, err)

assert.ElementsMatch(t, test.expected.liveAdapters, adapters, "Incorrect adapter list")
assert.Equal(t, fledge, test.expected.fledge, "Incorrect FLEDGE response")
assert.ElementsMatch(t, test.expected.liveAdapters, adapters, "Incorrect adapter list")
assert.Equal(t, fledge, test.expected.fledge, "Incorrect FLEDGE response")

for _, bidderName := range test.expected.liveAdapters {
assert.ElementsMatch(t, test.expected.adapterBids[bidderName].Bids, bids[bidderName].Bids, "Incorrect bids")
for _, bidderName := range test.expected.liveAdapters {
assert.ElementsMatch(t, test.expected.adapterBids[bidderName].Bids, bids[bidderName].Bids, "Incorrect bids")
}
}

}
}

Expand Down

0 comments on commit 2fb3b7e

Please sign in to comment.