diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go index ef6354b7bb9..9c42ae57b22 100644 --- a/adapters/pubmatic/pubmatic.go +++ b/adapters/pubmatic/pubmatic.go @@ -30,10 +30,10 @@ type PubmaticAdapter struct { } type pubmaticBidExt struct { - BidType *int `json:"BidType,omitempty"` VideoCreativeInfo *pubmaticBidExtVideo `json:"video,omitempty"` Marketplace string `json:"marketplace,omitempty"` PrebidDealPriority int `json:"prebiddealpriority,omitempty"` + InBannerVideo bool `json:"ibv,omitempty"` } type pubmaticWrapperExt struct { @@ -461,19 +461,24 @@ func (a *PubmaticAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa bid.Cat = bid.Cat[0:1] } + mType, err := getMediaTypeForBid(&bid) + if err != nil { + errs = append(errs, err) + continue + } + typedBid := &adapters.TypedBid{ Bid: &bid, - BidType: openrtb_ext.BidTypeBanner, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, } var bidExt *pubmaticBidExt - err := jsonutil.Unmarshal(bid.Ext, &bidExt) + err = jsonutil.Unmarshal(bid.Ext, &bidExt) if err != nil { errs = append(errs, err) } else if bidExt != nil { typedBid.Seat = openrtb_ext.BidderName(bidExt.Marketplace) - typedBid.BidType = getBidType(bidExt) + if bidExt.PrebidDealPriority > 0 { typedBid.DealPriority = bidExt.PrebidDealPriority } @@ -481,9 +486,14 @@ func (a *PubmaticAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa if bidExt.VideoCreativeInfo != nil && bidExt.VideoCreativeInfo.Duration != nil { typedBid.BidVideo.Duration = *bidExt.VideoCreativeInfo.Duration } + + typedBid.BidMeta = &openrtb_ext.ExtBidPrebidMeta{MediaType: string(mType)} + if bidExt.InBannerVideo { + typedBid.BidMeta.MediaType = string(openrtb_ext.BidTypeVideo) + } } - if typedBid.BidType == openrtb_ext.BidTypeNative { + if mType == openrtb_ext.BidTypeNative { bid.AdM, err = getNativeAdm(bid.AdM) if err != nil { errs = append(errs, err) @@ -637,24 +647,27 @@ func getStringArray(array []interface{}) []string { return aString } -// getBidType returns the bid type specified in the response bid.ext -func getBidType(bidExt *pubmaticBidExt) openrtb_ext.BidType { +// getMediaTypeForBid returns the Mtype +func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { // setting "banner" as the default bid type - bidType := openrtb_ext.BidTypeBanner - if bidExt != nil && bidExt.BidType != nil { - switch *bidExt.BidType { - case 0: - bidType = openrtb_ext.BidTypeBanner - case 1: - bidType = openrtb_ext.BidTypeVideo - case 2: - bidType = openrtb_ext.BidTypeNative + mType := openrtb_ext.BidTypeBanner + if bid != nil { + switch bid.MType { + case openrtb2.MarkupBanner: + mType = openrtb_ext.BidTypeBanner + case openrtb2.MarkupVideo: + mType = openrtb_ext.BidTypeVideo + case openrtb2.MarkupAudio: + mType = openrtb_ext.BidTypeAudio + case openrtb2.MarkupNative: + mType = openrtb_ext.BidTypeNative default: - // default value is banner - bidType = openrtb_ext.BidTypeBanner + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("failed to parse bid mtype (%d) for impression id %s", bid.MType, bid.ImpID), + } } } - return bidType + return mType, nil } // Builder builds a new instance of the Pubmatic adapter for the given bidder with the given config. diff --git a/adapters/pubmatic/pubmatic_test.go b/adapters/pubmatic/pubmatic_test.go index 122840771b1..74883b23a90 100644 --- a/adapters/pubmatic/pubmatic_test.go +++ b/adapters/pubmatic/pubmatic_test.go @@ -11,8 +11,10 @@ import ( "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/adapters/adapterstest" "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestJsonSamples(t *testing.T) { @@ -26,52 +28,67 @@ func TestJsonSamples(t *testing.T) { adapterstest.RunJSONBidderTest(t, "pubmatictest", bidder) } -func TestGetBidTypeVideo(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - pubmaticExt.BidType = new(int) - *pubmaticExt.BidType = 1 - actualBidTypeValue := getBidType(pubmaticExt) - if actualBidTypeValue != openrtb_ext.BidTypeVideo { - t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeVideo, actualBidTypeValue) +func TestGetMediaTypeForBid(t *testing.T) { + tests := []struct { + name string + mType openrtb2.MarkupType + expectedMType openrtb_ext.BidType + expectedError error + }{ + { + name: "Test Banner Bid Type", + mType: 1, + expectedMType: openrtb_ext.BidTypeBanner, + expectedError: nil, + }, + { + name: "Test Video Bid Type", + mType: 2, + expectedMType: openrtb_ext.BidTypeVideo, + expectedError: nil, + }, + { + name: "Test Audio Bid Type", + mType: 3, + expectedMType: openrtb_ext.BidTypeAudio, + expectedError: nil, + }, + { + name: "Test Native Bid Type", + mType: 4, + expectedMType: openrtb_ext.BidTypeNative, + expectedError: nil, + }, + { + name: "Test Unsupported MType (Invalid MType)", + mType: 44, + expectedMType: "", // default value for unsupported types + expectedError: &errortypes.BadServerResponse{Message: "failed to parse bid mtype (44) for impression id "}, + }, + { + name: "Test Default MType (MType 0 or Not Set)", + mType: 0, // This represents the default case where MType is not explicitly set + expectedMType: "", // Default is empty and return error + expectedError: &errortypes.BadServerResponse{Message: "failed to parse bid mtype (0) for impression id "}, + }, } -} -func TestGetBidTypeForMissingBidTypeExt(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - actualBidTypeValue := getBidType(pubmaticExt) - // banner is the default bid type when no bidType key is present in the bid.ext - if actualBidTypeValue != "banner" { - t.Errorf("Expected Bid Type value was: banner, actual value is: %v", actualBidTypeValue) - } -} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bid := openrtb2.Bid{ + MType: tt.mType, + } -func TestGetBidTypeBanner(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - pubmaticExt.BidType = new(int) - *pubmaticExt.BidType = 0 - actualBidTypeValue := getBidType(pubmaticExt) - if actualBidTypeValue != openrtb_ext.BidTypeBanner { - t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeBanner, actualBidTypeValue) - } -} + actualBidTypeValue, actualError := getMediaTypeForBid(&bid) -func TestGetBidTypeNative(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - pubmaticExt.BidType = new(int) - *pubmaticExt.BidType = 2 - actualBidTypeValue := getBidType(pubmaticExt) - if actualBidTypeValue != openrtb_ext.BidTypeNative { - t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeNative, actualBidTypeValue) - } -} + assert.Equal(t, tt.expectedMType, actualBidTypeValue, "unexpected BidType value") -func TestGetBidTypeForUnsupportedCode(t *testing.T) { - pubmaticExt := &pubmaticBidExt{} - pubmaticExt.BidType = new(int) - *pubmaticExt.BidType = 99 - actualBidTypeValue := getBidType(pubmaticExt) - if actualBidTypeValue != openrtb_ext.BidTypeBanner { - t.Errorf("Expected Bid Type value was: %v, actual value is: %v", openrtb_ext.BidTypeBanner, actualBidTypeValue) + if tt.expectedError != nil { + require.EqualError(t, actualError, tt.expectedError.Error(), "unexpected error message") + return + } + require.NoError(t, actualError, "expected no error but got one") + }) } } @@ -398,7 +415,7 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { args: args{ response: &adapters.ResponseData{ StatusCode: http.StatusOK, - Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "mtype": 1, "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), }, }, wantErr: nil, @@ -416,11 +433,14 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { H: 250, W: 300, DealID: "testdeal", + MType: 1, Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": 1}`), }, DealPriority: 1, - BidType: openrtb_ext.BidTypeBanner, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{ + MediaType: "banner", + }, }, }, Currency: "USD", @@ -431,7 +451,7 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { args: args{ response: &adapters.ResponseData{ StatusCode: http.StatusOK, - Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal","mtype": 1, "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), }, }, wantErr: nil, @@ -449,15 +469,67 @@ func TestPubmaticAdapter_MakeBids(t *testing.T) { H: 250, W: 300, DealID: "testdeal", + MType: 1, Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1}`), }, - BidType: openrtb_ext.BidTypeBanner, BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{ + MediaType: "banner", + }, }, }, Currency: "USD", }, }, + { + name: "bid_ext_InBannerVideo_is_true", + args: args{ + response: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "mtype": 1, "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1, "ibv": true}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + }, + }, + wantErr: nil, + wantResp: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{ + { + Bid: &openrtb2.Bid{ + ID: "7706636740145184841", + ImpID: "test-imp-id", + Price: 0.500000, + AdID: "29681110", + AdM: "some-test-ad", + ADomain: []string{"pubmatic.com"}, + CrID: "29681110", + H: 250, + W: 300, + DealID: "testdeal", + MType: 1, + Ext: json.RawMessage(`{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1, "ibv": true}`), + }, + BidVideo: &openrtb_ext.ExtBidPrebidVideo{}, + BidMeta: &openrtb_ext.ExtBidPrebidMeta{ + MediaType: "video", + }, + }, + }, + Currency: "USD", + }, + }, + { + name: "getMediaTypeForBid_return_error", + args: args{ + response: &adapters.ResponseData{ + StatusCode: http.StatusOK, + Body: []byte(`{"id": "test-request-id", "seatbid":[{"seat": "958", "bid":[{"id": "7706636740145184841", "impid": "test-imp-id", "price": 0.500000, "adid": "29681110", "adm": "some-test-ad", "adomain":["pubmatic.com"], "crid": "29681110", "h": 250, "w": 300, "dealid": "testdeal", "mtype": 0, "ext":{"dspid": 6, "deal_channel": 1, "prebiddealpriority": -1, "ibv": true}}]}], "bidid": "5778926625248726496", "cur": "USD"}`), + }, + }, + wantErr: []error{&errortypes.BadServerResponse{Message: "failed to parse bid mtype (0) for impression id test-imp-id"}}, + wantResp: &adapters.BidderResponse{ + Bids: []*adapters.TypedBid{}, + Currency: "USD", + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/adapters/pubmatic/pubmatictest/exemplary/banner.json b/adapters/pubmatic/pubmatictest/exemplary/banner.json index 8e505bd3348..43e0fd4ecdb 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/banner.json +++ b/adapters/pubmatic/pubmatictest/exemplary/banner.json @@ -111,6 +111,7 @@ "h": 250, "w": 300, "dealid":"test deal", + "mtype": 1, "ext": { "dspid": 6, "deal_channel": 1, @@ -142,13 +143,13 @@ "w": 300, "h": 250, "dealid":"test deal", + "mtype": 1, "ext": { "dspid": 6, "deal_channel": 1, "prebiddealpriority": 1 } - }, - "type": "banner" + } } ] } diff --git a/adapters/pubmatic/pubmatictest/exemplary/fledge.json b/adapters/pubmatic/pubmatictest/exemplary/fledge.json index 96c8f93ca5c..b094ea13f83 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/fledge.json +++ b/adapters/pubmatic/pubmatictest/exemplary/fledge.json @@ -67,6 +67,7 @@ "crid": "crid_10", "h": 90, "w": 728, + "mtype": 1, "ext": {} } ] @@ -123,9 +124,9 @@ "crid": "crid_10", "w": 728, "h": 90, + "mtype": 1, "ext": {} - }, - "type": "banner" + } } ], "fledgeauctionconfigs": [ diff --git a/adapters/pubmatic/pubmatictest/exemplary/native.json b/adapters/pubmatic/pubmatictest/exemplary/native.json index dedabf8af41..74e0a58af61 100644 --- a/adapters/pubmatic/pubmatictest/exemplary/native.json +++ b/adapters/pubmatic/pubmatictest/exemplary/native.json @@ -76,6 +76,7 @@ "adid": "some-test-id", "adm": "{\"native\":{\"assets\":[{\"id\":2,\"img\":{\"h\":90,\"url\":\"//ads.pubmatic.com/AdTag/native/728x90.png\",\"w\":728}},{\"data\":{\"value\":\"Sponsored By PubMatic\"},\"id\":4},{\"id\":3,\"img\":{\"h\":90,\"url\":\"//ads.pubmatic.com/AdTag/native/728x90.png\",\"w\":728}},{\"id\":1,\"title\":{\"text\":\"Native Test Title\"}},{\"data\":{\"value\":\"Sponsored By PubMatic\"},\"id\":5}],\"imptrackers\":[\"http://clicktracker.com/AdTag/9bde02d0-6017-11e4-9df7-005056967c35\"],\"jstracker\":\"