From 5d6c775cb34455536196b8efe12457221feb6298 Mon Sep 17 00:00:00 2001 From: nuba-io Date: Fri, 20 Mar 2026 20:42:30 +0200 Subject: [PATCH 01/13] New Adapter: Nuba (#4565) --- static/bidder-info/nuba.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 static/bidder-info/nuba.yaml diff --git a/static/bidder-info/nuba.yaml b/static/bidder-info/nuba.yaml new file mode 100644 index 00000000000..803402c68a1 --- /dev/null +++ b/static/bidder-info/nuba.yaml @@ -0,0 +1,4 @@ +aliasOf: "teqblaze" +endpoint: "https://ads.nuba.io/pserver" +maintainer: + email: "tech@nuba.io" From 1051353f0d4febcd89cb320f4554fceebb6a5ce3 Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Sat, 30 Aug 2025 23:55:16 +0300 Subject: [PATCH 02/13] Add new Adapter - DXTech --- adapters/dxtech.go | 172 ++++++++++++++++++++++++++++++++++++++++ adapters/dxtech_test.go | 17 ++++ adapters/params_test.go | 53 +++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 adapters/dxtech.go create mode 100644 adapters/dxtech_test.go create mode 100644 adapters/params_test.go diff --git a/adapters/dxtech.go b/adapters/dxtech.go new file mode 100644 index 00000000000..8d530bced58 --- /dev/null +++ b/adapters/dxtech.go @@ -0,0 +1,172 @@ +package dxtech + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" + + "github.com/prebid/openrtb/v20/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 DXTech 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), + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }) + } + + 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 := jsonutil.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.ExtImpDXTech, error) { + var bidderExt adapters.ExtImpBidder + + if err := jsonutil.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.ExtImpDXTech{} + err := jsonutil.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/dxtech_test.go b/adapters/dxtech_test.go new file mode 100644 index 00000000000..a72c05a27a5 --- /dev/null +++ b/adapters/dxtech_test.go @@ -0,0 +1,17 @@ +package dxtech + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/config" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder("dxtech", config.Adapter{Endpoint: "https://ads.dxtech.ai/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, "dxtechtest", bidder) +} diff --git a/adapters/params_test.go b/adapters/params_test.go new file mode 100644 index 00000000000..9cd1846059b --- /dev/null +++ b/adapters/params_test.go @@ -0,0 +1,53 @@ +package dxtech + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/dxtech.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.dxtech + +// TestValidParams makes sure that the dxtech 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.BidderDXTech, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected dxtech params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the dxtech 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.BidderDXTech, 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"}`, + `{}`, +} From f464c7d3ee93f2d37451683c57494a5032262995 Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Sat, 30 Aug 2025 23:56:33 +0300 Subject: [PATCH 03/13] Update and rename adapters/dxtech.go to adapters/dxtech/dxtech.go --- adapters/{ => dxtech}/dxtech.go | 1 + 1 file changed, 1 insertion(+) rename adapters/{ => dxtech}/dxtech.go (96%) diff --git a/adapters/dxtech.go b/adapters/dxtech/dxtech.go similarity index 96% rename from adapters/dxtech.go rename to adapters/dxtech/dxtech.go index 8d530bced58..986aadb0946 100644 --- a/adapters/dxtech.go +++ b/adapters/dxtech/dxtech.go @@ -170,3 +170,4 @@ func getHeaders(request *openrtb2.BidRequest) http.Header { } return headers } + From a9d9c351653337d41aa1c8b34325dd02e1641fee Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Sat, 30 Aug 2025 23:56:57 +0300 Subject: [PATCH 04/13] Update and rename adapters/dxtech_test.go to adapters/dxtech/dxtech_test.go --- adapters/{ => dxtech}/dxtech_test.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename adapters/{ => dxtech}/dxtech_test.go (100%) diff --git a/adapters/dxtech_test.go b/adapters/dxtech/dxtech_test.go similarity index 100% rename from adapters/dxtech_test.go rename to adapters/dxtech/dxtech_test.go From c7e4bd5fb38c8f9f1d1e4bb8574b657f09fab3b2 Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Sat, 30 Aug 2025 23:57:16 +0300 Subject: [PATCH 05/13] Update and rename adapters/params_test.go to adapters/dxtech/params_test.go --- adapters/{ => dxtech}/params_test.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename adapters/{ => dxtech}/params_test.go (100%) diff --git a/adapters/params_test.go b/adapters/dxtech/params_test.go similarity index 100% rename from adapters/params_test.go rename to adapters/dxtech/params_test.go From 168a23d0e224b2a2c3093213160e245b41388f5e Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Sat, 30 Aug 2025 23:58:38 +0300 Subject: [PATCH 06/13] Add files via upload --- .../dxtech/dxtechtest/exemplary/banner.json | 145 ++++++++++++++++ .../exemplary/empty-site-domain-ref.json | 143 ++++++++++++++++ .../dxtech/dxtechtest/exemplary/ipv6.json | 143 ++++++++++++++++ .../exemplary/video-test-request.json | 155 ++++++++++++++++++ .../dxtech/dxtechtest/exemplary/video.json | 153 +++++++++++++++++ .../supplemental/invalid-imp-ext-bidder.json | 40 +++++ .../supplemental/invalid-imp-ext.json | 38 +++++ .../supplemental/invalid-response.json | 114 +++++++++++++ .../dxtechtest/supplemental/no-mtype.json | 143 ++++++++++++++++ .../supplemental/status-code-bad-request.json | 113 +++++++++++++ .../supplemental/status-code-no-content.json | 109 ++++++++++++ .../supplemental/status-code-other-error.json | 113 +++++++++++++ 12 files changed, 1409 insertions(+) create mode 100644 adapters/dxtech/dxtechtest/exemplary/banner.json create mode 100644 adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json create mode 100644 adapters/dxtech/dxtechtest/exemplary/ipv6.json create mode 100644 adapters/dxtech/dxtechtest/exemplary/video-test-request.json create mode 100644 adapters/dxtech/dxtechtest/exemplary/video.json create mode 100644 adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext-bidder.json create mode 100644 adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext.json create mode 100644 adapters/dxtech/dxtechtest/supplemental/invalid-response.json create mode 100644 adapters/dxtech/dxtechtest/supplemental/no-mtype.json create mode 100644 adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json create mode 100644 adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json create mode 100644 adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json diff --git a/adapters/dxtech/dxtechtest/exemplary/banner.json b/adapters/dxtech/dxtechtest/exemplary/banner.json new file mode 100644 index 00000000000..daf099d4a1e --- /dev/null +++ b/adapters/dxtech/dxtechtest/exemplary/banner.json @@ -0,0 +1,145 @@ +{ + "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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "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": "dxtech" + } + ], + "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/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json b/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json new file mode 100644 index 00000000000..5141676cd13 --- /dev/null +++ b/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json @@ -0,0 +1,143 @@ +{ + "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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "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": "dxtech" + } + ], + "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/dxtech/dxtechtest/exemplary/ipv6.json b/adapters/dxtech/dxtechtest/exemplary/ipv6.json new file mode 100644 index 00000000000..aa3ffdb3716 --- /dev/null +++ b/adapters/dxtech/dxtechtest/exemplary/ipv6.json @@ -0,0 +1,143 @@ +{ + "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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "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": "dxtech" + } + ], + "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/dxtech/dxtechtest/exemplary/video-test-request.json b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json new file mode 100644 index 00000000000..c4f41629d04 --- /dev/null +++ b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json @@ -0,0 +1,155 @@ +{ + "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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "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": "dxtech" + } + ], + "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/dxtech/dxtechtest/exemplary/video.json b/adapters/dxtech/dxtechtest/exemplary/video.json new file mode 100644 index 00000000000..da74b46c4dd --- /dev/null +++ b/adapters/dxtech/dxtechtest/exemplary/video.json @@ -0,0 +1,153 @@ +{ + "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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "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": "dxtech" + } + ], + "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/dxtech/dxtechtest/supplemental/invalid-imp-ext-bidder.json b/adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext-bidder.json new file mode 100644 index 00000000000..549aef86ba9 --- /dev/null +++ b/adapters/dxtech/dxtechtest/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: expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext.json b/adapters/dxtech/dxtechtest/supplemental/invalid-imp-ext.json new file mode 100644 index 00000000000..fddf37a0b99 --- /dev/null +++ b/adapters/dxtech/dxtechtest/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: expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/dxtech/dxtechtest/supplemental/invalid-response.json b/adapters/dxtech/dxtechtest/supplemental/invalid-response.json new file mode 100644 index 00000000000..b03e175d0be --- /dev/null +++ b/adapters/dxtech/dxtechtest/supplemental/invalid-response.json @@ -0,0 +1,114 @@ +{ + "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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "body" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad Server Response", + "comparison": "literal" + } + ] +} diff --git a/adapters/dxtech/dxtechtest/supplemental/no-mtype.json b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json new file mode 100644 index 00000000000..1b3204e6655 --- /dev/null +++ b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json @@ -0,0 +1,143 @@ +{ + "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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "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": "dxtech" + } + ], + "bidid": "test-request-id", + "id": "test-request-id" + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unsupported MType 0", + "comparison": "literal" + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ] + +} diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json b/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json new file mode 100644 index 00000000000..a83c1b1667b --- /dev/null +++ b/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json b/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json new file mode 100644 index 00000000000..e2c2aa79f62 --- /dev/null +++ b/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json @@ -0,0 +1,109 @@ +{ + "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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [] +} diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json b/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json new file mode 100644 index 00000000000..90156ad9395 --- /dev/null +++ b/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.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.dxtech.ai/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" + } + }, + "impIDs":["test-imp-id"] + }, + "mockResponse": { + "status": 505 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 505. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} From aee5760885ed1d7c35db54361c3e76e95978acf1 Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Sun, 31 Aug 2025 00:10:24 +0300 Subject: [PATCH 07/13] New adapter - DXTech --- adapters/dxtech/dxtech.go | 345 +++++++++++++++---------------- adapters/dxtech/dxtech_test.go | 34 +-- adapters/dxtech/params_test.go | 106 +++++----- exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_dxtech.go | 7 + static/bidder-info/dxtech.yaml | 16 ++ static/bidder-params/dxtech.json | 20 ++ 8 files changed, 289 insertions(+), 243 deletions(-) create mode 100644 openrtb_ext/imp_dxtech.go create mode 100644 static/bidder-info/dxtech.yaml create mode 100644 static/bidder-params/dxtech.json diff --git a/adapters/dxtech/dxtech.go b/adapters/dxtech/dxtech.go index 986aadb0946..30ee116a25f 100644 --- a/adapters/dxtech/dxtech.go +++ b/adapters/dxtech/dxtech.go @@ -1,173 +1,172 @@ -package dxtech - -import ( - "encoding/json" - "fmt" - "net/http" - "net/url" - - "github.com/prebid/prebid-server/v3/adapters" - "github.com/prebid/prebid-server/v3/config" - "github.com/prebid/prebid-server/v3/errortypes" - "github.com/prebid/prebid-server/v3/openrtb_ext" - "github.com/prebid/prebid-server/v3/util/jsonutil" - - "github.com/prebid/openrtb/v20/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 DXTech 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), - ImpIDs: openrtb_ext.GetImpIDs(request.Imp), - }) - } - - 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 := jsonutil.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.ExtImpDXTech, error) { - var bidderExt adapters.ExtImpBidder - - if err := jsonutil.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.ExtImpDXTech{} - err := jsonutil.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 -} - +package dxtech + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "github.com/prebid/prebid-server/v4/adapters" + "github.com/prebid/prebid-server/v4/config" + "github.com/prebid/prebid-server/v4/errortypes" + "github.com/prebid/prebid-server/v4/openrtb_ext" + "github.com/prebid/prebid-server/v4/util/jsonutil" + + "github.com/prebid/openrtb/v20/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 DXTech 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), + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }) + } + + 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 := jsonutil.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.ExtImpDXTech, error) { + var bidderExt adapters.ExtImpBidder + + if err := jsonutil.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.ExtImpDXTech{} + err := jsonutil.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/dxtech/dxtech_test.go b/adapters/dxtech/dxtech_test.go index a72c05a27a5..b911bcecd85 100644 --- a/adapters/dxtech/dxtech_test.go +++ b/adapters/dxtech/dxtech_test.go @@ -1,17 +1,17 @@ -package dxtech - -import ( - "testing" - - "github.com/prebid/prebid-server/v3/config" - - "github.com/prebid/prebid-server/v3/adapters/adapterstest" -) - -func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder("dxtech", config.Adapter{Endpoint: "https://ads.dxtech.ai/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, "dxtechtest", bidder) -} +package dxtech + +import ( + "testing" + + "github.com/prebid/prebid-server/v4/config" + + "github.com/prebid/prebid-server/v4/adapters/adapterstest" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder("dxtech", config.Adapter{Endpoint: "https://ads.dxtech.ai/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, "dxtechtest", bidder) +} diff --git a/adapters/dxtech/params_test.go b/adapters/dxtech/params_test.go index 9cd1846059b..6a9f9483cc6 100644 --- a/adapters/dxtech/params_test.go +++ b/adapters/dxtech/params_test.go @@ -1,53 +1,53 @@ -package dxtech - -import ( - "encoding/json" - "testing" - - "github.com/prebid/prebid-server/v3/openrtb_ext" -) - -// This file actually intends to test static/bidder-params/dxtech.json -// -// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.dxtech - -// TestValidParams makes sure that the dxtech 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.BidderDXTech, json.RawMessage(validParam)); err != nil { - t.Errorf("Schema rejected dxtech params: %s", validParam) - } - } -} - -// TestInvalidParams makes sure that the dxtech 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.BidderDXTech, 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"}`, - `{}`, -} +package dxtech + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v4/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/dxtech.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.dxtech + +// TestValidParams makes sure that the dxtech 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.BidderDXTech, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected dxtech params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the dxtech 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.BidderDXTech, 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 630fbe348b9..fe820007dd9 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -97,6 +97,7 @@ import ( "github.com/prebid/prebid-server/v4/adapters/displayio" "github.com/prebid/prebid-server/v4/adapters/dmx" "github.com/prebid/prebid-server/v4/adapters/driftpixel" + "github.com/prebid/prebid-server/v4/adapters/dxtech" evolution "github.com/prebid/prebid-server/v4/adapters/e_volution" "github.com/prebid/prebid-server/v4/adapters/edge226" "github.com/prebid/prebid-server/v4/adapters/elementaltv" @@ -364,6 +365,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderDisplayio: displayio.Builder, openrtb_ext.BidderEdge226: edge226.Builder, openrtb_ext.BidderDmx: dmx.Builder, + openrtb_ext.BidderDXTech: dxtech.Builder, openrtb_ext.BidderDriftPixel: driftpixel.Builder, openrtb_ext.BidderElementalTV: elementaltv.Builder, openrtb_ext.BidderEmtv: emtv.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 1b61ff724e2..9d9115cac62 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -113,6 +113,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderDisplayio, BidderEdge226, BidderDmx, + BidderDXTech, BidderDriftPixel, BidderElementalTV, BidderEmtv, @@ -487,6 +488,7 @@ const ( BidderDisplayio BidderName = "displayio" BidderEdge226 BidderName = "edge226" BidderDmx BidderName = "dmx" + BidderDXTech BidderName = "dxtech" BidderDriftPixel BidderName = "driftpixel" BidderElementalTV BidderName = "elementaltv" BidderEmtv BidderName = "emtv" diff --git a/openrtb_ext/imp_dxtech.go b/openrtb_ext/imp_dxtech.go new file mode 100644 index 00000000000..5022dfe2de3 --- /dev/null +++ b/openrtb_ext/imp_dxtech.go @@ -0,0 +1,7 @@ +package openrtb_ext + +// ExtImpDXTech defines the contract for bidrequest.imp[i].ext.prebid.bidder.dxtech +type ExtImpDXTech struct { + PublisherId string `json:"publisherId"` + PlacementId string `json:"placementId"` +} diff --git a/static/bidder-info/dxtech.yaml b/static/bidder-info/dxtech.yaml new file mode 100644 index 00000000000..26d9864d0d2 --- /dev/null +++ b/static/bidder-info/dxtech.yaml @@ -0,0 +1,16 @@ +endpoint: "https://ads.dxtech.ai/pbs" +maintainer: + email: "support@dxtech.ai" +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video +userSync: + redirect: + url: "https://sync.dxtech.ai/usync-pbs?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&cb={{.RedirectURL}}" + userMacro: "$UID" diff --git a/static/bidder-params/dxtech.json b/static/bidder-params/dxtech.json new file mode 100644 index 00000000000..1003211c2fc --- /dev/null +++ b/static/bidder-params/dxtech.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "DXTech Adapter Params", + "description": "A schema which validates params accepted by the DXTech adapter", + "type": "object", + "properties": { + "publisherId": { + "type": "string", + "description": "The publisher id" + }, + "placementId": { + "type": "string", + "description": "The placement id" + } + }, + "required": [ + "publisherId", + "placementId" + ] +} From d9aac83a1269a1d2bf482416a1ae54c041d2bffd Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Mon, 8 Sep 2025 23:23:47 +0300 Subject: [PATCH 08/13] add min length --- static/bidder-params/dxtech.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/static/bidder-params/dxtech.json b/static/bidder-params/dxtech.json index 1003211c2fc..1e9cb29137e 100644 --- a/static/bidder-params/dxtech.json +++ b/static/bidder-params/dxtech.json @@ -6,10 +6,12 @@ "properties": { "publisherId": { "type": "string", + "minLength": 1, "description": "The publisher id" }, "placementId": { "type": "string", + "minLength": 1, "description": "The placement id" } }, From c3d1838092c08587ffdcbf10beba3c9bae114a34 Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Mon, 8 Sep 2025 23:24:40 +0300 Subject: [PATCH 09/13] change get to post --- adapters/dxtech/dxtechtest/exemplary/banner.json | 2 +- adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json | 2 +- adapters/dxtech/dxtechtest/exemplary/ipv6.json | 2 +- adapters/dxtech/dxtechtest/exemplary/video-test-request.json | 2 +- adapters/dxtech/dxtechtest/exemplary/video.json | 2 +- adapters/dxtech/dxtechtest/supplemental/invalid-response.json | 2 +- adapters/dxtech/dxtechtest/supplemental/no-mtype.json | 2 +- .../dxtech/dxtechtest/supplemental/status-code-bad-request.json | 2 +- .../dxtech/dxtechtest/supplemental/status-code-no-content.json | 2 +- .../dxtech/dxtechtest/supplemental/status-code-other-error.json | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/adapters/dxtech/dxtechtest/exemplary/banner.json b/adapters/dxtech/dxtechtest/exemplary/banner.json index daf099d4a1e..f443c8995d6 100644 --- a/adapters/dxtech/dxtechtest/exemplary/banner.json +++ b/adapters/dxtech/dxtechtest/exemplary/banner.json @@ -33,7 +33,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Referer": [ "http://site.com/ref" diff --git a/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json b/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json index 5141676cd13..83900b6a356 100644 --- a/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json +++ b/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json @@ -35,7 +35,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Accept": [ "application/json" diff --git a/adapters/dxtech/dxtechtest/exemplary/ipv6.json b/adapters/dxtech/dxtechtest/exemplary/ipv6.json index aa3ffdb3716..e74a939e3c1 100644 --- a/adapters/dxtech/dxtechtest/exemplary/ipv6.json +++ b/adapters/dxtech/dxtechtest/exemplary/ipv6.json @@ -35,7 +35,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Accept": [ "application/json" diff --git a/adapters/dxtech/dxtechtest/exemplary/video-test-request.json b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json index c4f41629d04..7dbfdccd8e8 100644 --- a/adapters/dxtech/dxtechtest/exemplary/video-test-request.json +++ b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json @@ -38,7 +38,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Referer": [ "http://site.com/ref" diff --git a/adapters/dxtech/dxtechtest/exemplary/video.json b/adapters/dxtech/dxtechtest/exemplary/video.json index da74b46c4dd..4d29b88aad4 100644 --- a/adapters/dxtech/dxtechtest/exemplary/video.json +++ b/adapters/dxtech/dxtechtest/exemplary/video.json @@ -37,7 +37,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Referer": [ "http://site.com/ref" diff --git a/adapters/dxtech/dxtechtest/supplemental/invalid-response.json b/adapters/dxtech/dxtechtest/supplemental/invalid-response.json index b03e175d0be..546e260becf 100644 --- a/adapters/dxtech/dxtechtest/supplemental/invalid-response.json +++ b/adapters/dxtech/dxtechtest/supplemental/invalid-response.json @@ -37,7 +37,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Referer": [ "http://site.com/ref" diff --git a/adapters/dxtech/dxtechtest/supplemental/no-mtype.json b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json index 1b3204e6655..cfcb1033e6b 100644 --- a/adapters/dxtech/dxtechtest/supplemental/no-mtype.json +++ b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json @@ -37,7 +37,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Referer": [ "http://site.com/ref" diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json b/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json index a83c1b1667b..c53d6d7e6b7 100644 --- a/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json +++ b/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json @@ -37,7 +37,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Referer": [ "http://site.com/ref" diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json b/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json index e2c2aa79f62..64dd93e17dc 100644 --- a/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json +++ b/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json @@ -37,7 +37,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Referer": [ "http://site.com/ref" diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json b/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json index 90156ad9395..5e3a58968d0 100644 --- a/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json +++ b/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json @@ -37,7 +37,7 @@ "httpCalls": [ { "expectedRequest": { - "method": "GET", + "method": "POST", "headers": { "Referer": [ "http://site.com/ref" From d564eb8f2c2ec26e03cc91f0dbc04768bbd84552 Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Mon, 8 Sep 2025 23:25:15 +0300 Subject: [PATCH 10/13] fix some issues --- adapters/dxtech/dxtech.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/adapters/dxtech/dxtech.go b/adapters/dxtech/dxtech.go index 30ee116a25f..ab5bcf28201 100644 --- a/adapters/dxtech/dxtech.go +++ b/adapters/dxtech/dxtech.go @@ -1,7 +1,6 @@ package dxtech import ( - "encoding/json" "fmt" "net/http" "net/url" @@ -46,7 +45,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E } request.Imp = []openrtb2.Imp{impression} - body, err := json.Marshal(request) + body, err := jsonutil.Marshal(request) if err != nil { errs = append(errs, err) continue @@ -142,30 +141,30 @@ func parseExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpDXTech, error) { 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") + headers.Set("Content-Type", "application/json;charset=utf-8") + headers.Set("Accept", "application/json") + headers.Set("X-Openrtb-Version", "2.6") if request.Site != nil { if request.Site.Ref != "" { headers.Set("Referer", request.Site.Ref) } if request.Site.Domain != "" { - headers.Add("Origin", request.Site.Domain) + headers.Set("Origin", request.Site.Domain) } } if request.Device != nil { if len(request.Device.UA) > 0 { - headers.Add("User-Agent", request.Device.UA) + headers.Set("User-Agent", request.Device.UA) } if len(request.Device.IPv6) > 0 { - headers.Add("X-Forwarded-For", request.Device.IPv6) + headers.Set("X-Forwarded-For", request.Device.IPv6) } if len(request.Device.IP) > 0 { - headers.Add("X-Forwarded-For", request.Device.IP) + headers.Set("X-Forwarded-For", request.Device.IP) } } return headers From b7990db57c3d8895cab26fff5f0f487e9dbf27cb Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Mon, 8 Sep 2025 23:48:55 +0300 Subject: [PATCH 11/13] test change rtb 2.5 to 2.6 --- adapters/dxtech/dxtechtest/exemplary/banner.json | 2 +- adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json | 2 +- adapters/dxtech/dxtechtest/exemplary/ipv6.json | 2 +- adapters/dxtech/dxtechtest/exemplary/video-test-request.json | 2 +- adapters/dxtech/dxtechtest/exemplary/video.json | 2 +- adapters/dxtech/dxtechtest/supplemental/invalid-response.json | 2 +- adapters/dxtech/dxtechtest/supplemental/no-mtype.json | 2 +- .../dxtech/dxtechtest/supplemental/status-code-bad-request.json | 2 +- .../dxtech/dxtechtest/supplemental/status-code-no-content.json | 2 +- .../dxtech/dxtechtest/supplemental/status-code-other-error.json | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/adapters/dxtech/dxtechtest/exemplary/banner.json b/adapters/dxtech/dxtechtest/exemplary/banner.json index f443c8995d6..8c6c72a6e1a 100644 --- a/adapters/dxtech/dxtechtest/exemplary/banner.json +++ b/adapters/dxtech/dxtechtest/exemplary/banner.json @@ -54,7 +54,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", diff --git a/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json b/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json index 83900b6a356..ff0a83ffbdf 100644 --- a/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json +++ b/adapters/dxtech/dxtechtest/exemplary/empty-site-domain-ref.json @@ -50,7 +50,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", diff --git a/adapters/dxtech/dxtechtest/exemplary/ipv6.json b/adapters/dxtech/dxtechtest/exemplary/ipv6.json index e74a939e3c1..7991213c5c7 100644 --- a/adapters/dxtech/dxtechtest/exemplary/ipv6.json +++ b/adapters/dxtech/dxtechtest/exemplary/ipv6.json @@ -50,7 +50,7 @@ "2001:0000:130F:0000:0000:09C0:876A:130B" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", diff --git a/adapters/dxtech/dxtechtest/exemplary/video-test-request.json b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json index 7dbfdccd8e8..5def56f0e90 100644 --- a/adapters/dxtech/dxtechtest/exemplary/video-test-request.json +++ b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json @@ -59,7 +59,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "2.5" + "6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=test", diff --git a/adapters/dxtech/dxtechtest/exemplary/video.json b/adapters/dxtech/dxtechtest/exemplary/video.json index 4d29b88aad4..bb039e971de 100644 --- a/adapters/dxtech/dxtechtest/exemplary/video.json +++ b/adapters/dxtech/dxtechtest/exemplary/video.json @@ -58,7 +58,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", diff --git a/adapters/dxtech/dxtechtest/supplemental/invalid-response.json b/adapters/dxtech/dxtechtest/supplemental/invalid-response.json index 546e260becf..93afea8c7b1 100644 --- a/adapters/dxtech/dxtechtest/supplemental/invalid-response.json +++ b/adapters/dxtech/dxtechtest/supplemental/invalid-response.json @@ -58,7 +58,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", diff --git a/adapters/dxtech/dxtechtest/supplemental/no-mtype.json b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json index cfcb1033e6b..8ece92870ae 100644 --- a/adapters/dxtech/dxtechtest/supplemental/no-mtype.json +++ b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json @@ -58,7 +58,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "2.5" + "6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json b/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json index c53d6d7e6b7..7a147852a6c 100644 --- a/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json +++ b/adapters/dxtech/dxtechtest/supplemental/status-code-bad-request.json @@ -58,7 +58,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json b/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json index 64dd93e17dc..5b7b65cc8f7 100644 --- a/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json +++ b/adapters/dxtech/dxtechtest/supplemental/status-code-no-content.json @@ -58,7 +58,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", diff --git a/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json b/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json index 5e3a58968d0..487245ceb89 100644 --- a/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json +++ b/adapters/dxtech/dxtechtest/supplemental/status-code-other-error.json @@ -58,7 +58,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "2.5" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", From bd9e944c7c54217dca9aa419dd0d3a4f73c1f1b4 Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Mon, 8 Sep 2025 23:51:45 +0300 Subject: [PATCH 12/13] typo fix --- adapters/dxtech/dxtechtest/exemplary/video-test-request.json | 2 +- adapters/dxtech/dxtechtest/supplemental/no-mtype.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/adapters/dxtech/dxtechtest/exemplary/video-test-request.json b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json index 5def56f0e90..683c985289b 100644 --- a/adapters/dxtech/dxtechtest/exemplary/video-test-request.json +++ b/adapters/dxtech/dxtechtest/exemplary/video-test-request.json @@ -59,7 +59,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "6" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=test", diff --git a/adapters/dxtech/dxtechtest/supplemental/no-mtype.json b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json index 8ece92870ae..2ef76d53c10 100644 --- a/adapters/dxtech/dxtechtest/supplemental/no-mtype.json +++ b/adapters/dxtech/dxtechtest/supplemental/no-mtype.json @@ -58,7 +58,7 @@ "1.2.3.4" ], "X-Openrtb-Version": [ - "6" + "2.6" ] }, "uri": "https://ads.dxtech.ai/pbs?placement_id=placement123&publisher_id=pub123", From 5b56d8d2e592a8e2d9ef982205f5f434f2fb24ba Mon Sep 17 00:00:00 2001 From: dxtech-git Date: Tue, 16 Dec 2025 09:21:00 +0000 Subject: [PATCH 13/13] DXTech: Add multi-imp test --- .../dxtechtest/exemplary/multi-imp.json | 266 ++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 adapters/dxtech/dxtechtest/exemplary/multi-imp.json diff --git a/adapters/dxtech/dxtechtest/exemplary/multi-imp.json b/adapters/dxtech/dxtechtest/exemplary/multi-imp.json new file mode 100644 index 00000000000..3ebff0ca499 --- /dev/null +++ b/adapters/dxtech/dxtechtest/exemplary/multi-imp.json @@ -0,0 +1,266 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "user": { + "buyeruid": "userId", + "yob": 1990 + }, + "device": { + "ua": "user-agent", + "ip": "1.2.3.4" + }, + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement123" + } + } + }, + { + "id": "test-imp-id-2", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement456" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "method": "POST", + "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.6" + ] + }, + "uri": "https://ads.dxtech.ai/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-1", + "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" + } + }, + "impIDs": ["test-imp-id-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-id-1", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id-1", + "adid": "2422", + "adm": "", + "mtype": 1 + } + ], + "seat": "dxtech" + } + ], + "bidid": "test-request-id", + "id": "test-request-id" + } + } + }, + { + "expectedRequest": { + "method": "POST", + "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.6" + ] + }, + "uri": "https://ads.dxtech.ai/pbs?placement_id=placement456&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-2", + "banner": { + "w": 728, + "h": 90 + }, + "ext": { + "bidder": { + "publisherId": "pub123", + "placementId": "placement456" + } + } + } + ], + "site": { + "domain": "site.com", + "page": "http://site.com/page", + "ref": "http://site.com/ref" + } + }, + "impIDs": ["test-imp-id-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "seatbid": [ + { + "bid": [ + { + "id": "bid-id-2", + "crid": "16330", + "adomain": [ + "adomain2.com" + ], + "price": 5, + "impid": "test-imp-id-2", + "adid": "2423", + "adm": "", + "mtype": 1 + } + ], + "seat": "dxtech" + } + ], + "bidid": "test-request-id", + "id": "test-request-id" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id-1", + "crid": "16329", + "adomain": [ + "adomain.com" + ], + "price": 3, + "impid": "test-imp-id-1", + "adid": "2422", + "adm": "", + "mtype": 1 + }, + "type": "banner" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-id-2", + "crid": "16330", + "adomain": [ + "adomain2.com" + ], + "price": 5, + "impid": "test-imp-id-2", + "adid": "2423", + "adm": "", + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +}