Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Districtm Dmx: new adapter #1209

Merged
merged 47 commits into from
Jun 3, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
0d36837
Merge pull request #1 from prebid/master
stevealliance Nov 21, 2019
a098d7c
adding DMX main file
steve-a-districtm Mar 2, 2020
255d384
adding user sync for dmx
steve-a-districtm Mar 2, 2020
c78cdcc
adding dmx in the adapter map
steve-a-districtm Mar 2, 2020
436f3a5
mapping in struct Adapter 'publisherId'
steve-a-districtm Mar 2, 2020
49bcf69
adding config in syncer.go
steve-a-districtm Mar 2, 2020
419bfc6
set config endpoint for dmx
steve-a-districtm Mar 2, 2020
f04450f
set default usersync url template
steve-a-districtm Mar 2, 2020
b3e6fbc
adding dmx to bidder.go
steve-a-districtm Mar 2, 2020
0f4e542
adding user sync test
steve-a-districtm Mar 2, 2020
08f108d
adding json bidder params
steve-a-districtm Mar 2, 2020
afb9768
adding yaml file
steve-a-districtm Mar 2, 2020
bd77380
remove fmt.Println
steve-a-districtm Mar 2, 2020
8e27b0b
adding media types app banner
steve-a-districtm Mar 2, 2020
63b61d2
adding DMX into sync test
steve-a-districtm Mar 2, 2020
572cc96
update correction required plus unit test
steve-a-districtm Mar 23, 2020
8bc4bd2
run gofmt on dmx
steve-a-districtm Mar 24, 2020
4e41153
update sellerid support in params
steve-a-districtm Apr 6, 2020
a00c90c
change setup key form publisherId to sellerId
steve-a-districtm Apr 6, 2020
9e4693d
update bidder info to main districtm mailbox
steve-a-districtm Apr 15, 2020
b53697a
run gofmt on bidders.go
steve-a-districtm Apr 15, 2020
b6530cb
update unit test to reflect change on main dmx.go
steve-a-districtm Apr 15, 2020
311e106
remove config setting inside config.go | run fmt
steve-a-districtm Apr 15, 2020
aa1dd6e
syncer_test.go update
steve-a-districtm Apr 15, 2020
465ab83
add test to confirm that site doesn't generate a panic in go
steve-a-districtm Apr 16, 2020
f906587
update request from last review (PR)
steve-a-districtm Apr 16, 2020
31d3f0b
update dmx.yaml file for video support
steve-a-districtm Apr 20, 2020
5f0339e
update support for video + testing at 88% coverage
steve-a-districtm Apr 21, 2020
3dcb2dc
update code based on last comment
steve-a-districtm Apr 22, 2020
30c595d
update idsync endpoint
steve-a-districtm Apr 22, 2020
409caec
update fetchparams to append nothing when tagid || dmxid is empty
steve-a-districtm Apr 22, 2020
f655384
Eids and Digitrust validation
steve-a-districtm Apr 23, 2020
c3f6364
create a full new instance of the App Site User value
steve-a-districtm Apr 30, 2020
c851a32
adding support for test exemplary and race
steve-a-districtm May 11, 2020
d7bb136
publisher share memory fix
steve-a-districtm May 11, 2020
9e6fe59
code removed
steve-a-districtm May 11, 2020
711e779
adding Digitrust verification 'nil'
steve-a-districtm May 12, 2020
cbbd517
update the test with empty user.ext
steve-a-districtm May 13, 2020
2b82610
remove deep copy function for performance issue
steve-a-districtm May 18, 2020
e649de1
remove custom struct for userExt
steve-a-districtm May 19, 2020
4bf0745
inforced dmxReq to be a pointer
steve-a-districtm May 27, 2020
0284310
Merge remote-tracking branch 'upstream/master'
steve-a-districtm May 29, 2020
8ed9ec3
fix code conflict for adapter_map.go
steve-a-districtm May 29, 2020
b6ed6da
update master branch to reflect code in forked master
steve-a-districtm Jun 2, 2020
2f3c122
fix conflict
stevealliance Jun 2, 2020
76372d0
Merge pull request #5 from stevealliance/fix-branch
stevealliance Jun 2, 2020
a4ac24f
update latest change for GDPR CCPA
stevealliance Jun 3, 2020
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
245 changes: 245 additions & 0 deletions adapters/dmx/dmx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
package dmx

import (
"encoding/json"
"errors"
"fmt"
"github.com/mxmCherry/openrtb"
"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/errortypes"
"github.com/prebid/prebid-server/openrtb_ext"
"github.com/prebid/prebid-server/pbs"
"net/http"
"sort"
)

type DmxAdapter struct {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
endpoint string
publisherId string
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't see publisherId in this struct being used for anything? It should not belong there anyway, since there will be only one instance of the DmxAdapter across all requests, and I imagine that publisherId is more dynamic than that.

Copy link
Contributor

Choose a reason for hiding this comment

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

@stevealliance This comment needs to be addressed.

}

func New(text string) error {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
return &errorString{text}
}

// errorString is a trivial implementation of error.
type errorString struct {
s string
}

func (e *errorString) Error() string {
return e.s
}

func NewDmxBidder(endpoint string, publisher_id string) *DmxAdapter {
return &DmxAdapter{endpoint: endpoint, publisherId: publisher_id}
}

type dmxBidder struct {
Bidder dmxExt `json:"bidder"`
}

type dmxUser struct {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
User *openrtb.User `json:"user"`
}

type dmxExt struct {
PublisherId string `json:"publisher_id,omitempty"`
}

type dmxBanner struct {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
Banner *openrtb.Banner `json:"banner"`
}

type dmxSize struct {
W uint64
H uint64
S uint64
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
}

type DmxSize []dmxSize
stevealliance marked this conversation as resolved.
Show resolved Hide resolved

func (a DmxSize) Len() int {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
return len(a)
}

func (a DmxSize) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}

func (a DmxSize) Less(i, j int) bool {
return a[i].S > a[j].S
}

func Remove(toBeRemove []openrtb.Format, a DmxSize) (dmx DmxSize) {
for _, value := range toBeRemove {
for _, dmxValue := range a {
if dmxValue.H == value.H && dmxValue.W == value.W {
//fmt.Println("true")
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
dmx = append(dmx, dmxValue)
}
}
}
return
}

var CheckTopSizes = []dmxSize{
{300, 250, 100},
{728, 90, 95},
{320, 50, 90},
{160, 600, 88},
{300, 600, 85},
{300, 50, 80},
{970, 250, 75},
{970, 90, 70},
}

func (adapter *DmxAdapter) MakeRequests(request *openrtb.BidRequest, req *adapters.ExtraRequestInfo) (reqsBidder []*adapters.RequestData, errs []error) {
var dmxImp dmxBidder
var imps []openrtb.Imp
//var userParams *dmxUser
if err := json.Unmarshal(request.Imp[0].Ext, &dmxImp); err != nil {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
errs = append(errs, err)
}

//fmt.Println(request.User)
if request.User != nil {
if request.User.BuyerUID != "" {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
request.User.ID = request.User.BuyerUID

}
}

for _, inst := range request.Imp {
var banner openrtb.Banner
var ins openrtb.Imp
//for _, insbanner := range inst.Banner.Format {
banner = openrtb.Banner{
W: &inst.Banner.Format[0].W,
Copy link
Contributor

Choose a reason for hiding this comment

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

Please verify there is at least 1 Format in the collection before indexing it via inst.Banner.Format[0].

H: &inst.Banner.Format[0].H,
Format: inst.Banner.Format,
}
nSize := Remove(inst.Banner.Format, CheckTopSizes)
sort.Sort(DmxSize(nSize))
if inst.Banner.Format[0].W != 0 {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
banner.W = &nSize[0].W
}
if inst.Banner.Format[0].H != 0 {
banner.H = &nSize[0].H
}

var intVal int8
intVal = 1
ins = openrtb.Imp{
ID: inst.ID,
Banner: &banner,
Ext: inst.Ext,
Secure: &intVal,
}
imps = append(imps, ins)

}

request.Imp = imps

if dmxImp.Bidder.PublisherId != "" {
request.Site.Publisher = &openrtb.Publisher{ID: dmxImp.Bidder.PublisherId}
} else {
if request.Site.Publisher != nil {
request.Site.Publisher.ID = adapter.publisherId
}
}

if request.App != nil {
request.Site = nil
request.App.Publisher = &openrtb.Publisher{ID: dmxImp.Bidder.PublisherId}
}

oJson, _ := json.Marshal(request)
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
headers := http.Header{}
headers.Add("Content-Type", "Application/json;charset=utf-8")
reqBidder := &adapters.RequestData{
Method: "POST",
Uri: adapter.endpoint, //adapter.endpoint,
Body: oJson,
Headers: headers,
}

if request.User == nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider simplifying the case here with a single if clause.

if request.App == nil {
return nil, []error{errors.New("no user Id only app send request")}
}
}

