Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2d0320b
Add Waardex bidder integration and tests
yegorHeiz Oct 8, 2025
de150e5
Refactor Waardex MakeRequests to ignore unused reqInfo argument
yegorHeiz Nov 13, 2025
9579219
Simplify error handling in Waardex MakeRequests function
yegorHeiz Nov 13, 2025
cdce8ef
Refactor Waardex MakeRequests error handling to improve clarity
yegorHeiz Nov 13, 2025
13a2eec
Refactor Waardex dispatchImpressions to simplify return structure and…
yegorHeiz Nov 13, 2025
10f656f
Refactor Waardex isMultiFormatImp to improve variable naming clarity
yegorHeiz Nov 13, 2025
eea4da4
Refactor error formatting in Waardex Unmarshal to use %v for consistency
yegorHeiz Nov 13, 2025
c662bfa
Refactor Waardex MakeRequests to improve variable naming consistency
yegorHeiz Nov 13, 2025
3b9301d
Refactor Waardex createBidRequest to remove unused params argument an…
yegorHeiz Nov 13, 2025
531e3e5
Refactor Waardex createBidRequest to simplify site and app copy logic
yegorHeiz Nov 13, 2025
bdafa95
Refactor Waardex MakeBids to ensure Currency is set only when available
yegorHeiz Nov 13, 2025
9300235
Refactor Waardex validateImpression logic into core JSON schema and s…
yegorHeiz Nov 13, 2025
1796660
Refactor Waardex dispatchImpressions to initialize map with capacity …
yegorHeiz Nov 13, 2025
27de5b2
Add comprehensive unit tests for Waardex adapter functions and utilities
yegorHeiz Jan 12, 2026
f2f8c97
Refactor Waardex MakeBids to aggregate errors instead of returning early
yegorHeiz Jan 12, 2026
c932712
Refactor Waardex adapter to use consistent indentation and add new un…
yegorHeiz Jan 12, 2026
f207127
Add unit tests for isMultiFormatImp to cover diverse impression cases
yegorHeiz Jan 12, 2026
43c3d05
Add unit tests for getImpressionExt to handle malformed and invalid b…
yegorHeiz Jan 12, 2026
4a1646a
Add unit tests for MakeRequests to handle invalid and malformed impre…
yegorHeiz Jan 12, 2026
482bb52
Refactor Waardex MakeRequests to remove redundant no-impression check…
yegorHeiz Jan 12, 2026
1f2485b
Update unit test expected error messages for malformed impression ext…
yegorHeiz Jan 12, 2026
1a97dd6
Optimize memory allocation in Waardex splitMultiFormatImp by reducing…
yegorHeiz Jan 12, 2026
16eeb26
Refactor Waardex adapter by merging `getImpressionsInfo` and `dispatc…
yegorHeiz Jan 12, 2026
d024330
Reduce initial slice capacity in Waardex adapter to optimize memory a…
yegorHeiz Jan 12, 2026
c1fdb37
Append `sspID` to Waardex user-sync redirect URL for enhanced tracking
yegorHeiz Jan 12, 2026
63861c2
Update Waardex user-sync configuration to require host setup and add …
yegorHeiz Jan 16, 2026
f3f8181
Reorder Waardex entry in adapter builders for consistent alphabetical…
yegorHeiz Jan 19, 2026
d298129
Add supplemental test cases for Waardex to validate error handling of…
yegorHeiz Jan 21, 2026
ab7c2e8
Add unit tests for Waardex to validate bidder parameter schema
yegorHeiz Jan 21, 2026
ae54a8a
Rename waardex adapter struct
yegorHeiz Jan 23, 2026
0bcfaf6
Add exemplary test cases for Waardex adapter to validate multiple imp…
yegorHeiz Jan 23, 2026
a8436cc
Remove unused `newBadInputError` function from Waardex adapter
yegorHeiz Jan 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions adapters/waardex/params_test.go
Original file line number Diff line number Diff line change
@@ -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"
}`,
}
255 changes: 255 additions & 0 deletions adapters/waardex/waardex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
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 adapter struct {
EndpointTemplate *template.Template
}

// MakeRequests prepares request information for prebid-server core
func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
var errs []error
impressionsByZone, impErrs := groupImpressionsByZone(request.Imp)
errs = append(errs, impErrs...)
if len(impressionsByZone) == 0 {
return nil, errs
}
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)
} else {
result = append(result, bidRequest)
}
}
return result, errs
}

// 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)
Comment thread
yegorWaardex marked this conversation as resolved.
continue
}
imp.Ext = nil
// 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, 2)
}
res[*impExt] = append(res[*impExt], splImps...)
} else {
if _, exists := res[*impExt]; !exists {
res[*impExt] = make([]openrtb2.Imp, 0, 2)
}
res[*impExt] = append(res[*impExt], imp)
}
}
return res, errors
}

func isMultiFormatImp(imp *openrtb2.Imp) bool {
Comment thread
yegorWaardex marked this conversation as resolved.
formatCount := 0
if imp.Video != nil {
formatCount++
}
if imp.Audio != nil {
formatCount++
}
if imp.Banner != nil {
formatCount++
}
if imp.Native != nil {
formatCount++
}
return formatCount > 1
}

func splitMultiFormatImp(imp *openrtb2.Imp) []openrtb2.Imp {
splitImps := make([]openrtb2.Imp, 0, 2)
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{
Comment thread
yegorWaardex marked this conversation as resolved.
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: fmt.Sprintf("imp.ext.bidder is invalid: %s", err.Error()),
}
}
return &waardexExt, nil
}

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 {
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, 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
}

// Builds endpoint url based on adapter-specific pub settings from imp.ext
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 *adapter) 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: %v", 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))
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 {
errs = append(errs, err)
continue
}
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: &bid,
BidType: bidType,
})
}
return bidResponse, errs
}

// 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 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 := &adapter{
EndpointTemplate: urlTemplate,
}
return bidder, nil
}
28 changes: 28 additions & 0 deletions adapters/waardex/waardex_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package waardex

Comment thread
yegorWaardex marked this conversation as resolved.
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) {
Comment thread
yegorWaardex marked this conversation as resolved.
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)
}
Loading
Loading