From 2d0320bf87a122fc44ea033e8814082e1b5bd705 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Wed, 8 Oct 2025 09:58:34 +0200 Subject: [PATCH 01/32] Add Waardex bidder integration and tests --- adapters/waardex/waardex.go | 288 ++++++++++++++++++ adapters/waardex/waardex_test.go | 28 ++ .../exemplary/multiformat-impression.json | 169 ++++++++++ .../exemplary/single-banner-impression.json | 105 +++++++ .../exemplary/single-video-impression.json | 118 +++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_waardex.go | 6 + static/bidder-info/waardex.yaml | 19 ++ static/bidder-params/waardex.json | 15 + 10 files changed, 752 insertions(+) create mode 100644 adapters/waardex/waardex.go create mode 100644 adapters/waardex/waardex_test.go create mode 100644 adapters/waardex/waardextest/exemplary/multiformat-impression.json create mode 100644 adapters/waardex/waardextest/exemplary/single-banner-impression.json create mode 100644 adapters/waardex/waardextest/exemplary/single-video-impression.json create mode 100644 openrtb_ext/imp_waardex.go create mode 100644 static/bidder-info/waardex.yaml create mode 100644 static/bidder-params/waardex.json diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go new file mode 100644 index 00000000000..716191c9c8c --- /dev/null +++ b/adapters/waardex/waardex.go @@ -0,0 +1,288 @@ +package waardex + +import ( + "encoding/json" + "fmt" + "net/http" + "strconv" + "text/template" + + "github.com/prebid/openrtb/v20/openrtb2" + "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/macros" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type waardexAdapter struct { + EndpointTemplate *template.Template +} + +// MakeRequests prepares request information for prebid-server core +func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + errs := make([]error, 0, len(request.Imp)) + if len(request.Imp) == 0 { + errs = append(errs, newBadInputError("No impression in the bid request")) + return nil, errs + } + imps, impExts, err := getImpressionsInfo(request.Imp) + if len(imps) == 0 { + return nil, err + } + errs = append(errs, err...) + + pub2impressions, dispErrors := dispatchImpressions(imps, impExts) + if len(dispErrors) > 0 { + errs = append(errs, dispErrors...) + } + if len(pub2impressions) == 0 { + return nil, errs + } + result := make([]*adapters.RequestData, 0, len(pub2impressions)) + for k, imps := range pub2impressions { + bidRequest, err := adapter.buildAdapterRequest(request, &k, imps) + if err != nil { + errs = append(errs, err) + } else { + result = append(result, bidRequest) + } + } + return result, errs +} + +// getImpressionsInfo checks each impression for validity and returns a copy for each impression with corresponding exts +func getImpressionsInfo(imps []openrtb2.Imp) ([]openrtb2.Imp, []openrtb_ext.ExtImpWaardex, []error) { + impsCount := len(imps) + errors := make([]error, 0, impsCount) + resImps := make([]openrtb2.Imp, 0, impsCount) + resImpExts := make([]openrtb_ext.ExtImpWaardex, 0, impsCount) + + for _, imp := range imps { + impExt, err := getImpressionExt(&imp) + if err != nil { + errors = append(errors, err) + continue + } + if err := validateImpression(&imp, impExt); err != nil { + errors = append(errors, err) + continue + } + resImps = append(resImps, imp) + resImpExts = append(resImpExts, *impExt) + } + return resImps, resImpExts, errors +} + +func validateImpression(imp *openrtb2.Imp, impExt *openrtb_ext.ExtImpWaardex) error { + if impExt.ZoneId < 1 { + return newBadInputError(fmt.Sprintf("Invalid zoneId value: %d. Ignoring imp id=%s", impExt.ZoneId, imp.ID)) + } + return nil +} + +// Group impressions by Waardex-specific parameter `zoneId` +func dispatchImpressions(imps []openrtb2.Imp, impsExt []openrtb_ext.ExtImpWaardex) (map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp, []error) { + res := make(map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp) + errors := make([]error, 0) + for idx := range imps { + imp := imps[idx] + imp.Ext = nil + impExt := impsExt[idx] + if res[impExt] == nil { + res[impExt] = make([]openrtb2.Imp, 0) + } + if isMultiFormatImp(&imp) { + splImps := splitMultiFormatImp(&imp) + res[impExt] = append(res[impExt], splImps...) + } else { + res[impExt] = append(res[impExt], imp) + } + } + return res, errors +} + +func isMultiFormatImp(imp *openrtb2.Imp) bool { + count := 0 + if imp.Video != nil { + count++ + } + if imp.Audio != nil { + count++ + } + if imp.Banner != nil { + count++ + } + if imp.Native != nil { + count++ + } + return count > 1 +} + +func splitMultiFormatImp(imp *openrtb2.Imp) []openrtb2.Imp { + splitImps := make([]openrtb2.Imp, 0, 4) + if imp.Banner != nil { + impCopy := *imp + impCopy.Video = nil + impCopy.Native = nil + impCopy.Audio = nil + splitImps = append(splitImps, impCopy) + } + if imp.Video != nil { + impCopy := *imp + impCopy.Banner = nil + impCopy.Native = nil + impCopy.Audio = nil + splitImps = append(splitImps, impCopy) + } + return splitImps +} + +func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpWaardex, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: err.Error(), + } + } + var waardexExt openrtb_ext.ExtImpWaardex + if err := jsonutil.Unmarshal(bidderExt.Bidder, &waardexExt); err != nil { + return nil, &errortypes.BadInput{ + Message: err.Error(), + } + } + return &waardexExt, nil +} + +func (adapter *waardexAdapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpWaardex, imps []openrtb2.Imp) (*adapters.RequestData, error) { + newBidRequest := createBidRequest(prebidBidRequest, params, imps) + reqJSON, err := json.Marshal(newBidRequest) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + headers.Add("x-openrtb-version", "2.5") + + url, err := adapter.buildEndpointURL(params) + if err != nil { + return nil, err + } + + return &adapters.RequestData{ + Method: "POST", + Uri: url, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(imps)}, nil +} + +func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpWaardex, imps []openrtb2.Imp) *openrtb2.BidRequest { + bidRequest := *prebidBidRequest + bidRequest.Imp = imps + if bidRequest.Site != nil { + // Need to copy Site as Request is a shallow copy + siteCopy := *bidRequest.Site + bidRequest.Site = &siteCopy + bidRequest.Site.Publisher = nil + } + if bidRequest.App != nil { + // Need to copy App as Request is a shallow copy + appCopy := *bidRequest.App + bidRequest.App = &appCopy + bidRequest.App.Publisher = nil + } + return &bidRequest +} + +// Builds endpoint url based on adapter-specific pub settings from imp.ext +func (adapter *waardexAdapter) buildEndpointURL(params *openrtb_ext.ExtImpWaardex) (string, error) { + endpointParams := macros.EndpointTemplateParams{ZoneID: strconv.Itoa(params.ZoneId)} + return macros.ResolveMacros(adapter.EndpointTemplate, endpointParams) +} + +// MakeBids translates Waardex bid response to prebid-server specific format +func (adapter *waardexAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if response.StatusCode == http.StatusNoContent { + return nil, nil + } + if response.StatusCode != http.StatusOK { + return nil, []error{ + newBadServerResponseError(fmt.Sprintf("Unexpected http status code: %d", response.StatusCode)), + } + } + var bidResp openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{ + newBadServerResponseError(fmt.Sprintf("Bad server response: %d", err)), + } + } + + if len(bidResp.SeatBid) != 1 { + return nil, []error{ + newBadServerResponseError(fmt.Sprintf("Invalid SeatBids count: %d", len(bidResp.SeatBid))), + } + } + + seatBid := bidResp.SeatBid[0] + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) + bidResponse.Currency = bidResp.Cur + for i := 0; i < len(seatBid.Bid); i++ { + bid := seatBid.Bid[i] + bidType, err := getMediaTypeForBid(&bid) + if err != nil { + return nil, []error{err} + } + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + }) + } + return bidResponse, nil +} + +// getMediaTypeForImp figures out which media type this bid is for +func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unsupported MType %d", bid.MType), + } + } +} + +func newBadInputError(message string) error { + return &errortypes.BadInput{ + Message: message, + } +} + +func newBadServerResponseError(message string) error { + return &errortypes.BadServerResponse{ + Message: message, + } +} + +// Builder builds a new instance of the waardex adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + urlTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + } + + bidder := &waardexAdapter{ + EndpointTemplate: urlTemplate, + } + return bidder, nil +} diff --git a/adapters/waardex/waardex_test.go b/adapters/waardex/waardex_test.go new file mode 100644 index 00000000000..2e66ce12e79 --- /dev/null +++ b/adapters/waardex/waardex_test.go @@ -0,0 +1,28 @@ +package waardex + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderWaardex, config.Adapter{ + Endpoint: "http://justbidit2.xyz:8800/hb?zone={{.ZoneID}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "waardextest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderWaardex, config.Adapter{ + Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) +} diff --git a/adapters/waardex/waardextest/exemplary/multiformat-impression.json b/adapters/waardex/waardextest/exemplary/multiformat-impression.json new file mode 100644 index 00000000000..3925d766bc2 --- /dev/null +++ b/adapters/waardex/waardextest/exemplary/multiformat-impression.json @@ -0,0 +1,169 @@ +{ + "mockBidRequest": { + "id": "0000000000001", + "imp": [ + { + "id": "multi-adunit", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 102, + "host": "tag.test.com" + } + } + } + ], + "app": { + "id": "app_001", + "bundle": "com.rovio.angrybirds", + "publisher": { + "id": "2" + } + }, + "user": { + "buyeruid": "A-38327932832" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=102", + "body": { + "id": "0000000000001", + "imp": [ + { + "id": "multi-adunit", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + } + }, + { + "id": "multi-adunit", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + } + } + ], + "app": { + "bundle": "com.rovio.angrybirds", + "id": "app_001" + }, + "user": { + "buyeruid": "A-38327932832" + } + }, + "impIDs": [ + "multi-adunit", + "multi-adunit" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "75472df2-1cb3-4f8e-9a28-10cb95fe05a4", + "seatbid": [ + { + "bid": [ + { + "id": "bid02", + "impid": "multi-adunit", + "price": 2.25, + "cid": "1001", + "crid": "2002", + "adid": "2002", + "adm": "", + "mtype": 1, + "adomain": [ + "tag-example.com" + ] + }, + { + "id": "bid03", + "impid": "multi-adunit", + "price": 1.25, + "cid": "601", + "crid": "702", + "adid": "702", + "adm": "", + "cat": [ + "IAB2" + ], + "mtype": 2, + "adomain": [ + "video-example.com" + ] + } + ] + } + ], + "bidid": "wehM-93KGr0" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid02", + "impid": "multi-adunit", + "price": 2.25, + "adm": "", + "adomain": [ + "tag-example.com" + ], + "cid": "1001", + "adid": "2002", + "crid": "2002", + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid03", + "impid": "multi-adunit", + "price": 1.25, + "adm": "", + "adomain": [ + "video-example.com" + ], + "cid": "601", + "adid": "702", + "crid": "702", + "cat": [ + "IAB2" + ], + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/waardex/waardextest/exemplary/single-banner-impression.json b/adapters/waardex/waardextest/exemplary/single-banner-impression.json new file mode 100644 index 00000000000..3b276f32872 --- /dev/null +++ b/adapters/waardex/waardextest/exemplary/single-banner-impression.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "0000000000001", + "imp": [ + { + "id": "adunit-1", + "banner": { + "format": [{"w": 300,"h": 200}, {"w": 300,"h": 250}] + }, + "ext": { + "bidder": { + "zoneId": 101, + "host": "tag.test.com" + } + } + } + ], + "site": { + "page": "http://example.com/test.html", + "publisher": { + "id": "1" + } + }, + "user": { + "buyeruid": "A-38327932832" + }, + "cur": ["TYR"] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=101", + "body": { + "id": "0000000000001", + "imp": [ + { + "id": "adunit-1", + "banner": { + "format": [{"w": 300, "h": 200}, {"w": 300, "h": 250}] + } + } + ], + "site": { + "page": "http://example.com/test.html" + }, + "user": { + "buyeruid": "A-38327932832" + }, + "cur": ["TYR"] + }, + "impIDs":["adunit-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "75472df2-1cb3-4f8e-9a28-10cb95fe05a4", + "seatbid": [{ + "bid": [{ + "id": "wehM-93KGr0_0_0", + "impid": "adunit-1", + "price": 0.5, + "cid": "3706", + "crid": "19005", + "adid": "19005", + "adm": "", + "cat": ["IAB2"], + "mtype": 1, + "adomain": ["test.com"], + "h": 250, + "w": 300 + }] + }], + "bidid": "wehM-93KGr0", + "cur": "TYR" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "TYR", + "bids": [ + { + "bid": { + "id": "wehM-93KGr0_0_0", + "impid": "adunit-1", + "price": 0.5, + "adm": "", + "adid": "19005", + "adomain": ["test.com"], + "cid": "3706", + "crid": "19005", + "w": 300, + "h": 250, + "cat": ["IAB2"], + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/waardex/waardextest/exemplary/single-video-impression.json b/adapters/waardex/waardextest/exemplary/single-video-impression.json new file mode 100644 index 00000000000..a3ed60a74bf --- /dev/null +++ b/adapters/waardex/waardextest/exemplary/single-video-impression.json @@ -0,0 +1,118 @@ +{ + "mockBidRequest": { + "id": "0000000000001", + "imp": [ + { + "id": "video-adunit-2", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "ext": { + "bidder": { + "zoneId": 102, + "host": "tag.test.com" + } + } + } + ], + "app": { + "id": "app_001", + "bundle": "com.rovio.angrybirds", + "publisher": { + "id": "2" + } + }, + "user": { + "buyeruid": "A-38327932832" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=102", + "body": { + "id": "0000000000001", + "imp": [ + { + "id": "video-adunit-2", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + } + } + ], + "app": { + "bundle": "com.rovio.angrybirds", + "id": "app_001" + }, + "user": { + "buyeruid": "A-38327932832" + } + }, + "impIDs":["video-adunit-2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "75472df2-1cb3-4f8e-9a28-10cb95fe05a4", + "seatbid": [ + { + "bid": [ + { + "id": "bid02", + "impid": "video-adunit-2", + "price": 2.25, + "cid": "1001", + "crid": "2002", + "adid": "2002", + "adm": "", + "cat": [ + "IAB2" + ], + "mtype": 2, + "adomain": [ + "video-example.com" + ] + } + ] + } + ], + "bidid": "wehM-93KGr0" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid02", + "impid": "video-adunit-2", + "price": 2.25, + "adm": "", + "adomain": [ + "video-example.com" + ], + "cid": "1001", + "adid": "2002", + "crid": "2002", + "cat": [ + "IAB2" + ], + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index af5c2889672..6f367c89d76 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -247,6 +247,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/vox" "github.com/prebid/prebid-server/v3/adapters/vrtcal" "github.com/prebid/prebid-server/v3/adapters/vungle" + "github.com/prebid/prebid-server/v3/adapters/waardex" "github.com/prebid/prebid-server/v3/adapters/xeworks" "github.com/prebid/prebid-server/v3/adapters/yahooAds" "github.com/prebid/prebid-server/v3/adapters/yandex" @@ -512,6 +513,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderVisibleMeasures: visiblemeasures.Builder, openrtb_ext.BidderVisx: visx.Builder, openrtb_ext.BidderVox: vox.Builder, + openrtb_ext.BidderWaardex: waardex.Builder, openrtb_ext.BidderVrtcal: vrtcal.Builder, openrtb_ext.BidderXeworks: xeworks.Builder, openrtb_ext.BidderYahooAds: yahooAds.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 435e92eb439..445f1c0be8a 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -265,6 +265,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderVox, BidderVrtcal, BidderVungle, + BidderWaardex, BidderXeworks, BidderYahooAds, BidderYandex, @@ -636,6 +637,7 @@ const ( BidderVox BidderName = "vox" BidderVrtcal BidderName = "vrtcal" BidderVungle BidderName = "vungle" + BidderWaardex BidderName = "waardex" BidderXeworks BidderName = "xeworks" BidderYahooAds BidderName = "yahooAds" BidderYandex BidderName = "yandex" diff --git a/openrtb_ext/imp_waardex.go b/openrtb_ext/imp_waardex.go new file mode 100644 index 00000000000..0330ea45f0a --- /dev/null +++ b/openrtb_ext/imp_waardex.go @@ -0,0 +1,6 @@ +package openrtb_ext + +// Waardex defines the contract for bidrequest.imp[i].ext.prebid.bidder.waardex +type ExtImpWaardex struct { + ZoneId int `json:"zoneId"` +} diff --git a/static/bidder-info/waardex.yaml b/static/bidder-info/waardex.yaml new file mode 100644 index 00000000000..44d093e2ad6 --- /dev/null +++ b/static/bidder-info/waardex.yaml @@ -0,0 +1,19 @@ +# We have the following regional endpoint domains: useast, uswest +# Please deploy this config in each of your datacenters with the appropriate regional subdomain +endpoint: "http://REGION.justbidit2.xyz:8800/hb?zone={{.ZoneID}}" +maintainer: + email: it@waardex.com +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video +userSync: + redirect: + url: "https://sync.justbidit2.xyz/user-sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" + userMacro: "{UID}" +endpointCompression: "GZIP" diff --git a/static/bidder-params/waardex.json b/static/bidder-params/waardex.json new file mode 100644 index 00000000000..395a8bbd01e --- /dev/null +++ b/static/bidder-params/waardex.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Waardex Adapter Params", + "description": "A schema which validates params accepted by the Waardex adapter", + + "type": "object", + "properties": { + "zoneId": { + "type": "integer", + "minimum": 1, + "description": "Publisher Id to use." + } + }, + "required": ["zoneId"] +} From de150e546b003786419e3db6881d4501b5e2a87f Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:00:42 +0100 Subject: [PATCH 02/32] Refactor Waardex MakeRequests to ignore unused reqInfo argument --- adapters/waardex/waardex.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 716191c9c8c..be5b97a83b2 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -21,7 +21,7 @@ type waardexAdapter struct { } // MakeRequests prepares request information for prebid-server core -func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { +func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { errs := make([]error, 0, len(request.Imp)) if len(request.Imp) == 0 { errs = append(errs, newBadInputError("No impression in the bid request")) From 9579219149e78d557c88def7853cd79563c08669 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:01:35 +0100 Subject: [PATCH 03/32] Simplify error handling in Waardex MakeRequests function --- adapters/waardex/waardex.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index be5b97a83b2..09146e1a4d1 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -22,11 +22,10 @@ type waardexAdapter struct { // MakeRequests prepares request information for prebid-server core func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - errs := make([]error, 0, len(request.Imp)) - if len(request.Imp) == 0 { - errs = append(errs, newBadInputError("No impression in the bid request")) - return nil, errs - } + var errs []error + if len(request.Imp) == 0 { + return nil, []error{newBadInputError("No impression in the bid request")} + } imps, impExts, err := getImpressionsInfo(request.Imp) if len(imps) == 0 { return nil, err From cdce8ef394d6041200f7ab1fb49a9d8bae4187ed Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:03:00 +0100 Subject: [PATCH 04/32] Refactor Waardex MakeRequests error handling to improve clarity --- adapters/waardex/waardex.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 09146e1a4d1..ea4d56bad85 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -26,11 +26,11 @@ func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *ada if len(request.Imp) == 0 { return nil, []error{newBadInputError("No impression in the bid request")} } - imps, impExts, err := getImpressionsInfo(request.Imp) - if len(imps) == 0 { - return nil, err - } - errs = append(errs, err...) + imps, impExts, impErrs := getImpressionsInfo(request.Imp) + errs = append(errs, impErrs...) + if len(imps) == 0 { + return nil, errs + } pub2impressions, dispErrors := dispatchImpressions(imps, impExts) if len(dispErrors) > 0 { From 13a2eec01911e0815d52d0103ee0749d67de8cc3 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:06:56 +0100 Subject: [PATCH 05/32] Refactor Waardex dispatchImpressions to simplify return structure and remove unused error handling --- adapters/waardex/waardex.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index ea4d56bad85..ac08f7fd616 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -32,10 +32,7 @@ func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *ada return nil, errs } - pub2impressions, dispErrors := dispatchImpressions(imps, impExts) - if len(dispErrors) > 0 { - errs = append(errs, dispErrors...) - } + pub2impressions := dispatchImpressions(imps, impExts) if len(pub2impressions) == 0 { return nil, errs } @@ -82,9 +79,8 @@ func validateImpression(imp *openrtb2.Imp, impExt *openrtb_ext.ExtImpWaardex) er } // Group impressions by Waardex-specific parameter `zoneId` -func dispatchImpressions(imps []openrtb2.Imp, impsExt []openrtb_ext.ExtImpWaardex) (map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp, []error) { +func dispatchImpressions(imps []openrtb2.Imp, impsExt []openrtb_ext.ExtImpWaardex) map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp { res := make(map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp) - errors := make([]error, 0) for idx := range imps { imp := imps[idx] imp.Ext = nil @@ -99,7 +95,7 @@ func dispatchImpressions(imps []openrtb2.Imp, impsExt []openrtb_ext.ExtImpWaarde res[impExt] = append(res[impExt], imp) } } - return res, errors + return res } func isMultiFormatImp(imp *openrtb2.Imp) bool { From 10f656f1ecc1f91c4255ad08c057544aa4b2892b Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:07:47 +0100 Subject: [PATCH 06/32] Refactor Waardex isMultiFormatImp to improve variable naming clarity --- adapters/waardex/waardex.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index ac08f7fd616..2260143f153 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -99,20 +99,20 @@ func dispatchImpressions(imps []openrtb2.Imp, impsExt []openrtb_ext.ExtImpWaarde } func isMultiFormatImp(imp *openrtb2.Imp) bool { - count := 0 + formatCount := 0 if imp.Video != nil { - count++ + formatCount++ } if imp.Audio != nil { - count++ + formatCount++ } if imp.Banner != nil { - count++ + formatCount++ } if imp.Native != nil { - count++ + formatCount++ } - return count > 1 + return formatCount > 1 } func splitMultiFormatImp(imp *openrtb2.Imp) []openrtb2.Imp { From eea4da4300a179ff28d8e25b149102f2ee62abae Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:08:49 +0100 Subject: [PATCH 07/32] Refactor error formatting in Waardex Unmarshal to use %v for consistency --- adapters/waardex/waardex.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 2260143f153..d122f3a1669 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -212,7 +212,7 @@ func (adapter *waardexAdapter) MakeBids(internalRequest *openrtb2.BidRequest, ex var bidResp openrtb2.BidResponse if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil { return nil, []error{ - newBadServerResponseError(fmt.Sprintf("Bad server response: %d", err)), + newBadServerResponseError(fmt.Sprintf("Bad server response: %v", err)), } } From c662bfaa81a7ce949e290ddcdba4fe44bc0e5dd1 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:09:23 +0100 Subject: [PATCH 08/32] Refactor Waardex MakeRequests to improve variable naming consistency --- adapters/waardex/waardex.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index d122f3a1669..194e7e233ee 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -32,12 +32,12 @@ func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *ada return nil, errs } - pub2impressions := dispatchImpressions(imps, impExts) - if len(pub2impressions) == 0 { + impressionsByZone := dispatchImpressions(imps, impExts) + if len(impressionsByZone) == 0 { return nil, errs } - result := make([]*adapters.RequestData, 0, len(pub2impressions)) - for k, imps := range pub2impressions { + result := make([]*adapters.RequestData, 0, len(impressionsByZone)) + for k, imps := range impressionsByZone { bidRequest, err := adapter.buildAdapterRequest(request, &k, imps) if err != nil { errs = append(errs, err) From 3b9301d0a52007d3ffddc05d5bcee96ee227c238 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:12:35 +0100 Subject: [PATCH 09/32] Refactor Waardex createBidRequest to remove unused params argument and improve structure consistency --- adapters/waardex/waardex.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 194e7e233ee..18c1928d1e9 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -151,7 +151,7 @@ func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpWaardex, error) { } func (adapter *waardexAdapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpWaardex, imps []openrtb2.Imp) (*adapters.RequestData, error) { - newBidRequest := createBidRequest(prebidBidRequest, params, imps) + newBidRequest := createBidRequest(prebidBidRequest, imps) reqJSON, err := json.Marshal(newBidRequest) if err != nil { return nil, err @@ -175,12 +175,12 @@ func (adapter *waardexAdapter) buildAdapterRequest(prebidBidRequest *openrtb2.Bi ImpIDs: openrtb_ext.GetImpIDs(imps)}, nil } -func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpWaardex, imps []openrtb2.Imp) *openrtb2.BidRequest { - bidRequest := *prebidBidRequest - bidRequest.Imp = imps - if bidRequest.Site != nil { - // Need to copy Site as Request is a shallow copy - siteCopy := *bidRequest.Site +func createBidRequest(prebidBidRequest *openrtb2.BidRequest, imps []openrtb2.Imp) *openrtb2.BidRequest { + bidRequest := *prebidBidRequest + bidRequest.Imp = imps + if bidRequest.Site != nil { + // Need to copy Site as Request is a shallow copy + siteCopy := *bidRequest.Site bidRequest.Site = &siteCopy bidRequest.Site.Publisher = nil } From 531e3e56d5a6ef62796a77cd22a7970e9f8cea91 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:15:21 +0100 Subject: [PATCH 10/32] Refactor Waardex createBidRequest to simplify site and app copy logic --- adapters/waardex/waardex.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 18c1928d1e9..f3641904944 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -180,17 +180,17 @@ func createBidRequest(prebidBidRequest *openrtb2.BidRequest, imps []openrtb2.Imp bidRequest.Imp = imps if bidRequest.Site != nil { // Need to copy Site as Request is a shallow copy - siteCopy := *bidRequest.Site - bidRequest.Site = &siteCopy - bidRequest.Site.Publisher = nil - } - if bidRequest.App != nil { - // Need to copy App as Request is a shallow copy - appCopy := *bidRequest.App - bidRequest.App = &appCopy - bidRequest.App.Publisher = nil - } - return &bidRequest + site := *bidRequest.Site + site.Publisher = nil + bidRequest.Site = &site + } + if bidRequest.App != nil { + // Need to copy App as Request is a shallow copy + app := *bidRequest.App + app.Publisher = nil + bidRequest.App = &app + } + return &bidRequest } // Builds endpoint url based on adapter-specific pub settings from imp.ext From bdafa95d44fbafc0b3c110a9a476ff465a414171 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:18:09 +0100 Subject: [PATCH 11/32] Refactor Waardex MakeBids to ensure Currency is set only when available --- adapters/waardex/waardex.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index f3641904944..3943b800584 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -223,8 +223,10 @@ func (adapter *waardexAdapter) MakeBids(internalRequest *openrtb2.BidRequest, ex } seatBid := bidResp.SeatBid[0] - bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) - bidResponse.Currency = bidResp.Cur + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } for i := 0; i < len(seatBid.Bid); i++ { bid := seatBid.Bid[i] bidType, err := getMediaTypeForBid(&bid) From 9300235c163f3a1de217797dd5994e895d719041 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:20:55 +0100 Subject: [PATCH 12/32] Refactor Waardex validateImpression logic into core JSON schema and simplify impression processing --- adapters/waardex/waardex.go | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 3943b800584..4022289e6e7 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -55,27 +55,17 @@ func getImpressionsInfo(imps []openrtb2.Imp) ([]openrtb2.Imp, []openrtb_ext.ExtI resImps := make([]openrtb2.Imp, 0, impsCount) resImpExts := make([]openrtb_ext.ExtImpWaardex, 0, impsCount) - for _, imp := range imps { - impExt, err := getImpressionExt(&imp) - if err != nil { - errors = append(errors, err) - continue - } - if err := validateImpression(&imp, impExt); err != nil { - errors = append(errors, err) - continue - } - resImps = append(resImps, imp) - resImpExts = append(resImpExts, *impExt) - } - return resImps, resImpExts, errors -} - -func validateImpression(imp *openrtb2.Imp, impExt *openrtb_ext.ExtImpWaardex) error { - if impExt.ZoneId < 1 { - return newBadInputError(fmt.Sprintf("Invalid zoneId value: %d. Ignoring imp id=%s", impExt.ZoneId, imp.ID)) - } - return nil + for _, imp := range imps { + impExt, err := getImpressionExt(&imp) + if err != nil { + errors = append(errors, err) + continue + } + // Additional validation is handled by the core JSON schema (static/bidder-params/waardex.json). + resImps = append(resImps, imp) + resImpExts = append(resImpExts, *impExt) + } + return resImps, resImpExts, errors } // Group impressions by Waardex-specific parameter `zoneId` From 17966609bc2a5909e224524eeb5882b9001922f5 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Thu, 13 Nov 2025 11:37:32 +0100 Subject: [PATCH 13/32] Refactor Waardex dispatchImpressions to initialize map with capacity and improve existence check logic --- adapters/waardex/waardex.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 4022289e6e7..894413d8c49 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -70,19 +70,19 @@ func getImpressionsInfo(imps []openrtb2.Imp) ([]openrtb2.Imp, []openrtb_ext.ExtI // Group impressions by Waardex-specific parameter `zoneId` func dispatchImpressions(imps []openrtb2.Imp, impsExt []openrtb_ext.ExtImpWaardex) map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp { - res := make(map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp) - for idx := range imps { - imp := imps[idx] - imp.Ext = nil - impExt := impsExt[idx] - if res[impExt] == nil { - res[impExt] = make([]openrtb2.Imp, 0) - } - if isMultiFormatImp(&imp) { - splImps := splitMultiFormatImp(&imp) - res[impExt] = append(res[impExt], splImps...) - } else { - res[impExt] = append(res[impExt], imp) + res := make(map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp) + for idx := range imps { + imp := imps[idx] + imp.Ext = nil + impExt := impsExt[idx] + if _, exists := res[impExt]; !exists { + res[impExt] = make([]openrtb2.Imp, 0, 4) + } + if isMultiFormatImp(&imp) { + splImps := splitMultiFormatImp(&imp) + res[impExt] = append(res[impExt], splImps...) + } else { + res[impExt] = append(res[impExt], imp) } } return res From 27de5b2ac35273e42432c62703fb6ce57a7e788b Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 08:39:20 +0100 Subject: [PATCH 14/32] Add comprehensive unit tests for Waardex adapter functions and utilities --- adapters/waardex/waardex_test.go | 258 +++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) diff --git a/adapters/waardex/waardex_test.go b/adapters/waardex/waardex_test.go index 2e66ce12e79..16132723522 100644 --- a/adapters/waardex/waardex_test.go +++ b/adapters/waardex/waardex_test.go @@ -1,12 +1,17 @@ package waardex import ( + "encoding/json" + "net/http" "testing" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/adapters/adapterstest" "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestJsonSamples(t *testing.T) { @@ -26,3 +31,256 @@ func TestEndpointTemplateMalformed(t *testing.T) { assert.Error(t, buildErr) } + +// --- Helpers --- + +func makeImp(t *testing.T, id string, withBanner, withVideo, withNative, withAudio bool, zoneID int) openrtb2.Imp { + t.Helper() + imp := openrtb2.Imp{ID: id} + if withBanner { + imp.Banner = &openrtb2.Banner{} + } + if withVideo { + imp.Video = &openrtb2.Video{} + } + if withNative { + imp.Native = &openrtb2.Native{Request: `{"ver":"1.2"}`} + } + if withAudio { + imp.Audio = &openrtb2.Audio{MinDuration: 1} + } + // ext: {"bidder":{"zoneId":}} + extObj := map[string]interface{}{"bidder": map[string]interface{}{"zoneId": zoneID}} + raw, err := json.Marshal(extObj) + require.NoError(t, err) + imp.Ext = raw + return imp +} + +// --- getImpressionsInfo --- + +func TestGetImpressionsInfo_FiltersInvalidAndKeepsValid(t *testing.T) { + validImp := makeImp(t, "1", true, false, false, false, 10) + invalidImp := openrtb2.Imp{ID: "2", Ext: json.RawMessage("malformed")} + + imps, exts, errs := getImpressionsInfo([]openrtb2.Imp{validImp, invalidImp}) + + assert.Len(t, errs, 1, "expected one error for invalid imp ext") + require.Len(t, imps, 1) + require.Len(t, exts, 1) + assert.Equal(t, "1", imps[0].ID) + assert.Equal(t, 10, exts[0].ZoneId) +} + +// --- dispatchImpressions --- + +func TestDispatchImpressions_GroupsByZoneAndSplitsMultiFormat(t *testing.T) { + imp1 := makeImp(t, "1", true, false, false, false, 100) // banner only + imp2 := makeImp(t, "2", true, true, false, false, 100) // banner + video (multi) + imp3 := makeImp(t, "3", false, true, false, false, 200) // video only different zone + + imps := []openrtb2.Imp{imp1, imp2, imp3} + exts := []openrtb_ext.ExtImpWaardex{{ZoneId: 100}, {ZoneId: 100}, {ZoneId: 200}} + + grouped := dispatchImpressions(imps, exts) + + // zone 100 should have imp1 and two split imps from imp2 + g100 := grouped[openrtb_ext.ExtImpWaardex{ZoneId: 100}] + require.Len(t, g100, 3) + // Expect exactly one banner-only and one video-only from the split, plus original banner-only + var banners, videos int + for _, imp := range g100 { + if imp.Banner != nil && imp.Video == nil { + banners++ + } + if imp.Video != nil && imp.Banner == nil { + videos++ + } + // ext is nil in dispatched imps + assert.Nil(t, imp.Ext) + } + assert.Equal(t, 2, banners) + assert.Equal(t, 1, videos) + + // zone 200 should have one video-only + g200 := grouped[openrtb_ext.ExtImpWaardex{ZoneId: 200}] + require.Len(t, g200, 1) + assert.NotNil(t, g200[0].Video) + assert.Nil(t, g200[0].Banner) +} + +// --- isMultiFormatImp --- + +func TestIsMultiFormatImp(t *testing.T) { + single := makeImp(t, "1", true, false, false, false, 1) + multi := makeImp(t, "2", true, true, false, false, 1) + none := openrtb2.Imp{ID: "3"} + + assert.False(t, isMultiFormatImp(&single)) + assert.True(t, isMultiFormatImp(&multi)) + assert.False(t, isMultiFormatImp(&none)) +} + +// --- splitMultiFormatImp --- + +func TestSplitMultiFormatImp_BannerVideoOnly(t *testing.T) { + imp := makeImp(t, "m", true, true, true, true, 5) + // ensure it is multi-format + require.True(t, isMultiFormatImp(&imp)) + + split := splitMultiFormatImp(&imp) + // Only banner and video are produced + require.Len(t, split, 2) + // first banner-only, second video-only (order not guaranteed; verify counts) + var banners, videos, natives, audios int + for _, s := range split { + if s.Banner != nil { + banners++ + } + if s.Video != nil { + videos++ + } + if s.Native != nil { + natives++ + } + if s.Audio != nil { + audios++ + } + } + assert.Equal(t, 1, banners) + assert.Equal(t, 1, videos) + assert.Equal(t, 0, natives) + assert.Equal(t, 0, audios) +} + +// --- createBidRequest --- + +func TestCreateBidRequest_ShallowCopyAndStripPublishers(t *testing.T) { + sitePublisher := &openrtb2.Publisher{ID: "pub-site"} + appPublisher := &openrtb2.Publisher{ID: "pub-app"} + req := &openrtb2.BidRequest{ + ID: "req-1", + Site: &openrtb2.Site{ID: "site-1", Publisher: sitePublisher}, + App: &openrtb2.App{ID: "app-1", Publisher: appPublisher}, + Imp: []openrtb2.Imp{makeImp(t, "i1", true, false, false, false, 9)}, + } + + newImps := []openrtb2.Imp{makeImp(t, "i2", false, true, false, false, 9)} + out := createBidRequest(req, newImps) + + // Ensure original not mutated + require.NotNil(t, req.Site.Publisher) + require.NotNil(t, req.App.Publisher) + assert.Equal(t, 1, len(req.Imp)) + + // Ensure new request contains provided imps and stripped publishers + require.Equal(t, newImps, out.Imp) + if out.Site != nil { + assert.Nil(t, out.Site.Publisher) + } + if out.App != nil { + assert.Nil(t, out.App.Publisher) + } +} + +// --- buildEndpointURL --- + +func TestBuildEndpointURL(t *testing.T) { + bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{ + Endpoint: "http://example.test/hb?zone={{.ZoneID}}"}, config.Server{}) + require.NoError(t, err) + + url, err := bidder.(*waardexAdapter).buildEndpointURL(&openrtb_ext.ExtImpWaardex{ZoneId: 321}) + require.NoError(t, err) + assert.Equal(t, "http://example.test/hb?zone=321", url) +} + +// --- MakeBids --- + +func TestMakeBids_NoContent(t *testing.T) { + bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) + require.NoError(t, err) + + br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusNoContent}) + assert.Nil(t, br) + assert.Nil(t, errs) +} + +func TestMakeBids_NonOKStatus(t *testing.T) { + bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) + require.NoError(t, err) + + br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusBadRequest}) + assert.Nil(t, br) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "Unexpected http status code") +} + +func TestMakeBids_BadJSON(t *testing.T) { + bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) + require.NoError(t, err) + + br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusOK, Body: []byte("not-json")}) + assert.Nil(t, br) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "Bad server response") +} + +func TestMakeBids_InvalidSeatBidsCount(t *testing.T) { + bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) + require.NoError(t, err) + + payload := openrtb2.BidResponse{SeatBid: []openrtb2.SeatBid{}} // zero seatbids + raw, _ := json.Marshal(payload) + br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusOK, Body: raw}) + assert.Nil(t, br) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "Invalid SeatBids count") +} + +func TestMakeBids_SuccessWithTypesAndCurrency(t *testing.T) { + bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) + require.NoError(t, err) + + bids := []openrtb2.Bid{ + {ID: "b1", ImpID: "1", Price: 1.1, MType: openrtb2.MarkupBanner}, + {ID: "b2", ImpID: "2", Price: 2.2, MType: openrtb2.MarkupVideo}, + } + payload := openrtb2.BidResponse{Cur: "EUR", SeatBid: []openrtb2.SeatBid{{Bid: bids}}} + raw, _ := json.Marshal(payload) + br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusOK, Body: raw}) + + require.Nil(t, errs) + require.NotNil(t, br) + assert.Equal(t, "EUR", br.Currency) + require.Len(t, br.Bids, 2) + assert.Equal(t, openrtb_ext.BidTypeBanner, br.Bids[0].BidType) + assert.Equal(t, openrtb_ext.BidTypeVideo, br.Bids[1].BidType) +} + +// --- getMediaTypeForBid --- + +func TestGetMediaTypeForBid(t *testing.T) { + type tc struct { + mtype openrtb2.MarkupType + want openrtb_ext.BidType + ok bool + } + tests := []tc{ + {openrtb2.MarkupBanner, openrtb_ext.BidTypeBanner, true}, + {openrtb2.MarkupAudio, openrtb_ext.BidTypeAudio, true}, + {openrtb2.MarkupNative, openrtb_ext.BidTypeNative, true}, + {openrtb2.MarkupVideo, openrtb_ext.BidTypeVideo, true}, + {openrtb2.MarkupType(99), "", false}, + } + for _, tt := range tests { + bid := &openrtb2.Bid{MType: tt.mtype} + got, err := getMediaTypeForBid(bid) + if tt.ok { + require.NoError(t, err) + assert.Equal(t, tt.want, got) + } else { + require.Error(t, err) + } + } +} From f2f8c9775c31340fb22227a71271842b5a48f20e Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 08:47:01 +0100 Subject: [PATCH 15/32] Refactor Waardex MakeBids to aggregate errors instead of returning early --- adapters/waardex/waardex.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 894413d8c49..1291956e934 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -217,18 +217,20 @@ func (adapter *waardexAdapter) MakeBids(internalRequest *openrtb2.BidRequest, ex if bidResp.Cur != "" { bidResponse.Currency = bidResp.Cur } + var errs []error for i := 0; i < len(seatBid.Bid); i++ { bid := seatBid.Bid[i] bidType, err := getMediaTypeForBid(&bid) if err != nil { - return nil, []error{err} + errs = append(errs, err) + continue } bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ Bid: &bid, BidType: bidType, }) } - return bidResponse, nil + return bidResponse, errs } // getMediaTypeForImp figures out which media type this bid is for From c9327121a75254dd5f823af4b297c77ebb038533 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 08:57:25 +0100 Subject: [PATCH 16/32] Refactor Waardex adapter to use consistent indentation and add new unit tests for MakeRequests --- adapters/waardex/waardex.go | 112 ++++++++++++++++--------------- adapters/waardex/waardex_test.go | 66 ++++++++++++++++++ 2 files changed, 125 insertions(+), 53 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 1291956e934..659249185f8 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -22,15 +22,15 @@ type waardexAdapter struct { // MakeRequests prepares request information for prebid-server core func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - var errs []error - if len(request.Imp) == 0 { - return nil, []error{newBadInputError("No impression in the bid request")} - } - imps, impExts, impErrs := getImpressionsInfo(request.Imp) - errs = append(errs, impErrs...) - if len(imps) == 0 { - return nil, errs - } + var errs []error + if len(request.Imp) == 0 { + return nil, []error{newBadInputError("No impression in the bid request")} + } + imps, impExts, impErrs := getImpressionsInfo(request.Imp) + errs = append(errs, impErrs...) + if len(imps) == 0 { + return nil, errs + } impressionsByZone := dispatchImpressions(imps, impExts) if len(impressionsByZone) == 0 { @@ -55,34 +55,40 @@ func getImpressionsInfo(imps []openrtb2.Imp) ([]openrtb2.Imp, []openrtb_ext.ExtI resImps := make([]openrtb2.Imp, 0, impsCount) resImpExts := make([]openrtb_ext.ExtImpWaardex, 0, impsCount) - for _, imp := range imps { - impExt, err := getImpressionExt(&imp) - if err != nil { - errors = append(errors, err) - continue - } - // Additional validation is handled by the core JSON schema (static/bidder-params/waardex.json). - resImps = append(resImps, imp) - resImpExts = append(resImpExts, *impExt) - } - return resImps, resImpExts, errors + for _, imp := range imps { + impExt, err := getImpressionExt(&imp) + if err != nil { + errors = append(errors, err) + continue + } + // Additional validation is handled by the core JSON schema (static/bidder-params/waardex.json). + resImps = append(resImps, imp) + resImpExts = append(resImpExts, *impExt) + } + return resImps, resImpExts, errors } // Group impressions by Waardex-specific parameter `zoneId` func dispatchImpressions(imps []openrtb2.Imp, impsExt []openrtb_ext.ExtImpWaardex) map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp { - res := make(map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp) - for idx := range imps { - imp := imps[idx] - imp.Ext = nil - impExt := impsExt[idx] - if _, exists := res[impExt]; !exists { - res[impExt] = make([]openrtb2.Imp, 0, 4) - } - if isMultiFormatImp(&imp) { - splImps := splitMultiFormatImp(&imp) - res[impExt] = append(res[impExt], splImps...) - } else { - res[impExt] = append(res[impExt], imp) + res := make(map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp) + for idx := range imps { + imp := imps[idx] + imp.Ext = nil + impExt := impsExt[idx] + if isMultiFormatImp(&imp) { + splImps := splitMultiFormatImp(&imp) + if len(splImps) == 0 { + continue + } + if _, exists := res[impExt]; !exists { + res[impExt] = make([]openrtb2.Imp, 0, 4) + } + res[impExt] = append(res[impExt], splImps...) + } else { + if _, exists := res[impExt]; !exists { + res[impExt] = make([]openrtb2.Imp, 0, 4) + } + res[impExt] = append(res[impExt], imp) } } return res @@ -141,7 +147,7 @@ func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpWaardex, error) { } func (adapter *waardexAdapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpWaardex, imps []openrtb2.Imp) (*adapters.RequestData, error) { - newBidRequest := createBidRequest(prebidBidRequest, imps) + newBidRequest := createBidRequest(prebidBidRequest, imps) reqJSON, err := json.Marshal(newBidRequest) if err != nil { return nil, err @@ -166,21 +172,21 @@ func (adapter *waardexAdapter) buildAdapterRequest(prebidBidRequest *openrtb2.Bi } func createBidRequest(prebidBidRequest *openrtb2.BidRequest, imps []openrtb2.Imp) *openrtb2.BidRequest { - bidRequest := *prebidBidRequest - bidRequest.Imp = imps - if bidRequest.Site != nil { - // Need to copy Site as Request is a shallow copy - site := *bidRequest.Site - site.Publisher = nil - bidRequest.Site = &site - } - if bidRequest.App != nil { - // Need to copy App as Request is a shallow copy - app := *bidRequest.App - app.Publisher = nil - bidRequest.App = &app - } - return &bidRequest + bidRequest := *prebidBidRequest + bidRequest.Imp = imps + if bidRequest.Site != nil { + // Need to copy Site as Request is a shallow copy + site := *bidRequest.Site + site.Publisher = nil + bidRequest.Site = &site + } + if bidRequest.App != nil { + // Need to copy App as Request is a shallow copy + app := *bidRequest.App + app.Publisher = nil + bidRequest.App = &app + } + return &bidRequest } // Builds endpoint url based on adapter-specific pub settings from imp.ext @@ -213,10 +219,10 @@ func (adapter *waardexAdapter) MakeBids(internalRequest *openrtb2.BidRequest, ex } seatBid := bidResp.SeatBid[0] - bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) - if bidResp.Cur != "" { - bidResponse.Currency = bidResp.Cur - } + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } var errs []error for i := 0; i < len(seatBid.Bid); i++ { bid := seatBid.Bid[i] diff --git a/adapters/waardex/waardex_test.go b/adapters/waardex/waardex_test.go index 16132723522..ede879a9a12 100644 --- a/adapters/waardex/waardex_test.go +++ b/adapters/waardex/waardex_test.go @@ -2,8 +2,10 @@ package waardex import ( "encoding/json" + "errors" "net/http" "testing" + "text/template" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/adapters" @@ -32,6 +34,70 @@ func TestEndpointTemplateMalformed(t *testing.T) { assert.Error(t, buildErr) } +// --- MakeRequests --- + +func TestMakeRequests_NoImpressions(t *testing.T) { + adapter := &waardexAdapter{ + EndpointTemplate: template.Must(template.New("endpointTemplate").Parse("http://example.com?zone={{.ZoneID}}")), + } + request := &openrtb2.BidRequest{} + + requests, errs := adapter.MakeRequests(request, &adapters.ExtraRequestInfo{}) + + assert.Nil(t, requests) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "No impression in the bid request") +} + +func TestMakeRequests_AllImpressionsInvalid(t *testing.T) { + adapter := &waardexAdapter{ + EndpointTemplate: template.Must(template.New("endpointTemplate").Parse("http://example.com?zone={{.ZoneID}}")), + } + request := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + {ID: "1", Ext: json.RawMessage("malformed")}, + }, + } + + requests, errs := adapter.MakeRequests(request, &adapters.ExtraRequestInfo{}) + + assert.Nil(t, requests) + require.Len(t, errs, 1) +} + +func TestMakeRequests_DispatchEmptyReturnsNil(t *testing.T) { + adapter := &waardexAdapter{ + EndpointTemplate: template.Must(template.New("endpointTemplate").Parse("http://example.com?zone={{.ZoneID}}")), + } + // audio+native is multi-format but splitMultiFormatImp returns no imps + request := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{makeImp(t, "1", false, false, true, true, 7)}, + } + + requests, errs := adapter.MakeRequests(request, &adapters.ExtraRequestInfo{}) + + assert.Nil(t, requests) + assert.Len(t, errs, 0) +} + +func TestMakeRequests_BuildAdapterRequestError(t *testing.T) { + failTemplate, err := template.New("endpointTemplate").Funcs(template.FuncMap{ + "fail": func() (string, error) { return "", errors.New("boom") }, + }).Parse("{{fail}}") + require.NoError(t, err) + + adapter := &waardexAdapter{EndpointTemplate: failTemplate} + request := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{makeImp(t, "1", true, false, false, false, 7)}, + } + + requests, errs := adapter.MakeRequests(request, &adapters.ExtraRequestInfo{}) + + assert.Len(t, requests, 0) + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "boom") +} + // --- Helpers --- func makeImp(t *testing.T, id string, withBanner, withVideo, withNative, withAudio bool, zoneID int) openrtb2.Imp { From f207127fd23653bc04bce44793d59c9f6b32c0d6 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 09:01:35 +0100 Subject: [PATCH 17/32] Add unit tests for isMultiFormatImp to cover diverse impression cases --- adapters/waardex/waardex_test.go | 40 ++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/adapters/waardex/waardex_test.go b/adapters/waardex/waardex_test.go index ede879a9a12..fa96ab4400c 100644 --- a/adapters/waardex/waardex_test.go +++ b/adapters/waardex/waardex_test.go @@ -187,6 +187,46 @@ func TestIsMultiFormatImp(t *testing.T) { assert.False(t, isMultiFormatImp(&none)) } +func TestIsMultiFormatImp_MultiImpressionCases(t *testing.T) { + tests := []struct { + name string + imp openrtb2.Imp + wantMulti bool + }{ + { + name: "banner+audio", + imp: makeImp(t, "ba", true, false, false, true, 1), + wantMulti: true, + }, + { + name: "video+native", + imp: makeImp(t, "vn", false, true, true, false, 1), + wantMulti: true, + }, + { + name: "banner+native+audio", + imp: makeImp(t, "bna", true, false, true, true, 1), + wantMulti: true, + }, + { + name: "audio-only", + imp: makeImp(t, "a", false, false, false, true, 1), + wantMulti: false, + }, + { + name: "native-only", + imp: makeImp(t, "n", false, false, true, false, 1), + wantMulti: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.wantMulti, isMultiFormatImp(&tt.imp)) + }) + } +} + // --- splitMultiFormatImp --- func TestSplitMultiFormatImp_BannerVideoOnly(t *testing.T) { From 43c3d056d793cf37deab5801ecdead2bcbe18d28 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 09:03:58 +0100 Subject: [PATCH 18/32] Add unit tests for getImpressionExt to handle malformed and invalid bidder extensions --- adapters/waardex/waardex_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/adapters/waardex/waardex_test.go b/adapters/waardex/waardex_test.go index fa96ab4400c..e9fbabe668a 100644 --- a/adapters/waardex/waardex_test.go +++ b/adapters/waardex/waardex_test.go @@ -138,6 +138,25 @@ func TestGetImpressionsInfo_FiltersInvalidAndKeepsValid(t *testing.T) { assert.Equal(t, 10, exts[0].ZoneId) } +func TestGetImpressionExt_BadImpExt(t *testing.T) { + imp := openrtb2.Imp{ID: "1", Ext: json.RawMessage("malformed")} + + ext, err := getImpressionExt(&imp) + + assert.Nil(t, ext) + require.Error(t, err) +} + +func TestGetImpressionExt_BadBidderExt(t *testing.T) { + imp := openrtb2.Imp{ID: "1"} + imp.Ext = json.RawMessage(`{"bidder": "not-json"}`) + + ext, err := getImpressionExt(&imp) + + assert.Nil(t, ext) + require.Error(t, err) +} + // --- dispatchImpressions --- func TestDispatchImpressions_GroupsByZoneAndSplitsMultiFormat(t *testing.T) { From 4a1646a0579aa8f2931f1cf846bede7208faa48c Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 09:08:13 +0100 Subject: [PATCH 19/32] Add unit tests for MakeRequests to handle invalid and malformed impression extensions --- .../multiformat-impression-invalid-ext.json | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json diff --git a/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json b/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json new file mode 100644 index 00000000000..18fe9331b99 --- /dev/null +++ b/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "0000000000001", + "imp": [ + { + "id": "multi-adunit", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": "malformed" + }, + { + "id": "multi-adunit-2", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480 + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": "not-json" + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "json: cannot unmarshal string into Go value of type adapters.ExtImpBidder", + "comparison": "literal" + }, + { + "value": "json: cannot unmarshal string into Go value of type openrtb_ext.ExtImpWaardex", + "comparison": "literal" + } + ], + "httpCalls": [] +} From 482bb52ba45f3892081257dc2e8a1b0f7201795f Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 09:11:09 +0100 Subject: [PATCH 20/32] Refactor Waardex MakeRequests to remove redundant no-impression check and its associated test --- adapters/waardex/waardex.go | 3 --- adapters/waardex/waardex_test.go | 13 ------------- 2 files changed, 16 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 659249185f8..2e5e9e0c562 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -23,9 +23,6 @@ type waardexAdapter struct { // MakeRequests prepares request information for prebid-server core func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { var errs []error - if len(request.Imp) == 0 { - return nil, []error{newBadInputError("No impression in the bid request")} - } imps, impExts, impErrs := getImpressionsInfo(request.Imp) errs = append(errs, impErrs...) if len(imps) == 0 { diff --git a/adapters/waardex/waardex_test.go b/adapters/waardex/waardex_test.go index e9fbabe668a..6fb7782dafd 100644 --- a/adapters/waardex/waardex_test.go +++ b/adapters/waardex/waardex_test.go @@ -36,19 +36,6 @@ func TestEndpointTemplateMalformed(t *testing.T) { // --- MakeRequests --- -func TestMakeRequests_NoImpressions(t *testing.T) { - adapter := &waardexAdapter{ - EndpointTemplate: template.Must(template.New("endpointTemplate").Parse("http://example.com?zone={{.ZoneID}}")), - } - request := &openrtb2.BidRequest{} - - requests, errs := adapter.MakeRequests(request, &adapters.ExtraRequestInfo{}) - - assert.Nil(t, requests) - require.Len(t, errs, 1) - assert.Contains(t, errs[0].Error(), "No impression in the bid request") -} - func TestMakeRequests_AllImpressionsInvalid(t *testing.T) { adapter := &waardexAdapter{ EndpointTemplate: template.Must(template.New("endpointTemplate").Parse("http://example.com?zone={{.ZoneID}}")), From 1f2485baa319110d291b156b4767612e9717a84c Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 09:11:13 +0100 Subject: [PATCH 21/32] Update unit test expected error messages for malformed impression extensions in Waardex adapter --- .../supplemental/multiformat-impression-invalid-ext.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json b/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json index 18fe9331b99..5a8dee14c49 100644 --- a/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json +++ b/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json @@ -46,11 +46,11 @@ }, "expectedMakeRequestsErrors": [ { - "value": "json: cannot unmarshal string into Go value of type adapters.ExtImpBidder", + "value": "expect { or n, but found \"", "comparison": "literal" }, { - "value": "json: cannot unmarshal string into Go value of type openrtb_ext.ExtImpWaardex", + "value": "expect { or n, but found \"", "comparison": "literal" } ], From 1a97dd6f3337dd5fd130f02f174c20cc8c5db2d9 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 09:13:22 +0100 Subject: [PATCH 22/32] Optimize memory allocation in Waardex splitMultiFormatImp by reducing initial slice capacity --- adapters/waardex/waardex.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 2e5e9e0c562..2025036f0f0 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -109,7 +109,7 @@ func isMultiFormatImp(imp *openrtb2.Imp) bool { } func splitMultiFormatImp(imp *openrtb2.Imp) []openrtb2.Imp { - splitImps := make([]openrtb2.Imp, 0, 4) + splitImps := make([]openrtb2.Imp, 0, 2) if imp.Banner != nil { impCopy := *imp impCopy.Video = nil From 16eeb26bd0938aae75c83c3eb1ce961510fdf74b Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 09:16:08 +0100 Subject: [PATCH 23/32] Refactor Waardex adapter by merging `getImpressionsInfo` and `dispatchImpressions` into `groupImpressionsByZone` for improved clarity and efficiency, and update associated tests --- adapters/waardex/waardex.go | 49 ++++++++++---------------------- adapters/waardex/waardex_test.go | 25 +++++++--------- 2 files changed, 26 insertions(+), 48 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 2025036f0f0..42f9195f21d 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -23,13 +23,8 @@ type waardexAdapter struct { // MakeRequests prepares request information for prebid-server core func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { var errs []error - imps, impExts, impErrs := getImpressionsInfo(request.Imp) + impressionsByZone, impErrs := groupImpressionsByZone(request.Imp) errs = append(errs, impErrs...) - if len(imps) == 0 { - return nil, errs - } - - impressionsByZone := dispatchImpressions(imps, impExts) if len(impressionsByZone) == 0 { return nil, errs } @@ -45,50 +40,36 @@ func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *ada return result, errs } -// getImpressionsInfo checks each impression for validity and returns a copy for each impression with corresponding exts -func getImpressionsInfo(imps []openrtb2.Imp) ([]openrtb2.Imp, []openrtb_ext.ExtImpWaardex, []error) { - impsCount := len(imps) - errors := make([]error, 0, impsCount) - resImps := make([]openrtb2.Imp, 0, impsCount) - resImpExts := make([]openrtb_ext.ExtImpWaardex, 0, impsCount) - - for _, imp := range imps { +// groupImpressionsByZone validates imps and groups them by Waardex-specific parameter `zoneId`. +func groupImpressionsByZone(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp, []error) { + res := make(map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp) + errors := make([]error, 0, len(imps)) + for idx := range imps { + imp := imps[idx] impExt, err := getImpressionExt(&imp) if err != nil { errors = append(errors, err) continue } - // Additional validation is handled by the core JSON schema (static/bidder-params/waardex.json). - resImps = append(resImps, imp) - resImpExts = append(resImpExts, *impExt) - } - return resImps, resImpExts, errors -} - -// Group impressions by Waardex-specific parameter `zoneId` -func dispatchImpressions(imps []openrtb2.Imp, impsExt []openrtb_ext.ExtImpWaardex) map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp { - res := make(map[openrtb_ext.ExtImpWaardex][]openrtb2.Imp) - for idx := range imps { - imp := imps[idx] imp.Ext = nil - impExt := impsExt[idx] + // Additional validation is handled by the core JSON schema (static/bidder-params/waardex.json). if isMultiFormatImp(&imp) { splImps := splitMultiFormatImp(&imp) if len(splImps) == 0 { continue } - if _, exists := res[impExt]; !exists { - res[impExt] = make([]openrtb2.Imp, 0, 4) + if _, exists := res[*impExt]; !exists { + res[*impExt] = make([]openrtb2.Imp, 0, 4) } - res[impExt] = append(res[impExt], splImps...) + res[*impExt] = append(res[*impExt], splImps...) } else { - if _, exists := res[impExt]; !exists { - res[impExt] = make([]openrtb2.Imp, 0, 4) + if _, exists := res[*impExt]; !exists { + res[*impExt] = make([]openrtb2.Imp, 0, 4) } - res[impExt] = append(res[impExt], imp) + res[*impExt] = append(res[*impExt], imp) } } - return res + return res, errors } func isMultiFormatImp(imp *openrtb2.Imp) bool { diff --git a/adapters/waardex/waardex_test.go b/adapters/waardex/waardex_test.go index 6fb7782dafd..572df253c05 100644 --- a/adapters/waardex/waardex_test.go +++ b/adapters/waardex/waardex_test.go @@ -110,19 +110,20 @@ func makeImp(t *testing.T, id string, withBanner, withVideo, withNative, withAud return imp } -// --- getImpressionsInfo --- +// --- groupImpressionsByZone --- -func TestGetImpressionsInfo_FiltersInvalidAndKeepsValid(t *testing.T) { +func TestGroupImpressionsByZone_FiltersInvalidAndKeepsValid(t *testing.T) { validImp := makeImp(t, "1", true, false, false, false, 10) invalidImp := openrtb2.Imp{ID: "2", Ext: json.RawMessage("malformed")} - imps, exts, errs := getImpressionsInfo([]openrtb2.Imp{validImp, invalidImp}) + grouped, errs := groupImpressionsByZone([]openrtb2.Imp{validImp, invalidImp}) assert.Len(t, errs, 1, "expected one error for invalid imp ext") - require.Len(t, imps, 1) - require.Len(t, exts, 1) - assert.Equal(t, "1", imps[0].ID) - assert.Equal(t, 10, exts[0].ZoneId) + require.Len(t, grouped, 1) + group := grouped[openrtb_ext.ExtImpWaardex{ZoneId: 10}] + require.Len(t, group, 1) + assert.Equal(t, "1", group[0].ID) + assert.Nil(t, group[0].Ext) } func TestGetImpressionExt_BadImpExt(t *testing.T) { @@ -144,17 +145,13 @@ func TestGetImpressionExt_BadBidderExt(t *testing.T) { require.Error(t, err) } -// --- dispatchImpressions --- - -func TestDispatchImpressions_GroupsByZoneAndSplitsMultiFormat(t *testing.T) { +func TestGroupImpressionsByZone_GroupsByZoneAndSplitsMultiFormat(t *testing.T) { imp1 := makeImp(t, "1", true, false, false, false, 100) // banner only imp2 := makeImp(t, "2", true, true, false, false, 100) // banner + video (multi) imp3 := makeImp(t, "3", false, true, false, false, 200) // video only different zone - imps := []openrtb2.Imp{imp1, imp2, imp3} - exts := []openrtb_ext.ExtImpWaardex{{ZoneId: 100}, {ZoneId: 100}, {ZoneId: 200}} - - grouped := dispatchImpressions(imps, exts) + grouped, errs := groupImpressionsByZone([]openrtb2.Imp{imp1, imp2, imp3}) + require.Len(t, errs, 0) // zone 100 should have imp1 and two split imps from imp2 g100 := grouped[openrtb_ext.ExtImpWaardex{ZoneId: 100}] From d024330ed3cfa74162b3aa248eed731af5d45fa3 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 09:16:56 +0100 Subject: [PATCH 24/32] Reduce initial slice capacity in Waardex adapter to optimize memory allocation --- adapters/waardex/waardex.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 42f9195f21d..00c77204a8d 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -59,12 +59,12 @@ func groupImpressionsByZone(imps []openrtb2.Imp) (map[openrtb_ext.ExtImpWaardex] continue } if _, exists := res[*impExt]; !exists { - res[*impExt] = make([]openrtb2.Imp, 0, 4) + res[*impExt] = make([]openrtb2.Imp, 0, 2) } res[*impExt] = append(res[*impExt], splImps...) } else { if _, exists := res[*impExt]; !exists { - res[*impExt] = make([]openrtb2.Imp, 0, 4) + res[*impExt] = make([]openrtb2.Imp, 0, 2) } res[*impExt] = append(res[*impExt], imp) } From c1fdb37c84281dc098fdcdba1049e594dfff3dc0 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 12 Jan 2026 09:25:17 +0100 Subject: [PATCH 25/32] Append `sspID` to Waardex user-sync redirect URL for enhanced tracking --- static/bidder-info/waardex.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/waardex.yaml b/static/bidder-info/waardex.yaml index 44d093e2ad6..c307010fdc4 100644 --- a/static/bidder-info/waardex.yaml +++ b/static/bidder-info/waardex.yaml @@ -14,6 +14,6 @@ capabilities: - video userSync: redirect: - url: "https://sync.justbidit2.xyz/user-sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}" + url: "https://sync.justbidit2.xyz/user-sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}&s={{.SspID}}" userMacro: "{UID}" endpointCompression: "GZIP" From 63861c2eb41df4c3d78ce79aa246efe8c3b2b939 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Fri, 16 Jan 2026 10:24:15 +0100 Subject: [PATCH 26/32] Update Waardex user-sync configuration to require host setup and add support details --- static/bidder-info/waardex.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/static/bidder-info/waardex.yaml b/static/bidder-info/waardex.yaml index c307010fdc4..fb3f482fefc 100644 --- a/static/bidder-info/waardex.yaml +++ b/static/bidder-info/waardex.yaml @@ -14,6 +14,8 @@ capabilities: - video userSync: redirect: - url: "https://sync.justbidit2.xyz/user-sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&r={{.RedirectURL}}&s={{.SspID}}" - userMacro: "{UID}" + # waardex supports user syncing, but requires configuration by the host. contact this + # bidder directly at the email address support@waardex.com to ask about enabling user sync. + supports: + - redirect endpointCompression: "GZIP" From f3f8181e6f93a643f260668b90cb9611adbaa5b7 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Mon, 19 Jan 2026 10:05:03 +0100 Subject: [PATCH 27/32] Reorder Waardex entry in adapter builders for consistent alphabetical sorting --- exchange/adapter_builders.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 6f367c89d76..c5427d4dec5 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -513,8 +513,8 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderVisibleMeasures: visiblemeasures.Builder, openrtb_ext.BidderVisx: visx.Builder, openrtb_ext.BidderVox: vox.Builder, - openrtb_ext.BidderWaardex: waardex.Builder, openrtb_ext.BidderVrtcal: vrtcal.Builder, + openrtb_ext.BidderWaardex: waardex.Builder, openrtb_ext.BidderXeworks: xeworks.Builder, openrtb_ext.BidderYahooAds: yahooAds.Builder, openrtb_ext.BidderYandex: yandex.Builder, From d2981295d5652b86f93b13a419f24df66f4de364 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Wed, 21 Jan 2026 08:37:04 +0100 Subject: [PATCH 28/32] Add supplemental test cases for Waardex to validate error handling of invalid responses and malformed inputs --- adapters/waardex/waardex.go | 4 +- adapters/waardex/waardex_test.go | 367 ------------------ .../supplemental/all-impressions-invalid.json | 26 ++ .../supplemental/bad-response.json | 60 +++ .../supplemental/invalid-seatbid-count.json | 63 +++ .../multiformat-audio-native.json | 28 ++ .../multiformat-impression-invalid-ext.json | 4 +- .../waardextest/supplemental/status-204.json | 55 +++ .../supplemental/status-not-200.json | 60 +++ .../supplemental/unsupported-mtype.json | 81 ++++ 10 files changed, 377 insertions(+), 371 deletions(-) create mode 100644 adapters/waardex/waardextest/supplemental/all-impressions-invalid.json create mode 100644 adapters/waardex/waardextest/supplemental/bad-response.json create mode 100644 adapters/waardex/waardextest/supplemental/invalid-seatbid-count.json create mode 100644 adapters/waardex/waardextest/supplemental/multiformat-audio-native.json create mode 100644 adapters/waardex/waardextest/supplemental/status-204.json create mode 100644 adapters/waardex/waardextest/supplemental/status-not-200.json create mode 100644 adapters/waardex/waardextest/supplemental/unsupported-mtype.json diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 00c77204a8d..f8aa310cfa9 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -112,13 +112,13 @@ func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpWaardex, error) { var bidderExt adapters.ExtImpBidder if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { return nil, &errortypes.BadInput{ - Message: err.Error(), + Message: fmt.Sprintf("imp.ext is invalid: %s", err.Error()), } } var waardexExt openrtb_ext.ExtImpWaardex if err := jsonutil.Unmarshal(bidderExt.Bidder, &waardexExt); err != nil { return nil, &errortypes.BadInput{ - Message: err.Error(), + Message: fmt.Sprintf("imp.ext.bidder is invalid: %s", err.Error()), } } return &waardexExt, nil diff --git a/adapters/waardex/waardex_test.go b/adapters/waardex/waardex_test.go index 572df253c05..2e66ce12e79 100644 --- a/adapters/waardex/waardex_test.go +++ b/adapters/waardex/waardex_test.go @@ -1,19 +1,12 @@ package waardex import ( - "encoding/json" - "errors" - "net/http" "testing" - "text/template" - "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v3/adapters" "github.com/prebid/prebid-server/v3/adapters/adapterstest" "github.com/prebid/prebid-server/v3/config" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestJsonSamples(t *testing.T) { @@ -33,363 +26,3 @@ func TestEndpointTemplateMalformed(t *testing.T) { assert.Error(t, buildErr) } - -// --- MakeRequests --- - -func TestMakeRequests_AllImpressionsInvalid(t *testing.T) { - adapter := &waardexAdapter{ - EndpointTemplate: template.Must(template.New("endpointTemplate").Parse("http://example.com?zone={{.ZoneID}}")), - } - request := &openrtb2.BidRequest{ - Imp: []openrtb2.Imp{ - {ID: "1", Ext: json.RawMessage("malformed")}, - }, - } - - requests, errs := adapter.MakeRequests(request, &adapters.ExtraRequestInfo{}) - - assert.Nil(t, requests) - require.Len(t, errs, 1) -} - -func TestMakeRequests_DispatchEmptyReturnsNil(t *testing.T) { - adapter := &waardexAdapter{ - EndpointTemplate: template.Must(template.New("endpointTemplate").Parse("http://example.com?zone={{.ZoneID}}")), - } - // audio+native is multi-format but splitMultiFormatImp returns no imps - request := &openrtb2.BidRequest{ - Imp: []openrtb2.Imp{makeImp(t, "1", false, false, true, true, 7)}, - } - - requests, errs := adapter.MakeRequests(request, &adapters.ExtraRequestInfo{}) - - assert.Nil(t, requests) - assert.Len(t, errs, 0) -} - -func TestMakeRequests_BuildAdapterRequestError(t *testing.T) { - failTemplate, err := template.New("endpointTemplate").Funcs(template.FuncMap{ - "fail": func() (string, error) { return "", errors.New("boom") }, - }).Parse("{{fail}}") - require.NoError(t, err) - - adapter := &waardexAdapter{EndpointTemplate: failTemplate} - request := &openrtb2.BidRequest{ - Imp: []openrtb2.Imp{makeImp(t, "1", true, false, false, false, 7)}, - } - - requests, errs := adapter.MakeRequests(request, &adapters.ExtraRequestInfo{}) - - assert.Len(t, requests, 0) - require.Len(t, errs, 1) - assert.Contains(t, errs[0].Error(), "boom") -} - -// --- Helpers --- - -func makeImp(t *testing.T, id string, withBanner, withVideo, withNative, withAudio bool, zoneID int) openrtb2.Imp { - t.Helper() - imp := openrtb2.Imp{ID: id} - if withBanner { - imp.Banner = &openrtb2.Banner{} - } - if withVideo { - imp.Video = &openrtb2.Video{} - } - if withNative { - imp.Native = &openrtb2.Native{Request: `{"ver":"1.2"}`} - } - if withAudio { - imp.Audio = &openrtb2.Audio{MinDuration: 1} - } - // ext: {"bidder":{"zoneId":}} - extObj := map[string]interface{}{"bidder": map[string]interface{}{"zoneId": zoneID}} - raw, err := json.Marshal(extObj) - require.NoError(t, err) - imp.Ext = raw - return imp -} - -// --- groupImpressionsByZone --- - -func TestGroupImpressionsByZone_FiltersInvalidAndKeepsValid(t *testing.T) { - validImp := makeImp(t, "1", true, false, false, false, 10) - invalidImp := openrtb2.Imp{ID: "2", Ext: json.RawMessage("malformed")} - - grouped, errs := groupImpressionsByZone([]openrtb2.Imp{validImp, invalidImp}) - - assert.Len(t, errs, 1, "expected one error for invalid imp ext") - require.Len(t, grouped, 1) - group := grouped[openrtb_ext.ExtImpWaardex{ZoneId: 10}] - require.Len(t, group, 1) - assert.Equal(t, "1", group[0].ID) - assert.Nil(t, group[0].Ext) -} - -func TestGetImpressionExt_BadImpExt(t *testing.T) { - imp := openrtb2.Imp{ID: "1", Ext: json.RawMessage("malformed")} - - ext, err := getImpressionExt(&imp) - - assert.Nil(t, ext) - require.Error(t, err) -} - -func TestGetImpressionExt_BadBidderExt(t *testing.T) { - imp := openrtb2.Imp{ID: "1"} - imp.Ext = json.RawMessage(`{"bidder": "not-json"}`) - - ext, err := getImpressionExt(&imp) - - assert.Nil(t, ext) - require.Error(t, err) -} - -func TestGroupImpressionsByZone_GroupsByZoneAndSplitsMultiFormat(t *testing.T) { - imp1 := makeImp(t, "1", true, false, false, false, 100) // banner only - imp2 := makeImp(t, "2", true, true, false, false, 100) // banner + video (multi) - imp3 := makeImp(t, "3", false, true, false, false, 200) // video only different zone - - grouped, errs := groupImpressionsByZone([]openrtb2.Imp{imp1, imp2, imp3}) - require.Len(t, errs, 0) - - // zone 100 should have imp1 and two split imps from imp2 - g100 := grouped[openrtb_ext.ExtImpWaardex{ZoneId: 100}] - require.Len(t, g100, 3) - // Expect exactly one banner-only and one video-only from the split, plus original banner-only - var banners, videos int - for _, imp := range g100 { - if imp.Banner != nil && imp.Video == nil { - banners++ - } - if imp.Video != nil && imp.Banner == nil { - videos++ - } - // ext is nil in dispatched imps - assert.Nil(t, imp.Ext) - } - assert.Equal(t, 2, banners) - assert.Equal(t, 1, videos) - - // zone 200 should have one video-only - g200 := grouped[openrtb_ext.ExtImpWaardex{ZoneId: 200}] - require.Len(t, g200, 1) - assert.NotNil(t, g200[0].Video) - assert.Nil(t, g200[0].Banner) -} - -// --- isMultiFormatImp --- - -func TestIsMultiFormatImp(t *testing.T) { - single := makeImp(t, "1", true, false, false, false, 1) - multi := makeImp(t, "2", true, true, false, false, 1) - none := openrtb2.Imp{ID: "3"} - - assert.False(t, isMultiFormatImp(&single)) - assert.True(t, isMultiFormatImp(&multi)) - assert.False(t, isMultiFormatImp(&none)) -} - -func TestIsMultiFormatImp_MultiImpressionCases(t *testing.T) { - tests := []struct { - name string - imp openrtb2.Imp - wantMulti bool - }{ - { - name: "banner+audio", - imp: makeImp(t, "ba", true, false, false, true, 1), - wantMulti: true, - }, - { - name: "video+native", - imp: makeImp(t, "vn", false, true, true, false, 1), - wantMulti: true, - }, - { - name: "banner+native+audio", - imp: makeImp(t, "bna", true, false, true, true, 1), - wantMulti: true, - }, - { - name: "audio-only", - imp: makeImp(t, "a", false, false, false, true, 1), - wantMulti: false, - }, - { - name: "native-only", - imp: makeImp(t, "n", false, false, true, false, 1), - wantMulti: false, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - assert.Equal(t, tt.wantMulti, isMultiFormatImp(&tt.imp)) - }) - } -} - -// --- splitMultiFormatImp --- - -func TestSplitMultiFormatImp_BannerVideoOnly(t *testing.T) { - imp := makeImp(t, "m", true, true, true, true, 5) - // ensure it is multi-format - require.True(t, isMultiFormatImp(&imp)) - - split := splitMultiFormatImp(&imp) - // Only banner and video are produced - require.Len(t, split, 2) - // first banner-only, second video-only (order not guaranteed; verify counts) - var banners, videos, natives, audios int - for _, s := range split { - if s.Banner != nil { - banners++ - } - if s.Video != nil { - videos++ - } - if s.Native != nil { - natives++ - } - if s.Audio != nil { - audios++ - } - } - assert.Equal(t, 1, banners) - assert.Equal(t, 1, videos) - assert.Equal(t, 0, natives) - assert.Equal(t, 0, audios) -} - -// --- createBidRequest --- - -func TestCreateBidRequest_ShallowCopyAndStripPublishers(t *testing.T) { - sitePublisher := &openrtb2.Publisher{ID: "pub-site"} - appPublisher := &openrtb2.Publisher{ID: "pub-app"} - req := &openrtb2.BidRequest{ - ID: "req-1", - Site: &openrtb2.Site{ID: "site-1", Publisher: sitePublisher}, - App: &openrtb2.App{ID: "app-1", Publisher: appPublisher}, - Imp: []openrtb2.Imp{makeImp(t, "i1", true, false, false, false, 9)}, - } - - newImps := []openrtb2.Imp{makeImp(t, "i2", false, true, false, false, 9)} - out := createBidRequest(req, newImps) - - // Ensure original not mutated - require.NotNil(t, req.Site.Publisher) - require.NotNil(t, req.App.Publisher) - assert.Equal(t, 1, len(req.Imp)) - - // Ensure new request contains provided imps and stripped publishers - require.Equal(t, newImps, out.Imp) - if out.Site != nil { - assert.Nil(t, out.Site.Publisher) - } - if out.App != nil { - assert.Nil(t, out.App.Publisher) - } -} - -// --- buildEndpointURL --- - -func TestBuildEndpointURL(t *testing.T) { - bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{ - Endpoint: "http://example.test/hb?zone={{.ZoneID}}"}, config.Server{}) - require.NoError(t, err) - - url, err := bidder.(*waardexAdapter).buildEndpointURL(&openrtb_ext.ExtImpWaardex{ZoneId: 321}) - require.NoError(t, err) - assert.Equal(t, "http://example.test/hb?zone=321", url) -} - -// --- MakeBids --- - -func TestMakeBids_NoContent(t *testing.T) { - bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) - require.NoError(t, err) - - br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusNoContent}) - assert.Nil(t, br) - assert.Nil(t, errs) -} - -func TestMakeBids_NonOKStatus(t *testing.T) { - bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) - require.NoError(t, err) - - br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusBadRequest}) - assert.Nil(t, br) - require.Len(t, errs, 1) - assert.Contains(t, errs[0].Error(), "Unexpected http status code") -} - -func TestMakeBids_BadJSON(t *testing.T) { - bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) - require.NoError(t, err) - - br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusOK, Body: []byte("not-json")}) - assert.Nil(t, br) - require.Len(t, errs, 1) - assert.Contains(t, errs[0].Error(), "Bad server response") -} - -func TestMakeBids_InvalidSeatBidsCount(t *testing.T) { - bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) - require.NoError(t, err) - - payload := openrtb2.BidResponse{SeatBid: []openrtb2.SeatBid{}} // zero seatbids - raw, _ := json.Marshal(payload) - br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusOK, Body: raw}) - assert.Nil(t, br) - require.Len(t, errs, 1) - assert.Contains(t, errs[0].Error(), "Invalid SeatBids count") -} - -func TestMakeBids_SuccessWithTypesAndCurrency(t *testing.T) { - bidder, err := Builder(openrtb_ext.BidderWaardex, config.Adapter{Endpoint: "http://e"}, config.Server{}) - require.NoError(t, err) - - bids := []openrtb2.Bid{ - {ID: "b1", ImpID: "1", Price: 1.1, MType: openrtb2.MarkupBanner}, - {ID: "b2", ImpID: "2", Price: 2.2, MType: openrtb2.MarkupVideo}, - } - payload := openrtb2.BidResponse{Cur: "EUR", SeatBid: []openrtb2.SeatBid{{Bid: bids}}} - raw, _ := json.Marshal(payload) - br, errs := bidder.MakeBids(&openrtb2.BidRequest{}, &adapters.RequestData{}, &adapters.ResponseData{StatusCode: http.StatusOK, Body: raw}) - - require.Nil(t, errs) - require.NotNil(t, br) - assert.Equal(t, "EUR", br.Currency) - require.Len(t, br.Bids, 2) - assert.Equal(t, openrtb_ext.BidTypeBanner, br.Bids[0].BidType) - assert.Equal(t, openrtb_ext.BidTypeVideo, br.Bids[1].BidType) -} - -// --- getMediaTypeForBid --- - -func TestGetMediaTypeForBid(t *testing.T) { - type tc struct { - mtype openrtb2.MarkupType - want openrtb_ext.BidType - ok bool - } - tests := []tc{ - {openrtb2.MarkupBanner, openrtb_ext.BidTypeBanner, true}, - {openrtb2.MarkupAudio, openrtb_ext.BidTypeAudio, true}, - {openrtb2.MarkupNative, openrtb_ext.BidTypeNative, true}, - {openrtb2.MarkupVideo, openrtb_ext.BidTypeVideo, true}, - {openrtb2.MarkupType(99), "", false}, - } - for _, tt := range tests { - bid := &openrtb2.Bid{MType: tt.mtype} - got, err := getMediaTypeForBid(bid) - if tt.ok { - require.NoError(t, err) - assert.Equal(t, tt.want, got) - } else { - require.Error(t, err) - } - } -} diff --git a/adapters/waardex/waardextest/supplemental/all-impressions-invalid.json b/adapters/waardex/waardextest/supplemental/all-impressions-invalid.json new file mode 100644 index 00000000000..8349d722185 --- /dev/null +++ b/adapters/waardex/waardextest/supplemental/all-impressions-invalid.json @@ -0,0 +1,26 @@ +{ + "mockBidRequest": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": "malformed" + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "imp.ext is invalid: expect { or n, but found \"", + "comparison": "literal" + } + ], + "httpCalls": [] +} diff --git a/adapters/waardex/waardextest/supplemental/bad-response.json b/adapters/waardex/waardextest/supplemental/bad-response.json new file mode 100644 index 00000000000..bdc48f793d5 --- /dev/null +++ b/adapters/waardex/waardextest/supplemental/bad-response.json @@ -0,0 +1,60 @@ +{ + "mockBidRequest": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 101, + "host": "tag.test.com" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=101", + "body": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + } + } + ] + }, + "impIDs": [ + "imp-1" + ] + }, + "mockResponse": { + "status": 200, + "body": "" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Bad server response: .*", + "comparison": "regex" + } + ] +} diff --git a/adapters/waardex/waardextest/supplemental/invalid-seatbid-count.json b/adapters/waardex/waardextest/supplemental/invalid-seatbid-count.json new file mode 100644 index 00000000000..35994a950ab --- /dev/null +++ b/adapters/waardex/waardextest/supplemental/invalid-seatbid-count.json @@ -0,0 +1,63 @@ +{ + "mockBidRequest": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 101, + "host": "tag.test.com" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=101", + "body": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + } + } + ] + }, + "impIDs": [ + "imp-1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-1", + "seatbid": [] + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Invalid SeatBids count: 0", + "comparison": "literal" + } + ] +} diff --git a/adapters/waardex/waardextest/supplemental/multiformat-audio-native.json b/adapters/waardex/waardextest/supplemental/multiformat-audio-native.json new file mode 100644 index 00000000000..c4771051ffe --- /dev/null +++ b/adapters/waardex/waardextest/supplemental/multiformat-audio-native.json @@ -0,0 +1,28 @@ +{ + "mockBidRequest": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "audio": { + "mimes": [ + "audio/mp4" + ], + "minduration": 1, + "maxduration": 30 + }, + "native": { + "request": "{\"ver\":\"1.2\"}" + }, + "ext": { + "bidder": { + "zoneId": 101, + "host": "tag.test.com" + } + } + } + ] + }, + "httpCalls": [], + "expectedBidResponses": [] +} diff --git a/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json b/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json index 5a8dee14c49..736742542d1 100644 --- a/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json +++ b/adapters/waardex/waardextest/supplemental/multiformat-impression-invalid-ext.json @@ -46,11 +46,11 @@ }, "expectedMakeRequestsErrors": [ { - "value": "expect { or n, but found \"", + "value": "imp.ext is invalid: expect { or n, but found \"", "comparison": "literal" }, { - "value": "expect { or n, but found \"", + "value": "imp.ext.bidder is invalid: expect { or n, but found \"", "comparison": "literal" } ], diff --git a/adapters/waardex/waardextest/supplemental/status-204.json b/adapters/waardex/waardextest/supplemental/status-204.json new file mode 100644 index 00000000000..73c66022bcd --- /dev/null +++ b/adapters/waardex/waardextest/supplemental/status-204.json @@ -0,0 +1,55 @@ +{ + "mockBidRequest": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 101, + "host": "tag.test.com" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=101", + "body": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + } + } + ] + }, + "impIDs": [ + "imp-1" + ] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/waardex/waardextest/supplemental/status-not-200.json b/adapters/waardex/waardextest/supplemental/status-not-200.json new file mode 100644 index 00000000000..b7a6d0ee491 --- /dev/null +++ b/adapters/waardex/waardextest/supplemental/status-not-200.json @@ -0,0 +1,60 @@ +{ + "mockBidRequest": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 101, + "host": "tag.test.com" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=101", + "body": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + } + } + ] + }, + "impIDs": [ + "imp-1" + ] + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected http status code: 400", + "comparison": "literal" + } + ] +} diff --git a/adapters/waardex/waardextest/supplemental/unsupported-mtype.json b/adapters/waardex/waardextest/supplemental/unsupported-mtype.json new file mode 100644 index 00000000000..40b0f546e3b --- /dev/null +++ b/adapters/waardex/waardextest/supplemental/unsupported-mtype.json @@ -0,0 +1,81 @@ +{ + "mockBidRequest": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 101, + "host": "tag.test.com" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=101", + "body": { + "id": "req-1", + "imp": [ + { + "id": "imp-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + } + } + ] + }, + "impIDs": [ + "imp-1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-1", + "seatbid": [ + { + "bid": [ + { + "id": "bid-1", + "impid": "imp-1", + "price": 1.25, + "mtype": 99, + "adm": "" + } + ] + } + ] + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unsupported MType 99", + "comparison": "literal" + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [] + } + ] +} From ab7c2e8d5453197d66a1e8d258f03407fa99ad31 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Wed, 21 Jan 2026 08:41:09 +0100 Subject: [PATCH 29/32] Add unit tests for Waardex to validate bidder parameter schema --- adapters/waardex/params_test.go | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 adapters/waardex/params_test.go diff --git a/adapters/waardex/params_test.go b/adapters/waardex/params_test.go new file mode 100644 index 00000000000..d97726ba884 --- /dev/null +++ b/adapters/waardex/params_test.go @@ -0,0 +1,62 @@ +package waardex + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderWaardex, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderWaardex, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{ + "zoneId": 1 + }`, + `{ + "zoneId": 12345 + }`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{ + "zoneId": 0 + }`, + `{ + "zoneId": -1 + }`, + `{ + "zoneId": "1" + }`, +} From ae54a8a16d2af3aa586d50589586b73ccba3f4e8 Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Fri, 23 Jan 2026 10:14:33 +0100 Subject: [PATCH 30/32] Rename waardex adapter struct --- adapters/waardex/waardex.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index f8aa310cfa9..7540a25bbd4 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -16,12 +16,12 @@ import ( "github.com/prebid/prebid-server/v3/util/jsonutil" ) -type waardexAdapter struct { +type adapter struct { EndpointTemplate *template.Template } // MakeRequests prepares request information for prebid-server core -func (adapter *waardexAdapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { +func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { var errs []error impressionsByZone, impErrs := groupImpressionsByZone(request.Imp) errs = append(errs, impErrs...) @@ -124,7 +124,7 @@ func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpWaardex, error) { return &waardexExt, nil } -func (adapter *waardexAdapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpWaardex, imps []openrtb2.Imp) (*adapters.RequestData, error) { +func (adapter *adapter) buildAdapterRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext.ExtImpWaardex, imps []openrtb2.Imp) (*adapters.RequestData, error) { newBidRequest := createBidRequest(prebidBidRequest, imps) reqJSON, err := json.Marshal(newBidRequest) if err != nil { @@ -168,13 +168,13 @@ func createBidRequest(prebidBidRequest *openrtb2.BidRequest, imps []openrtb2.Imp } // Builds endpoint url based on adapter-specific pub settings from imp.ext -func (adapter *waardexAdapter) buildEndpointURL(params *openrtb_ext.ExtImpWaardex) (string, error) { +func (adapter *adapter) buildEndpointURL(params *openrtb_ext.ExtImpWaardex) (string, error) { endpointParams := macros.EndpointTemplateParams{ZoneID: strconv.Itoa(params.ZoneId)} return macros.ResolveMacros(adapter.EndpointTemplate, endpointParams) } // MakeBids translates Waardex bid response to prebid-server specific format -func (adapter *waardexAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { +func (adapter *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { if response.StatusCode == http.StatusNoContent { return nil, nil } @@ -254,7 +254,7 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) } - bidder := &waardexAdapter{ + bidder := &adapter{ EndpointTemplate: urlTemplate, } return bidder, nil From 0bcfaf625b3d96e0903cf411f9a0ee63fdce560a Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Fri, 23 Jan 2026 10:21:11 +0100 Subject: [PATCH 31/32] Add exemplary test cases for Waardex adapter to validate multiple impressions for same and different zones --- .../multiple-impressions-different-zones.json | 227 ++++++++++++++++++ .../multiple-impressions-same-zone.json | 187 +++++++++++++++ 2 files changed, 414 insertions(+) create mode 100644 adapters/waardex/waardextest/exemplary/multiple-impressions-different-zones.json create mode 100644 adapters/waardex/waardextest/exemplary/multiple-impressions-same-zone.json diff --git a/adapters/waardex/waardextest/exemplary/multiple-impressions-different-zones.json b/adapters/waardex/waardextest/exemplary/multiple-impressions-different-zones.json new file mode 100644 index 00000000000..b29d75c587e --- /dev/null +++ b/adapters/waardex/waardextest/exemplary/multiple-impressions-different-zones.json @@ -0,0 +1,227 @@ +{ + "mockBidRequest": { + "id": "0000000000003", + "imp": [ + { + "id": "banner-3", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 301, + "host": "tag.test.com" + } + } + }, + { + "id": "banner-4", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 302, + "host": "tag.test.com" + } + } + } + ], + "site": { + "page": "http://example.com/multi-zone.html", + "publisher": { + "id": "3" + } + }, + "user": { + "buyeruid": "A-38327932832" + }, + "cur": [ + "USD" + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=301", + "body": { + "id": "0000000000003", + "imp": [ + { + "id": "banner-3", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + } + } + ], + "site": { + "page": "http://example.com/multi-zone.html" + }, + "user": { + "buyeruid": "A-38327932832" + }, + "cur": [ + "USD" + ] + }, + "impIDs": [ + "banner-3" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-0002", + "seatbid": [ + { + "bid": [ + { + "id": "bid-301-1", + "impid": "banner-3", + "price": 0.95, + "cid": "7001", + "crid": "8001", + "adid": "8001", + "adm": "", + "mtype": 1, + "adomain": [ + "example-3.com" + ], + "w": 300, + "h": 250 + } + ] + } + ], + "bidid": "resp-0002-bid", + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=302", + "body": { + "id": "0000000000003", + "imp": [ + { + "id": "banner-4", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + } + } + ], + "site": { + "page": "http://example.com/multi-zone.html" + }, + "user": { + "buyeruid": "A-38327932832" + }, + "cur": [ + "USD" + ] + }, + "impIDs": [ + "banner-4" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-0003", + "seatbid": [ + { + "bid": [ + { + "id": "bid-302-1", + "impid": "banner-4", + "price": 0.75, + "cid": "7002", + "crid": "8002", + "adid": "8002", + "adm": "", + "mtype": 1, + "adomain": [ + "example-4.com" + ], + "w": 728, + "h": 90 + } + ] + } + ], + "bidid": "resp-0003-bid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-301-1", + "impid": "banner-3", + "price": 0.95, + "adm": "", + "adomain": [ + "example-3.com" + ], + "cid": "7001", + "adid": "8001", + "crid": "8001", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-302-1", + "impid": "banner-4", + "price": 0.75, + "adm": "", + "adomain": [ + "example-4.com" + ], + "cid": "7002", + "adid": "8002", + "crid": "8002", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/waardex/waardextest/exemplary/multiple-impressions-same-zone.json b/adapters/waardex/waardextest/exemplary/multiple-impressions-same-zone.json new file mode 100644 index 00000000000..198f3a0652f --- /dev/null +++ b/adapters/waardex/waardextest/exemplary/multiple-impressions-same-zone.json @@ -0,0 +1,187 @@ +{ + "mockBidRequest": { + "id": "0000000000002", + "imp": [ + { + "id": "banner-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 201, + "host": "tag.test.com" + } + } + }, + { + "id": "banner-2", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "zoneId": 201, + "host": "tag.test.com" + } + } + } + ], + "site": { + "page": "http://example.com/multi-zone.html", + "publisher": { + "id": "3" + } + }, + "user": { + "buyeruid": "A-38327932832" + }, + "cur": [ + "USD" + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://justbidit2.xyz:8800/hb?zone=201", + "body": { + "id": "0000000000002", + "imp": [ + { + "id": "banner-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + } + }, + { + "id": "banner-2", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ] + } + } + ], + "site": { + "page": "http://example.com/multi-zone.html" + }, + "user": { + "buyeruid": "A-38327932832" + }, + "cur": [ + "USD" + ] + }, + "impIDs": [ + "banner-1", + "banner-2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "resp-0001", + "seatbid": [ + { + "bid": [ + { + "id": "bid-201-1", + "impid": "banner-1", + "price": 1.1, + "cid": "5001", + "crid": "6001", + "adid": "6001", + "adm": "", + "mtype": 1, + "adomain": [ + "example-1.com" + ], + "w": 300, + "h": 250 + }, + { + "id": "bid-201-2", + "impid": "banner-2", + "price": 1.4, + "cid": "5002", + "crid": "6002", + "adid": "6002", + "adm": "", + "mtype": 1, + "adomain": [ + "example-2.com" + ], + "w": 300, + "h": 600 + } + ] + } + ], + "bidid": "resp-0001-bid", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-201-1", + "impid": "banner-1", + "price": 1.1, + "adm": "", + "adomain": [ + "example-1.com" + ], + "cid": "5001", + "adid": "6001", + "crid": "6001", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }, + { + "bid": { + "id": "bid-201-2", + "impid": "banner-2", + "price": 1.4, + "adm": "", + "adomain": [ + "example-2.com" + ], + "cid": "5002", + "adid": "6002", + "crid": "6002", + "w": 300, + "h": 600, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} From a8436cc4be57f16d57d9ffa132caeec44aef23ab Mon Sep 17 00:00:00 2001 From: Yegor Serdiuk Date: Fri, 30 Jan 2026 11:13:11 +0100 Subject: [PATCH 32/32] Remove unused `newBadInputError` function from Waardex adapter --- adapters/waardex/waardex.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/adapters/waardex/waardex.go b/adapters/waardex/waardex.go index 7540a25bbd4..86f1fe8d91c 100644 --- a/adapters/waardex/waardex.go +++ b/adapters/waardex/waardex.go @@ -235,12 +235,6 @@ func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { } } -func newBadInputError(message string) error { - return &errortypes.BadInput{ - Message: message, - } -} - func newBadServerResponseError(message string) error { return &errortypes.BadServerResponse{ Message: message,