From 98860a125da713b902c5b11a06b78e1f0765c056 Mon Sep 17 00:00:00 2001 From: kmdevops Date: Wed, 27 Sep 2023 16:41:38 +0200 Subject: [PATCH] DXKulture adapter --- adapters/dxkulture/dxkulture.go | 170 ++++++++++++++++++ adapters/dxkulture/dxkulture_test.go | 17 ++ .../dxkulturetest/exemplary/banner.json | 144 +++++++++++++++ .../exemplary/empty-site-domain-ref.json | 142 +++++++++++++++ .../dxkulturetest/exemplary/ipv6.json | 142 +++++++++++++++ .../exemplary/video-test-request.json | 154 ++++++++++++++++ .../dxkulturetest/exemplary/video.json | 152 ++++++++++++++++ .../supplemental/invalid-imp-ext-bidder.json | 40 +++++ .../supplemental/invalid-imp-ext.json | 38 ++++ .../supplemental/invalid-response.json | 113 ++++++++++++ .../dxkulturetest/supplemental/no-mtype.json | 142 +++++++++++++++ .../supplemental/status-code-bad-request.json | 112 ++++++++++++ .../supplemental/status-code-no-content.json | 108 +++++++++++ .../supplemental/status-code-other-error.json | 112 ++++++++++++ adapters/dxkulture/params_test.go | 53 ++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_dxkulture.go | 7 + static/bidder-info/dxkulture.yaml | 16 ++ static/bidder-params/dxkulture.json | 20 +++ 20 files changed, 1686 insertions(+) create mode 100644 adapters/dxkulture/dxkulture.go create mode 100644 adapters/dxkulture/dxkulture_test.go create mode 100644 adapters/dxkulture/dxkulturetest/exemplary/banner.json create mode 100644 adapters/dxkulture/dxkulturetest/exemplary/empty-site-domain-ref.json create mode 100644 adapters/dxkulture/dxkulturetest/exemplary/ipv6.json create mode 100644 adapters/dxkulture/dxkulturetest/exemplary/video-test-request.json create mode 100644 adapters/dxkulture/dxkulturetest/exemplary/video.json create mode 100644 adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext-bidder.json create mode 100644 adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext.json create mode 100644 adapters/dxkulture/dxkulturetest/supplemental/invalid-response.json create mode 100644 adapters/dxkulture/dxkulturetest/supplemental/no-mtype.json create mode 100644 adapters/dxkulture/dxkulturetest/supplemental/status-code-bad-request.json create mode 100644 adapters/dxkulture/dxkulturetest/supplemental/status-code-no-content.json create mode 100644 adapters/dxkulture/dxkulturetest/supplemental/status-code-other-error.json create mode 100644 adapters/dxkulture/params_test.go create mode 100644 openrtb_ext/imp_dxkulture.go create mode 100644 static/bidder-info/dxkulture.yaml create mode 100644 static/bidder-params/dxkulture.json diff --git a/adapters/dxkulture/dxkulture.go b/adapters/dxkulture/dxkulture.go new file mode 100644 index 00000000000..5347c71a303 --- /dev/null +++ b/adapters/dxkulture/dxkulture.go @@ -0,0 +1,170 @@ +package dxkulture + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/openrtb_ext" + + "github.com/prebid/openrtb/v19/openrtb2" +) + +var markupTypeToBidType = map[openrtb2.MarkupType]openrtb_ext.BidType{ + openrtb2.MarkupBanner: openrtb_ext.BidTypeBanner, + openrtb2.MarkupVideo: openrtb_ext.BidTypeVideo, +} + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the DXKulture adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + impressions := request.Imp + + adapterRequests := make([]*adapters.RequestData, 0, len(impressions)) + var errs []error + + for _, impression := range impressions { + impExt, err := parseExt(&impression) + if err != nil { + errs = append(errs, err) + continue + } + + request.Imp = []openrtb2.Imp{impression} + body, err := json.Marshal(request) + if err != nil { + errs = append(errs, err) + continue + } + + if request.Test == 1 { + impExt.PublisherId = "test" + } + + params := url.Values{} + params.Add("publisher_id", impExt.PublisherId) + params.Add("placement_id", impExt.PlacementId) + + adapterRequests = append(adapterRequests, &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint + "?" + params.Encode(), + Body: body, + Headers: getHeaders(request), + }) + } + + request.Imp = impressions + return adapterRequests, errs +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var ortbResponse openrtb2.BidResponse + err := json.Unmarshal(response.Body, &ortbResponse) + if err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: "Bad Server Response", + }} + } + + var bidErrors []error + + bidderResponse := adapters.NewBidderResponseWithBidsCapacity(1) + for _, seatBid := range ortbResponse.SeatBid { + for i := range seatBid.Bid { + bid := seatBid.Bid[i] + bidType, err := getBidType(&bid) + if err != nil { + bidErrors = append(bidErrors, err) + continue + } + + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + }) + } + } + + return bidderResponse, bidErrors +} + +func getBidType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + if bidType, ok := markupTypeToBidType[bid.MType]; ok { + return bidType, nil + } + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unsupported MType %d", bid.MType), + } +} + +func parseExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpDXKulture, error) { + var bidderExt adapters.ExtImpBidder + + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err), + } + } + + impExt := openrtb_ext.ExtImpDXKulture{} + err := json.Unmarshal(bidderExt.Bidder, &impExt) + if err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Ignoring imp id=%s, error while decoding impExt, err: %s", imp.ID, err), + } + } + + return &impExt, nil +} + +func getHeaders(request *openrtb2.BidRequest) http.Header { + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + headers.Add("X-Openrtb-Version", "2.5") + + if request.Site != nil { + if request.Site.Ref != "" { + headers.Set("Referer", request.Site.Ref) + } + if request.Site.Domain != "" { + headers.Add("Origin", request.Site.Domain) + } + } + + if request.Device != nil { + if len(request.Device.UA) > 0 { + headers.Add("User-Agent", request.Device.UA) + } + + if len(request.Device.IPv6) > 0 { + headers.Add("X-Forwarded-For", request.Device.IPv6) + } + + if len(request.Device.IP) > 0 { + headers.Add("X-Forwarded-For", request.Device.IP) + } + } + return headers +} diff --git a/adapters/dxkulture/dxkulture_test.go b/adapters/dxkulture/dxkulture_test.go new file mode 100644 index 00000000000..9b2da4f27ab --- /dev/null +++ b/adapters/dxkulture/dxkulture_test.go @@ -0,0 +1,17 @@ +package dxkulture + +import ( + "testing" + + "github.com/prebid/prebid-server/config" + + "github.com/prebid/prebid-server/adapters/adapterstest" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder("dxkulture", config.Adapter{Endpoint: "https://ads.kulture.media/pbs"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + adapterstest.RunJSONBidderTest(t, "dxkulturetest", bidder) +} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/banner.json b/adapters/dxkulture/dxkulturetest/exemplary/banner.json new file mode 100644 index 00000000000..3b84881fc67 --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/exemplary/banner.json @@ -0,0 +1,144 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Referer": [ + "http://site.com/ref" + ], + "Origin": [ + "site.com" + ], + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123", + "body": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 1 + } + ], + "seat": "dxkulture" + } + ], + "bidid": "test-request-id", + "id": "test-request-id" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/empty-site-domain-ref.json b/adapters/dxkulture/dxkulturetest/exemplary/empty-site-domain-ref.json new file mode 100644 index 00000000000..630467ce96b --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/exemplary/empty-site-domain-ref.json @@ -0,0 +1,142 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "page": "http://site.com/page" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123", + "body": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "page": "http://site.com/page" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 2 + } + ], + "seat": "dxkulture" + } + ], + "bidid": "test-request-id", + "id": "test-request-id" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/ipv6.json b/adapters/dxkulture/dxkulturetest/exemplary/ipv6.json new file mode 100644 index 00000000000..58f7e7fdf2c --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/exemplary/ipv6.json @@ -0,0 +1,142 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ipv6": "2001:0000:130F:0000:0000:09C0:876A:130B" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "page": "http://site.com/page" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "2001:0000:130F:0000:0000:09C0:876A:130B" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123", + "body": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ipv6": "2001:0000:130F:0000:0000:09C0:876A:130B" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "page": "http://site.com/page" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 2 + } + ], + "seat": "dxkulture" + } + ], + "bidid": "test-request-id", + "id": "test-request-id" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/video-test-request.json b/adapters/dxkulture/dxkulturetest/exemplary/video-test-request.json new file mode 100644 index 00000000000..6a0746ad258 --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/exemplary/video-test-request.json @@ -0,0 +1,154 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "test": 1, + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Referer": [ + "http://site.com/ref" + ], + "Origin": [ + "site.com" + ], + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=test", + "body": { + "id": "test-request-id", + "test": 1, + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 2 + } + ], + "seat": "dxkulture" + } + ], + "bidid": "test-request-id", + "id": "test-request-id" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/dxkulture/dxkulturetest/exemplary/video.json b/adapters/dxkulture/dxkulturetest/exemplary/video.json new file mode 100644 index 00000000000..017dd5ea2bc --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/exemplary/video.json @@ -0,0 +1,152 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Referer": [ + "http://site.com/ref" + ], + "Origin": [ + "site.com" + ], + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123", + "body": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 2 + } + ], + "seat": "dxkulture" + } + ], + "bidid": "test-request-id", + "id": "test-request-id" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "", + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext-bidder.json b/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext-bidder.json new file mode 100644 index 00000000000..ae30b327030 --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext-bidder.json @@ -0,0 +1,40 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": "not_json" + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Ignoring imp id=test-imp-id, error while decoding impExt, err: json: cannot unmarshal string into Go value of type openrtb_ext.ExtImpDXKulture", + "comparison": "literal" + } + ] +} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext.json b/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext.json new file mode 100644 index 00000000000..2587dc216d2 --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/supplemental/invalid-imp-ext.json @@ -0,0 +1,38 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": "not_json" + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Ignoring imp id=test-imp-id, error while decoding extImpBidder, err: json: cannot unmarshal string into Go value of type adapters.ExtImpBidder", + "comparison": "literal" + } + ] +} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/invalid-response.json b/adapters/dxkulture/dxkulturetest/supplemental/invalid-response.json new file mode 100644 index 00000000000..8fff1bb0375 --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/supplemental/invalid-response.json @@ -0,0 +1,113 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Referer": [ + "http://site.com/ref" + ], + "Origin": [ + "site.com" + ], + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123", + "body": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + } + }, + "mockResponse": { + "status": 200, + "body": "body" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad Server Response", + "comparison": "literal" + } + ] +} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/no-mtype.json b/adapters/dxkulture/dxkulturetest/supplemental/no-mtype.json new file mode 100644 index 00000000000..a56200fad50 --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/supplemental/no-mtype.json @@ -0,0 +1,142 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Referer": [ + "http://site.com/ref" + ], + "Origin": [ + "site.com" + ], + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123", + "body": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "43271b2d-41c0-4093-8ba1-2105d9658e80", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id", + "adid": "2422", + "adm": "" + } + ], + "seat": "dxkulture" + } + ], + "bidid": "test-request-id", + "id": "test-request-id" + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unsupported MType 0", + "comparison": "literal" + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ] + +} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/status-code-bad-request.json b/adapters/dxkulture/dxkulturetest/supplemental/status-code-bad-request.json new file mode 100644 index 00000000000..f0f2ce2c47b --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/supplemental/status-code-bad-request.json @@ -0,0 +1,112 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Referer": [ + "http://site.com/ref" + ], + "Origin": [ + "site.com" + ], + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123", + "body": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + } + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/status-code-no-content.json b/adapters/dxkulture/dxkulturetest/supplemental/status-code-no-content.json new file mode 100644 index 00000000000..43c53f3d64c --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/supplemental/status-code-no-content.json @@ -0,0 +1,108 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Referer": [ + "http://site.com/ref" + ], + "Origin": [ + "site.com" + ], + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123", + "body": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + } + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [] +} diff --git a/adapters/dxkulture/dxkulturetest/supplemental/status-code-other-error.json b/adapters/dxkulture/dxkulturetest/supplemental/status-code-other-error.json new file mode 100644 index 00000000000..3e1b0b33c1e --- /dev/null +++ b/adapters/dxkulture/dxkulturetest/supplemental/status-code-other-error.json @@ -0,0 +1,112 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "GET", + "headers": { + "Referer": [ + "http://site.com/ref" + ], + "Origin": [ + "site.com" + ], + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "User-Agent": [ + "user-agent" + ], + "X-Forwarded-For": [ + "1.2.3.4" + ], + "X-Openrtb-Version": [ + "2.5" + ] + }, + "uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123", + "body": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "w": 1920, + "h": 1080, + "mimes": [ + "video/x-flv", + "video/mp4" + ] + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + } + }, + "mockResponse": { + "status": 505 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 505. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/dxkulture/params_test.go b/adapters/dxkulture/params_test.go new file mode 100644 index 00000000000..838d092df8f --- /dev/null +++ b/adapters/dxkulture/params_test.go @@ -0,0 +1,53 @@ +package dxkulture + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/dxkulture.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.dxkulture + +// TestValidParams makes sure that the dxkulture schema accepts all imp.ext fields which we intend to support. +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderDXKulture, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected dxkulture params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the dxkulture schema rejects all the imp.ext fields we don't support. +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderDXKulture, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"publisherId": "pub", "placementId": "plac"}`, + `{"publisherId": "pub", "placementId": "plac", "a":1}`, +} + +var invalidParams = []string{ + `{"publisherId": "pub"}`, + `{"placementId": "plac"}`, + //malformed + `{"ub", "placementId": "plac"}`, + `{}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 395e4fbbc39..0fb84cc5898 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -75,6 +75,7 @@ import ( "github.com/prebid/prebid-server/adapters/definemedia" "github.com/prebid/prebid-server/adapters/dianomi" "github.com/prebid/prebid-server/adapters/dmx" + "github.com/prebid/prebid-server/adapters/dxkulture" evolution "github.com/prebid/prebid-server/adapters/e_volution" "github.com/prebid/prebid-server/adapters/emtv" "github.com/prebid/prebid-server/adapters/engagebdr" @@ -273,6 +274,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderDefinemedia: definemedia.Builder, openrtb_ext.BidderDianomi: dianomi.Builder, openrtb_ext.BidderDmx: dmx.Builder, + openrtb_ext.BidderDXKulture: dxkulture.Builder, openrtb_ext.BidderEmtv: emtv.Builder, openrtb_ext.BidderEmxDigital: cadentaperturemx.Builder, openrtb_ext.BidderEngageBDR: engagebdr.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index e12316f7e72..33e0204ecf5 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -95,6 +95,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderDefinemedia, BidderDianomi, BidderDmx, + BidderDXKulture, BidderEmtv, BidderEmxDigital, BidderEngageBDR, @@ -390,6 +391,7 @@ const ( BidderDefinemedia BidderName = "definemedia" BidderDianomi BidderName = "dianomi" BidderDmx BidderName = "dmx" + BidderDXKulture BidderName = "dxkulture" BidderEmtv BidderName = "emtv" BidderEmxDigital BidderName = "emx_digital" BidderEngageBDR BidderName = "engagebdr" diff --git a/openrtb_ext/imp_dxkulture.go b/openrtb_ext/imp_dxkulture.go new file mode 100644 index 00000000000..4b507c55248 --- /dev/null +++ b/openrtb_ext/imp_dxkulture.go @@ -0,0 +1,7 @@ +package openrtb_ext + +// ExtImpDXKulture defines the contract for bidrequest.imp[i].ext.prebid.bidder.dxkulture +type ExtImpDXKulture struct { + PublisherId string `json:"publisherId"` + PlacementId string `json:"placementId"` +} diff --git a/static/bidder-info/dxkulture.yaml b/static/bidder-info/dxkulture.yaml new file mode 100644 index 00000000000..1af72e9fc33 --- /dev/null +++ b/static/bidder-info/dxkulture.yaml @@ -0,0 +1,16 @@ +endpoint: "https://ads.kulture.media/pbs" +maintainer: + email: "devops@kulture.media" +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video +userSync: + redirect: + url: "https://ads.kulture.media/usync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&cb={{.RedirectURL}}" + userMacro: "$UID" diff --git a/static/bidder-params/dxkulture.json b/static/bidder-params/dxkulture.json new file mode 100644 index 00000000000..858eefd22e4 --- /dev/null +++ b/static/bidder-params/dxkulture.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "DXKulture Adapter Params", + "description": "A schema which validates params accepted by the DXKulture adapter", + "type": "object", + "properties": { + "publisherId": { + "type": "string", + "description": "The publisher id" + }, + "placementId": { + "type": "string", + "description": "The placement id" + } + }, + "required": [ + "publisherId", + "placementId" + ] +}