Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 32 additions & 17 deletions adapters/pubmatic/pubmatic.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type pubmaticBidExt struct {
VideoCreativeInfo *pubmaticBidExtVideo `json:"video,omitempty"`
Marketplace string `json:"marketplace,omitempty"`
PrebidDealPriority int `json:"prebiddealpriority,omitempty"`
InBannerVideo bool `json:"ibv,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that getBidType(bidExt *pubmaticBidExt) has become getMediaTypeForBid(bid *openrtb2.Bid), the BidType *int json:"BidType,omitempty" field seems to not be used anywhere in your adapter's code anymore. Should we remove?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, removed BidType from adapter code

}

type pubmaticWrapperExt struct {
Expand Down Expand Up @@ -461,26 +462,37 @@ func (a *PubmaticAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externa
bid.Cat = bid.Cat[0:1]
}

mType, err := getMediaTypeForBid(&bid)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we write a JSON test case to cover the error scenario?
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes Added test case

errs = append(errs, err)
continue
}

typedBid := &adapters.TypedBid{
Bid: &bid,
BidType: openrtb_ext.BidTypeBanner,
BidType: mType,
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
}

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppose a native type bid comes and, for some unknown reason, its bidExt.InBannerVideo is set to true. Would it be misleading to set typedBid.BidMeta.MediaType to "video" given that this is not a banner? In other words, would it be desirable to add an additional check here to make sure this is really a banner that contains a video?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This scenario will not occur on Pubmatic-openwrap side. It will be handled by Pubmatic SSP side.
So, we don't need any extra check for this scenario.

typedBid.BidMeta.MediaType = string(openrtb_ext.BidTypeVideo)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the scenario where bidExt.InBannerVideo is true, but bidExt.VideoCreativeInfo or bidExt.VideoCreativeInfo.Duration is nil, valid? If not, should we validate and append an error to the errs array in such cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, It is valid case bidExt.VideoCreativeInfo and bidExt.VideoCreativeInfo.Duration is nil in case of bidExt.InBannerVideo is true.

}
}

if typedBid.BidType == openrtb_ext.BidTypeNative {
Expand Down Expand Up @@ -637,24 +649,27 @@ func getStringArray(array []interface{}) []string {
return aString
}

// getBidType returns the bid type specified in the response bid.ext
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we update the comment? getMediaTypeForBid doesn't return the bid type from bid.ext anymore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes sure

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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure from now on the media type will always be located in bid.MType and not in bid.Ext? Do you think we should look in bid.MType first and then bid.Ext second for backwards compatibility?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we are sure on media type will always be located in bid.MType. I don't think we need to have any backward compatibility logic.

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),
Copy link
Contributor

@scr-oath scr-oath Jun 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: superfluous space.

Suggested change
Message: fmt.Sprintf("failed to parse bid mtype (%d) for impression id %s", bid.MType, bid.ImpID),
Message: fmt.Sprintf("failed to parse bid mtype (%d) for impression id %s", bid.MType, bid.ImpID),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed extra space

}
}
}
return bidType
return mType, nil
}

// Builder builds a new instance of the Pubmatic adapter for the given bidder with the given config.
Expand Down
205 changes: 162 additions & 43 deletions adapters/pubmatic/pubmatic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ 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"
)
Expand All @@ -26,52 +27,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 {
assert.EqualError(t, actualError, tt.expectedError.Error(), "unexpected error message")
} else {
assert.NoError(t, actualError, "expected no error but got one")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Use require for things that cannot proceed if unmet. Also, in the expect error case, use the guard pattern (merely return rather than needing else clause).

Suggested change
if tt.expectedError != nil {
assert.EqualError(t, actualError, tt.expectedError.Error(), "unexpected error message")
} else {
assert.NoError(t, actualError, "expected no error but got one")
}
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")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you
Updated code with require.

})
}
}

Expand Down Expand Up @@ -398,7 +414,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,
Expand All @@ -416,11 +432,30 @@ 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{
AdapterCode: "",
AdvertiserDomains: nil,
AdvertiserID: 0,
AdvertiserName: "",
AgencyID: 0,
AgencyName: "",
DChain: nil,
DemandSource: "",
MediaType: "banner",
NetworkID: 0,
NetworkName: "",
RendererName: "",
RendererVersion: "",
RendererData: nil,
RendererUrl: "",
SecondaryCategoryIDs: nil,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: reduce complexity by omitting "zero values"

Suggested change
BidMeta: &openrtb_ext.ExtBidPrebidMeta{
AdapterCode: "",
AdvertiserDomains: nil,
AdvertiserID: 0,
AdvertiserName: "",
AgencyID: 0,
AgencyName: "",
DChain: nil,
DemandSource: "",
MediaType: "banner",
NetworkID: 0,
NetworkName: "",
RendererName: "",
RendererVersion: "",
RendererData: nil,
RendererUrl: "",
SecondaryCategoryIDs: nil,
},
BidMeta: &openrtb_ext.ExtBidPrebidMeta{
MediaType: "banner",
},

},
},
Currency: "USD",
Expand All @@ -431,7 +466,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,
Expand All @@ -449,15 +484,99 @@ 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{
AdapterCode: "",
AdvertiserDomains: nil,
AdvertiserID: 0,
AdvertiserName: "",
AgencyID: 0,
AgencyName: "",
DChain: nil,
DemandSource: "",
MediaType: "banner",
NetworkID: 0,
NetworkName: "",
RendererName: "",
RendererVersion: "",
RendererData: nil,
RendererUrl: "",
SecondaryCategoryIDs: nil,
},
},
},
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}`),
},
BidType: openrtb_ext.BidTypeBanner,
BidVideo: &openrtb_ext.ExtBidPrebidVideo{},
BidMeta: &openrtb_ext.ExtBidPrebidMeta{
AdapterCode: "",
AdvertiserDomains: nil,
AdvertiserID: 0,
AdvertiserName: "",
AgencyID: 0,
AgencyName: "",
DChain: nil,
DemandSource: "",
MediaType: "video",
NetworkID: 0,
NetworkName: "",
RendererName: "",
RendererVersion: "",
RendererData: nil,
RendererUrl: "",
SecondaryCategoryIDs: nil,
},
},
},
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) {
Expand Down
2 changes: 2 additions & 0 deletions adapters/pubmatic/pubmatictest/exemplary/banner.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
"h": 250,
"w": 300,
"dealid":"test deal",
"mtype": 1,
"ext": {
"dspid": 6,
"deal_channel": 1,
Expand Down Expand Up @@ -142,6 +143,7 @@
"w": 300,
"h": 250,
"dealid":"test deal",
"mtype": 1,
"ext": {
"dspid": 6,
"deal_channel": 1,
Expand Down
2 changes: 2 additions & 0 deletions adapters/pubmatic/pubmatictest/exemplary/fledge.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"crid": "crid_10",
"h": 90,
"w": 728,
"mtype": 1,
"ext": {}
}
]
Expand Down Expand Up @@ -123,6 +124,7 @@
"crid": "crid_10",
"w": 728,
"h": 90,
"mtype": 1,
"ext": {}
},
"type": "banner"
Expand Down
Loading
Loading