reqsBidder = append(reqsBidder, reqBidder)
return
}

func (adapter *DmxAdapter) MakeBids(request *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
var errs []error

if http.StatusNoContent == response.StatusCode {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
return nil, []error{&errortypes.BadInput{
Message: fmt.Sprintf("No content to be return"),
}}
}

if http.StatusBadRequest == response.StatusCode {
return nil, []error{&errortypes.BadInput{
Message: fmt.Sprintf("Bad formated request"),
}}
}

if http.StatusOK != response.StatusCode {
return nil, []error{&errortypes.BadInput{
Message: fmt.Sprintf("Something is really wrong"),
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
}}
}

var bidResp openrtb.BidResponse

if err := json.Unmarshal(response.Body, &bidResp); err != nil {
return nil, []error{err}
}

bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)

for _, sb := range bidResp.SeatBid {
for i := range sb.Bid {
bidType, err := getMediaTypeForImp(sb.Bid[i].ImpID, request.Imp)
if err != nil {
errs = append(errs, err)
} else {
b := &adapters.TypedBid{
Bid: &sb.Bid[i],
BidType: bidType,
}
bidResponse.Bids = append(bidResponse.Bids, b)
}
}
}
return bidResponse, errs

return nil, errs
}

func getMediaTypeForImp(impID string, imps []openrtb.Imp) (openrtb_ext.BidType, error) {
mediaType := openrtb_ext.BidTypeBanner
for _, imp := range imps {
if imp.ID == impID {
if imp.Banner == nil && imp.Video != nil {
mediaType = openrtb_ext.BidTypeVideo
}
return mediaType, nil
}
}

// This shouldnt happen. Lets handle it just incase by returning an error.
return "", &errortypes.BadInput{
Message: fmt.Sprintf("Failed to find impression \"%s\" ", impID),
}
}

func getCookieInfo(request *pbs.PBSRequest) {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved

}
12 changes: 12 additions & 0 deletions adapters/dmx/usersync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dmx

import (
"text/template"

"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/usersync"
)

func NewDmxSyncer(temp *template.Template) usersync.Usersyncer {
return adapters.NewSyncer("dmx", 144, temp, adapters.SyncTypeRedirect)
}
19 changes: 19 additions & 0 deletions adapters/dmx/usersync_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package dmx

import (
"testing"
"text/template"

"github.com/stretchr/testify/assert"
)

