Skip to content

Commit 48e6275

Browse files
authored
DOOH support (prebid#2758)
1 parent b96e2f7 commit 48e6275

File tree

19 files changed

+774
-52
lines changed

19 files changed

+774
-52
lines changed

adapters/infoawarebidder.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
// media types defined in the static/bidder-info/{bidder}.yaml file.
1414
//
1515
// It adjusts incoming requests in the following ways:
16-
// 1. If App or Site traffic is not supported by the info file, then requests from
16+
// 1. If App, Site or DOOH traffic is not supported by the info file, then requests from
1717
// those sources will be rejected before the delegate is called.
1818
// 2. If a given MediaType is not supported for the platform, then it will be set
1919
// to nil before the request is forwarded to the delegate.
@@ -24,7 +24,7 @@ type InfoAwareBidder struct {
2424
info parsedBidderInfo
2525
}
2626

27-
// BuildInfoAwareBidder wraps a bidder to enforce site, app, and media type support.
27+
// BuildInfoAwareBidder wraps a bidder to enforce inventory {site, app, dooh} and media type support.
2828
func BuildInfoAwareBidder(bidder Bidder, info config.BidderInfo) Bidder {
2929
return &InfoAwareBidder{
3030
Bidder: bidder,
@@ -47,6 +47,12 @@ func (i *InfoAwareBidder) MakeRequests(request *openrtb2.BidRequest, reqInfo *Ex
4747
}
4848
allowedMediaTypes = i.info.app
4949
}
50+
if request.DOOH != nil {
51+
if !i.info.dooh.enabled {
52+
return nil, []error{&errortypes.Warning{Message: "this bidder does not support dooh requests"}}
53+
}
54+
allowedMediaTypes = i.info.dooh
55+
}
5056

5157
// Filtering imps is quite expensive (array filter with large, non-pointer elements)... but should be rare,
5258
// because it only happens if the publisher makes a really bad request.
@@ -136,6 +142,7 @@ func filterImps(imps []openrtb2.Imp, numToFilter int) ([]openrtb2.Imp, []error)
136142
type parsedBidderInfo struct {
137143
app parsedSupports
138144
site parsedSupports
145+
dooh parsedSupports
139146
}
140147

141148
type parsedSupports struct {
@@ -148,13 +155,22 @@ type parsedSupports struct {
148155

149156
func parseBidderInfo(info config.BidderInfo) parsedBidderInfo {
150157
var parsedInfo parsedBidderInfo
151-
if info.Capabilities != nil && info.Capabilities.App != nil {
158+
159+
if info.Capabilities == nil {
160+
return parsedInfo
161+
}
162+
163+
if info.Capabilities.App != nil {
152164
parsedInfo.app.enabled = true
153165
parsedInfo.app.banner, parsedInfo.app.video, parsedInfo.app.audio, parsedInfo.app.native = parseAllowedTypes(info.Capabilities.App.MediaTypes)
154166
}
155-
if info.Capabilities != nil && info.Capabilities.Site != nil {
167+
if info.Capabilities.Site != nil {
156168
parsedInfo.site.enabled = true
157169
parsedInfo.site.banner, parsedInfo.site.video, parsedInfo.site.audio, parsedInfo.site.native = parseAllowedTypes(info.Capabilities.Site.MediaTypes)
158170
}
171+
if info.Capabilities.DOOH != nil {
172+
parsedInfo.dooh.enabled = true
173+
parsedInfo.dooh.banner, parsedInfo.dooh.video, parsedInfo.dooh.audio, parsedInfo.dooh.native = parseAllowedTypes(info.Capabilities.DOOH.MediaTypes)
174+
}
159175
return parsedInfo
160176
}

adapters/infoawarebidder_test.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/prebid/prebid-server/errortypes"
1111
"github.com/prebid/prebid-server/openrtb_ext"
1212
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
1314
)
1415

1516
func TestAppNotSupported(t *testing.T) {
@@ -56,6 +57,26 @@ func TestSiteNotSupported(t *testing.T) {
5657
assert.Len(t, bids, 0)
5758
}
5859

60+
func TestDOOHNotSupported(t *testing.T) {
61+
bidder := &mockBidder{}
62+
info := config.BidderInfo{
63+
Capabilities: &config.CapabilitiesInfo{
64+
Site: &config.PlatformInfo{
65+
MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner},
66+
},
67+
},
68+
}
69+
constrained := adapters.BuildInfoAwareBidder(bidder, info)
70+
bids, errs := constrained.MakeRequests(&openrtb2.BidRequest{
71+
Imp: []openrtb2.Imp{{ID: "imp-1", Banner: &openrtb2.Banner{}}},
72+
DOOH: &openrtb2.DOOH{},
73+
}, &adapters.ExtraRequestInfo{})
74+
require.Len(t, errs, 1)
75+
assert.EqualError(t, errs[0], "this bidder does not support dooh requests")
76+
assert.IsType(t, &errortypes.Warning{}, errs[0])
77+
assert.Len(t, bids, 0)
78+
}
79+
5980
func TestImpFiltering(t *testing.T) {
6081
bidder := &mockBidder{}
6182
info := config.BidderInfo{
@@ -66,6 +87,9 @@ func TestImpFiltering(t *testing.T) {
6687
App: &config.PlatformInfo{
6788
MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeBanner},
6889
},
90+
DOOH: &config.PlatformInfo{
91+
MediaTypes: []openrtb_ext.BidType{openrtb_ext.BidTypeNative},
92+
},
6993
},
7094
}
7195

@@ -153,10 +177,10 @@ func TestImpFiltering(t *testing.T) {
153177
description: "All imps with correct media type, MakeRequest() call expected",
154178
inBidRequest: &openrtb2.BidRequest{
155179
Imp: []openrtb2.Imp{
156-
{ID: "imp-1", Video: &openrtb2.Video{}},
157-
{ID: "imp-2", Video: &openrtb2.Video{}},
180+
{ID: "imp-1", Native: &openrtb2.Native{}},
181+
{ID: "imp-2", Native: &openrtb2.Native{}},
158182
},
159-
Site: &openrtb2.Site{},
183+
DOOH: &openrtb2.DOOH{},
160184
},
161185
expectedErrors: nil,
162186
expectedImpLen: 2,

config/account.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const (
2020
ChannelApp ChannelType = "app"
2121
ChannelVideo ChannelType = "video"
2222
ChannelWeb ChannelType = "web"
23+
ChannelDOOH ChannelType = "dooh"
2324
)
2425

2526
// Account represents a publisher account configuration
@@ -251,6 +252,7 @@ type AccountChannel struct {
251252
App *bool `mapstructure:"app" json:"app,omitempty"`
252253
Video *bool `mapstructure:"video" json:"video,omitempty"`
253254
Web *bool `mapstructure:"web" json:"web,omitempty"`
255+
DOOH *bool `mapstructure:"dooh" json:"dooh,omitempty"`
254256
}
255257

256258
// GetByChannelType looks up the account integration enabled setting for the specified channel type
@@ -266,6 +268,8 @@ func (a *AccountChannel) GetByChannelType(channelType ChannelType) *bool {
266268
channelEnabled = a.Video
267269
case ChannelWeb:
268270
channelEnabled = a.Web
271+
case ChannelDOOH:
272+
channelEnabled = a.DOOH
269273
}
270274

271275
return channelEnabled
@@ -296,7 +300,7 @@ func (m AccountModules) ModuleConfig(id string) (json.RawMessage, error) {
296300
}
297301

298302
func (a *AccountChannel) IsSet() bool {
299-
return a.AMP != nil || a.App != nil || a.Video != nil || a.Web != nil
303+
return a.AMP != nil || a.App != nil || a.Video != nil || a.Web != nil || a.DOOH != nil
300304
}
301305

302306
type AccountPrivacy struct {

config/account_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ func TestAccountChannelGetByChannelType(t *testing.T) {
205205
giveAppEnabled *bool
206206
giveVideoEnabled *bool
207207
giveWebEnabled *bool
208+
giveDOOHEnabled *bool
208209
giveChannelType ChannelType
209210
wantEnabled *bool
210211
}{
@@ -276,6 +277,23 @@ func TestAccountChannelGetByChannelType(t *testing.T) {
276277
giveChannelType: ChannelWeb,
277278
wantEnabled: &trueValue,
278279
},
280+
{
281+
description: "DOOH channel setting unspecified, returns nil",
282+
giveChannelType: ChannelDOOH,
283+
wantEnabled: nil,
284+
},
285+
{
286+
description: "DOOH channel disabled, returns false",
287+
giveDOOHEnabled: &falseValue,
288+
giveChannelType: ChannelDOOH,
289+
wantEnabled: &falseValue,
290+
},
291+
{
292+
description: "DOOH channel enabled, returns true",
293+
giveDOOHEnabled: &trueValue,
294+
giveChannelType: ChannelDOOH,
295+
wantEnabled: &trueValue,
296+
},
279297
}
280298

281299
for _, tt := range tests {
@@ -284,6 +302,7 @@ func TestAccountChannelGetByChannelType(t *testing.T) {
284302
App: tt.giveAppEnabled,
285303
Video: tt.giveVideoEnabled,
286304
Web: tt.giveWebEnabled,
305+
DOOH: tt.giveDOOHEnabled,
287306
}
288307

289308
result := accountChannel.GetByChannelType(tt.giveChannelType)
@@ -836,7 +855,7 @@ func TestAccountChannelIsSet(t *testing.T) {
836855
}{
837856
{
838857
name: "AccountChannelSetAllFields",
839-
givenAccountChannel: &AccountChannel{AMP: &trueBool, App: &falseBool, Video: &falseBool, Web: &falseBool},
858+
givenAccountChannel: &AccountChannel{AMP: &trueBool, App: &falseBool, Video: &falseBool, Web: &falseBool, DOOH: &falseBool},
840859
expected: true,
841860
},
842861
{

config/bidderinfo.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ type MaintainerInfo struct {
7878
type CapabilitiesInfo struct {
7979
App *PlatformInfo `yaml:"app" mapstructure:"app"`
8080
Site *PlatformInfo `yaml:"site" mapstructure:"site"`
81+
DOOH *PlatformInfo `yaml:"dooh" mapstructure:"dooh"`
8182
}
8283

8384
// PlatformInfo specifies the supported media types for a bidder.
@@ -461,7 +462,9 @@ func validateAliasCapabilities(aliasBidderInfo BidderInfo, infos BidderInfos, bi
461462
return fmt.Errorf("capabilities for alias: %s should be a subset of capabilities for parent bidder: %s", bidderName, aliasBidderInfo.AliasOf)
462463
}
463464

464-
if (aliasBidderInfo.Capabilities.App != nil && parentBidder.Capabilities.App == nil) || (aliasBidderInfo.Capabilities.Site != nil && parentBidder.Capabilities.Site == nil) {
465+
if (aliasBidderInfo.Capabilities.App != nil && parentBidder.Capabilities.App == nil) ||
466+
(aliasBidderInfo.Capabilities.Site != nil && parentBidder.Capabilities.Site == nil) ||
467+
(aliasBidderInfo.Capabilities.DOOH != nil && parentBidder.Capabilities.DOOH == nil) {
465468
return fmt.Errorf("capabilities for alias: %s should be a subset of capabilities for parent bidder: %s", bidderName, aliasBidderInfo.AliasOf)
466469
}
467470

@@ -476,6 +479,12 @@ func validateAliasCapabilities(aliasBidderInfo BidderInfo, infos BidderInfos, bi
476479
return err
477480
}
478481
}
482+
483+
if aliasBidderInfo.Capabilities.DOOH != nil && parentBidder.Capabilities.DOOH != nil {
484+
if err := isAliasPlatformInfoSubsetOfParent(*parentBidder.Capabilities.DOOH, *aliasBidderInfo.Capabilities.DOOH, bidderName, aliasBidderInfo.AliasOf); err != nil {
485+
return err
486+
}
487+
}
479488
}
480489

481490
return nil
@@ -501,8 +510,8 @@ func validateCapabilities(info *CapabilitiesInfo, bidderName string) error {
501510
return fmt.Errorf("missing required field: capabilities for adapter: %s", bidderName)
502511
}
503512

504-
if info.App == nil && info.Site == nil {
505-
return fmt.Errorf("at least one of capabilities.site or capabilities.app must exist for adapter: %s", bidderName)
513+
if info.App == nil && info.Site == nil && info.DOOH == nil {
514+
return fmt.Errorf("at least one of capabilities.site, capabilities.app, or capabilities.dooh must exist for adapter: %s", bidderName)
506515
}
507516

508517
if info.App != nil {
@@ -513,9 +522,16 @@ func validateCapabilities(info *CapabilitiesInfo, bidderName string) error {
513522

514523
if info.Site != nil {
515524
if err := validatePlatformInfo(info.Site); err != nil {
516-
return fmt.Errorf("capabilities.site failed validation: %v, for adapter: %s", err, bidderName)
525+
return fmt.Errorf("capabilities.site failed validation: %v for adapter: %s", err, bidderName)
517526
}
518527
}
528+
529+
if info.DOOH != nil {
530+
if err := validatePlatformInfo(info.DOOH); err != nil {
531+
return fmt.Errorf("capabilities.dooh failed validation: %v for adapter: %s", err, bidderName)
532+
}
533+
}
534+
519535
return nil
520536
}
521537

0 commit comments

Comments
 (0)