func TestDmxSyncer(t *testing.T) {
temp := template.Must(template.New("sync-template").Parse("https://cdn.districtm.io/ids/?sellerid=10007"))
Copy link
Contributor

Choose a reason for hiding this comment

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

We've updated the template for this test. Did you get this old style from a doc we forgot to update?

syncer := NewDmxSyncer(temp)
syncInfo, err := syncer.GetUsersyncInfo("", "")
assert.NoError(t, err)
assert.Equal(t, "https://cdn.districtm.io/ids/?sellerid=10007", syncInfo.URL)
assert.Equal(t, "redirect", syncInfo.Type)
assert.EqualValues(t, 144, syncer.GDPRVendorID())
assert.Equal(t, false, syncInfo.SupportCORS)
}
6 changes: 5 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ type Adapter struct {
PlatformID string `mapstructure:"platform_id"`
AppID string `mapstructure:"app_id"`
AppSecret string `mapstructure:"app_secret"`

// needed for district m DMX
PublisherId string `mapstructure:"publisher_id"`
Copy link
Contributor

Choose a reason for hiding this comment

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

Please consider using ExtraAdapterInfo for bidder specific configs. We added that recently to avoid many one-off config entries.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, best to avoid one off additions to adapter configs.

}

// validateAdapterEndpoint makes sure that an adapter has a valid endpoint
Expand Down Expand Up @@ -486,6 +489,7 @@ func (cfg *Configuration) setDerivedDefaults() {
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderConsumable, "https://e.serverbid.com/udb/9969/match?gdpr={{.GDPR}}&euconsent={{.GDPRConsent}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dconsumable%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderConversant, "https://prebid-match.dotomi.com/prebid/match?rurl="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dconversant%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderDatablocks, "https://search.v5prebid.datablocks.net/s2ssync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&r="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Ddatablocks%26gdpr%3D%24%7Bgdpr%7D%26gdpr_consent%3D%24%7Bgdpr_consent%7D%26uid%3D%24%7Buid%7D")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderDmx, "https://cdn.districtm.io/ids/?sellerid="+cfg.Adapters[string(openrtb_ext.BidderDmx)].PublisherId+"&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}")
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderEmxDigital, "https://cs.emxdgt.com/um?ssp=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Demx_digital%26uid%3D%24UID")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderEPlanning, "https://ads.us.e-planning.net/uspd/1/?du=https%3A%2F%2Fads.us.e-planning.net%2Fgetuid%2F1%2F5a1ad71d2d53a0f5%3F"+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Deplanning%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
// openrtb_ext.BidderFacebook doesn't have a good default.
Expand Down Expand Up @@ -650,7 +654,7 @@ func SetupViper(v *viper.Viper, filename string) {
// for them and specify all the parameters they need for them to work correctly.
v.SetDefault("adapters.audiencenetwork.disabled", true)
v.SetDefault("adapters.rubicon.disabled", true)

v.SetDefault("adapters.dmx.endpoint", "https://dmx.districtm.io/b/v2")
v.SetDefault("adapters.adtelligent.endpoint", "http://hb.adtelligent.com/auction")
v.SetDefault("adapters.adform.endpoint", "http://adx.adform.net/adx")
v.SetDefault("adapters.appnexus.endpoint", "http://ib.adnxs.com/openrtb2") // Docs: https://wiki.appnexus.com/display/supply/Incoming+Bid+Request+from+SSPs
Expand Down
2 changes: 2 additions & 0 deletions exchange/adapter_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/prebid/prebid-server/adapters/consumable"
"github.com/prebid/prebid-server/adapters/conversant"
"github.com/prebid/prebid-server/adapters/datablocks"
"github.com/prebid/prebid-server/adapters/dmx"
"github.com/prebid/prebid-server/adapters/emx_digital"
"github.com/prebid/prebid-server/adapters/engagebdr"
"github.com/prebid/prebid-server/adapters/eplanning"
Expand Down Expand Up @@ -73,6 +74,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter
openrtb_ext.BidderBrightroll: brightroll.NewBrightrollBidder(cfg.Adapters[string(openrtb_ext.BidderBrightroll)].Endpoint),
openrtb_ext.BidderConsumable: consumable.NewConsumableBidder(cfg.Adapters[string(openrtb_ext.BidderConsumable)].Endpoint),
openrtb_ext.BidderDatablocks: datablocks.NewDatablocksBidder(cfg.Adapters[string(openrtb_ext.BidderDatablocks)].Endpoint),
openrtb_ext.BidderDmx: dmx.NewDmxBidder(cfg.Adapters[string(openrtb_ext.BidderDmx)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderDmx)].PublisherId),
openrtb_ext.BidderEngageBDR: engagebdr.NewEngageBDRBidder(client, cfg.Adapters[string(openrtb_ext.BidderEngageBDR)].Endpoint),
openrtb_ext.BidderEmxDigital: emx_digital.NewEmxDigitalBidder(cfg.Adapters[string(openrtb_ext.BidderEmxDigital)].Endpoint),
openrtb_ext.BidderEPlanning: eplanning.NewEPlanningBidder(client, cfg.Adapters[string(openrtb_ext.BidderEPlanning)].Endpoint),
Expand Down
2 changes: 2 additions & 0 deletions openrtb_ext/bidders.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const (
BidderConsumable BidderName = "consumable"
BidderConversant BidderName = "conversant"
BidderDatablocks BidderName = "datablocks"
BidderDmx BidderName = "dmx"
BidderEmxDigital BidderName = "emx_digital"
BidderEPlanning BidderName = "eplanning"
BidderFacebook BidderName = "audienceNetwork"
Expand Down Expand Up @@ -84,6 +85,7 @@ var BidderMap = map[string]BidderName{
"consumable": BidderConsumable,
"conversant": BidderConversant,
"datablocks": BidderDatablocks,
"dmx": BidderDmx,
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
"emx_digital": BidderEmxDigital,
"eplanning": BidderEPlanning,
"gamma": BidderGamma,
Expand Down
9 changes: 9 additions & 0 deletions static/bidder-info/dmx.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
maintainer:
email: "[email protected]"
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious. Do you work for DistrictM?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm asking because you're using a personal email address. It's preferable to be a work email address or a work support mailing list.

capabilities:
site:
mediaTypes:
- banner
SyntaxNode marked this conversation as resolved.
Show resolved Hide resolved
app:
mediaTypes:
- banner
22 changes: 22 additions & 0 deletions static/bidder-params/dmx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "District M DMX Adapter Params",
"description": "A schema which validates params accepted by the DMX adapter",
"type": "object",
"properties": {
"memberid" : {
"type": "string",
"description": "Represent boost MemberId from districtm UI"
},
"tagid": {
"type": "string",
"description": "Represent the placement ID, this value is optional"
},
"bidfloor": {
"type": "string",
"description": "The minimum price acceptable for a bid"
}
},

"required": ["memberid"]
}
2 changes: 2 additions & 0 deletions usersync/usersyncers/syncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/prebid/prebid-server/adapters/consumable"
"github.com/prebid/prebid-server/adapters/conversant"
"github.com/prebid/prebid-server/adapters/datablocks"
"github.com/prebid/prebid-server/adapters/dmx"
"github.com/prebid/prebid-server/adapters/emx_digital"
"github.com/prebid/prebid-server/adapters/engagebdr"
"github.com/prebid/prebid-server/adapters/eplanning"
Expand Down Expand Up @@ -73,6 +74,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
insertIntoMap(cfg, syncers, openrtb_ext.BidderConsumable, consumable.NewConsumableSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderConversant, conversant.NewConversantSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderDatablocks, datablocks.NewDatablocksSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderDmx, dmx.NewDmxSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderEmxDigital, emx_digital.NewEMXDigitalSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderEPlanning, eplanning.NewEPlanningSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderFacebook, audienceNetwork.NewFacebookSyncer)
Expand Down
1 change: 1 addition & 0 deletions usersync/usersyncers/syncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func TestNewSyncerMap(t *testing.T) {
string(openrtb_ext.BidderConsumable): syncConfig,
string(openrtb_ext.BidderConversant): syncConfig,
string(openrtb_ext.BidderDatablocks): syncConfig,
string(openrtb_ext.BidderDmx): syncConfig,
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
string(openrtb_ext.BidderEmxDigital): syncConfig,
string(openrtb_ext.BidderEPlanning): syncConfig,
string(openrtb_ext.BidderGrid): syncConfig,
Expand Down